<commit_before>/**
 * @file allkrann_search_test.cpp
 *
 * Unit tests for the 'RASearch' class and consequently the
 * 'RASearchRules' class
 */
#include <time.h>
#include <mlpack/core.hpp>
#include <mlpack/core/metrics/lmetric.hpp>

// So that we can test private members.  This is hackish (for now).
#define private public
#include <mlpack/methods/rann/ra_search.hpp>
#undef private

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace std;
using namespace mlpack;
using namespace mlpack::neighbor;

BOOST_AUTO_TEST_SUITE(AllkRANNTest);

BOOST_AUTO_TEST_CASE(AllkRANNNaiveSearch)
{
  // first testing on a small set.

  arma::mat rdata(2, 10);
  rdata << 3 << 2 << 4 << 3 << 5 << 6 << 0 << 8 << 3 << 1 << arma::endr <<
    0 << 3 << 4 << 7 << 8 << 4 << 1 << 0 << 4 << 3 << arma::endr;

  arma::mat qdata(2, 3);
  qdata << 3 << 2 << 0 << arma::endr << 5 << 3 << 4 << arma::endr;

  metric::SquaredEuclideanDistance dMetric;
  double rankApproximation = 30;
  double successProb = 0.95;

  // Search for 1 rank-approximate nearest-neighbors in the top 30%
  // of the point (rank error of 3)
  arma::Mat<size_t> neighbors;
  arma::mat distances;

  // Test naive rank-approximate search

  // Predict what the actual RANN-RS result would be
  math::RandomSeed(0);

  size_t numSamples = (size_t) ceil( log (1.0 / (1.0 - successProb))
   / log (1.0 / (1.0 - (rankApproximation / 100.0) ) ) );

  arma::Mat<size_t> samples(qdata.n_cols, numSamples);
  for (size_t j = 0; j < qdata.n_cols; j++)
    for (size_t i = 0; i < numSamples; i++)
      samples(j, i) = (size_t) math::RandInt(10);

  arma::Col<size_t> rann(qdata.n_cols);
  arma::vec rann_distance(qdata.n_cols);
  rann_distance.fill(DBL_MAX);

  for (size_t j = 0; j < qdata.n_cols; j++)
  {
    for (size_t i = 0; i < numSamples; i++)
    {
      double dist = dMetric.Evaluate(qdata.unsafe_col(j),
                                     rdata.unsafe_col(samples(j, i)));
      if (dist < rann_distance[j])
      {
        rann[j] = samples(j, i);
        rann_distance[j] = dist;
      }
    }
  }

  // use RANN-RS implementation
  math::RandomSeed(0);

  arma::mat naive_rdata = rdata;
  arma::mat naive_qdata = qdata;

  RASearch<> *naive = new RASearch<>(naive_rdata, naive_qdata, true);
  naive->Search(1, neighbors, distances, rankApproximation);

  delete naive;
  naive_rdata.reset();
  naive_qdata.reset();

  // Things to check:
  //
  // 1. (implicitly) The minimum number of required samples for
  //    guaranteed approximation
  // 2. (implicitly) Check the samples obtained.
  // 3. Check the neighbor returned.

  for (size_t i = 0; i < qdata.n_cols; i++)
  {
    BOOST_REQUIRE(neighbors(0, i) == rann[i]);
    BOOST_REQUIRE_CLOSE(distances(0, i), rann_distance[i], 1e-5);
  }

  Log::Warn << "RANN-RS (no tree) works as expected on small set." << endl;

  neighbors.reset();
  distances.reset();

  // now test the correctness & guarantees of this algorithm
  math::RandomSeed(time(NULL));

  arma::mat refData;
  arma::mat queryData;

  data::Load("rann_test_r_3_900.csv", refData, true);
  data::Load("rann_test_q_3_100.csv", queryData, true);

  RASearch<> *rann_rs = new RASearch<>(refData, queryData, true);

  arma::mat qrRanks;
  data::Load("rann_test_qr_ranks.csv", qrRanks, true);
  qrRanks = qrRanks.t();

  size_t numRounds = 1000;
  arma::Col<size_t> numSuccessRounds(queryData.n_cols);
  numSuccessRounds.fill(0);

  // 1% of 900 is 9, so the rank is expected to be less than 10
  size_t expectedRankErrorUB = 10;

  for (size_t rounds = 0; rounds < numRounds; rounds++)
  {
    rann_rs->Search(1, neighbors, distances, 1.0);

    for (size_t i = 0; i < queryData.n_cols; i++)
      if (qrRanks(i, neighbors(0, i)) < expectedRankErrorUB)
        numSuccessRounds[i]++;

    neighbors.reset();
    distances.reset();
  }

  delete rann_rs;

  // Finding the 95%-tile threshold so that 95% of the queries should
  // pass this threshold
  size_t threshold = floor(numRounds * (0.95 - (1.96 * sqrt(0.95 * 0.05
                                                            / numRounds))));
  size_t numQueriesFail = 0;
  for (size_t i = 0; i < queryData.n_cols; i++)
    if (numSuccessRounds[i] < threshold)
      numQueriesFail++;

  Log::Warn << "RANN-RS: RANN guarantee fails on " << numQueriesFail <<
    " queries." << endl;

  // assert that at most 5% of the queries fall out of this threshold
  // 5% of 100 queries is 5.
  size_t maxNumQueriesFail = 6;

  BOOST_REQUIRE(numQueriesFail < maxNumQueriesFail);
  Log::Warn << "RANN-RS (no tree) guarantees desired rank-approximation." <<
    endl;
}

BOOST_AUTO_TEST_CASE(AllkRANNSingleTreeSearch)
{
  // Test single-tree rank-approximate search (harder to test because of
  // the randomness involved)

  // Checking the correctness & guarantees of the algorithm
  math::RandomSeed(time(NULL));

  arma::mat refData;
  arma::mat queryData;

  data::Load("rann_test_r_3_900.csv", refData, true);
  data::Load("rann_test_q_3_100.csv", queryData, true);

  // Search for 1 rank-approximate nearest-neighbors in the top 30%
  // of the point (rank error of 3)
  arma::Mat<size_t> neighbors;
  arma::mat distances;

  RASearch<> *rann_tss = new RASearch<>(refData, queryData, false, true, 5);

  // The relative ranks for the given query reference pair
  arma::Mat<size_t> qrRanks;
  data::Load("rann_test_qr_ranks.csv", qrRanks, true);
  qrRanks = qrRanks.t();

  size_t numRounds = 1000;
  arma::Col<size_t> numSuccessRounds(queryData.n_cols);
  numSuccessRounds.fill(0);

  // 1% of 900 is 9, so the rank is expected to be less than 10
  size_t expectedRankErrorUB = 10;

  for (size_t rounds = 0; rounds < numRounds; rounds++)
  {
    rann_tss->Search(1, neighbors, distances, 1.0, 0.95, false, false, 5);

    for (size_t i = 0; i < queryData.n_cols; i++)
      if (qrRanks(i, neighbors(0, i)) < expectedRankErrorUB)
        numSuccessRounds[i]++;

    neighbors.reset();
    distances.reset();
  }

  delete rann_tss;

  // Finding the 95%-tile threshold so that 95% of the queries should
  // pass this threshold
  size_t threshold = floor(numRounds * (0.95 - (1.96 * sqrt(0.95 * 0.05
                                                            / numRounds))));
  size_t numQueriesFail = 0;
  for (size_t i = 0; i < queryData.n_cols; i++)
    if (numSuccessRounds[i] < threshold)
      numQueriesFail++;

  Log::Warn << "RANN-TSS: RANN guarantee fails on " << numQueriesFail <<
    " queries." << endl;

  // assert that at most 5% of the queries fall out of this threshold
  // 5% of 100 queries is 5.
  size_t maxNumQueriesFail = 6;

  BOOST_REQUIRE(numQueriesFail < maxNumQueriesFail);
  Log::Warn << "RANN-TSS (single tree) guarantees desired " <<
    "rank-approximation." << endl;
}

BOOST_AUTO_TEST_CASE(AllkRANNDualTreeSearch)
{
  // Test dual-tree rank-approximate search (harder to test because of
  // the randomness involved)
  // Test dual-tree rank-approximate search

  // Checking the correctness & guarantees of the algorithm
  math::RandomSeed(time(NULL));

  arma::mat refData;
  arma::mat queryData;

  data::Load("rann_test_r_3_900.csv", refData, true);
  data::Load("rann_test_q_3_100.csv", queryData, true);

  // Search for 1 rank-approximate nearest-neighbors in the top 30%
  // of the point (rank error of 3)
  arma::Mat<size_t> neighbors;
  arma::mat distances;

  RASearch<> *rann_tsd = new RASearch<>(refData, queryData, false, false, 5);

  arma::Mat<size_t> qrRanks;
  data::Load("rann_test_qr_ranks.csv", qrRanks, true);
  qrRanks = qrRanks.t();

  size_t numRounds = 1000;
  arma::Col<size_t> numSuccessRounds(queryData.n_cols);
  numSuccessRounds.fill(0);

  // 1% of 900 is 9, so the rank is expected to be less than 10
  size_t expectedRankErrorUB = 10;

  for (size_t rounds = 0; rounds < numRounds; rounds++)
  {
    rann_tsd->Search(1, neighbors, distances, 1.0, 0.95, false, false, 5);

    for (size_t i = 0; i < queryData.n_cols; i++)
      if (qrRanks(i, neighbors(0, i)) < expectedRankErrorUB)
        numSuccessRounds[i]++;

    neighbors.reset();
    distances.reset();

    rann_tsd->ResetQueryTree();
  }

  delete rann_tsd;

  // Finding the 95%-tile threshold so that 95% of the queries should
  // pass this threshold
  size_t threshold = floor(numRounds * (0.95 - (1.96 * sqrt(0.95 * 0.05
                                                              / numRounds))));
  size_t numQueriesFail = 0;
  for (size_t i = 0; i < queryData.n_cols; i++)
    if (numSuccessRounds[i] < threshold)
      numQueriesFail++;

  Log::Warn << "RANN-TSD: RANN guarantee fails on " << numQueriesFail <<
    " queries." << endl;

  // assert that at most 5% of the queries fall out of this threshold
  // 5% of 100 queries is 5.
  size_t maxNumQueriesFail = 6;

  BOOST_REQUIRE(numQueriesFail < maxNumQueriesFail);
  Log::Warn << "RANN-TSD (dual tree) guarantees desired " <<
    "rank-approximation." << endl;
}

BOOST_AUTO_TEST_SUITE_END();
<commit_msg>Clean up tests; split into four (not three) tests, remove random seed setting where appropriate.<commit_after>/**
 * @file allkrann_search_test.cpp
 *
 * Unit tests for the 'RASearch' class and consequently the
 * 'RASearchRules' class
 */
#include <time.h>
#include <mlpack/core.hpp>
#include <mlpack/core/metrics/lmetric.hpp>

// So that we can test private members.  This is hackish (for now).
#define private public
#include <mlpack/methods/rann/ra_search.hpp>
#undef private

#include <boost/test/unit_test.hpp>
#include "old_boost_test_definitions.hpp"

using namespace std;
using namespace mlpack;
using namespace mlpack::neighbor;

BOOST_AUTO_TEST_SUITE(AllkRANNTest);

// Test AllkRANN in naive mode for exact results when the random seeds are set
// the same.  This may not be the best test; if the implementation of RANN-RS
// gets random numbers in a different way, then this test might fail.
BOOST_AUTO_TEST_CASE(AllkRANNNaiveSearchExact)
{
  // First test on a small set.
  arma::mat rdata(2, 10);
  rdata << 3 << 2 << 4 << 3 << 5 << 6 << 0 << 8 << 3 << 1 << arma::endr <<
           0 << 3 << 4 << 7 << 8 << 4 << 1 << 0 << 4 << 3 << arma::endr;

  arma::mat qdata(2, 3);
  qdata << 3 << 2 << 0 << arma::endr
        << 5 << 3 << 4 << arma::endr;

  metric::SquaredEuclideanDistance dMetric;
  double rankApproximation = 30;
  double successProb = 0.95;

  // Search for 1 rank-approximate nearest-neighbors in the top 30% of the point
  // (rank error of 3).
  arma::Mat<size_t> neighbors;
  arma::mat distances;

  // Test naive rank-approximate search.
  // Predict what the actual RANN-RS result would be.
  math::RandomSeed(0);

  size_t numSamples = (size_t) ceil(log(1.0 / (1.0 - successProb)) /
      log(1.0 / (1.0 - (rankApproximation / 100.0))));

  arma::Mat<size_t> samples(qdata.n_cols, numSamples);
  for (size_t j = 0; j < qdata.n_cols; j++)
    for (size_t i = 0; i < numSamples; i++)
      samples(j, i) = (size_t) math::RandInt(10);

  arma::Col<size_t> rann(qdata.n_cols);
  arma::vec rannDistances(qdata.n_cols);
  rannDistances.fill(DBL_MAX);

  for (size_t j = 0; j < qdata.n_cols; j++)
  {
    for (size_t i = 0; i < numSamples; i++)
    {
      double dist = dMetric.Evaluate(qdata.unsafe_col(j),
                                     rdata.unsafe_col(samples(j, i)));
      if (dist < rannDistances[j])
      {
        rann[j] = samples(j, i);
        rannDistances[j] = dist;
      }
    }
  }

  // Use RANN-RS implementation.
  math::RandomSeed(0);

  RASearch<> naive(rdata, qdata, true);
  naive.Search(1, neighbors, distances, rankApproximation);

  // Things to check:
  //
  // 1. (implicitly) The minimum number of required samples for guaranteed
  //    approximation.
  // 2. (implicitly) Check the samples obtained.
  // 3. Check the neighbor returned.
  for (size_t i = 0; i < qdata.n_cols; i++)
  {
    BOOST_REQUIRE(neighbors(0, i) == rann[i]);
    BOOST_REQUIRE_CLOSE(distances(0, i), rannDistances[i], 1e-5);
  }
}

// Test the correctness and guarantees of AllkRANN when in naive mode.
BOOST_AUTO_TEST_CASE(AllkRANNNaiveGuaranteeTest)
{
  arma::Mat<size_t> neighbors;
  arma::mat distances;

  arma::mat refData;
  arma::mat queryData;

  data::Load("rann_test_r_3_900.csv", refData, true);
  data::Load("rann_test_q_3_100.csv", queryData, true);

  RASearch<> rsRann(refData, queryData, true);

  arma::mat qrRanks;
  data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose.

  size_t numRounds = 1000;
  arma::Col<size_t> numSuccessRounds(queryData.n_cols);
  numSuccessRounds.fill(0);

  // 1% of 900 is 9, so the rank is expected to be less than 10
  size_t expectedRankErrorUB = 10;

  for (size_t rounds = 0; rounds < numRounds; rounds++)
  {
    rsRann.Search(1, neighbors, distances, 1.0);

    for (size_t i = 0; i < queryData.n_cols; i++)
      if (qrRanks(i, neighbors(0, i)) < expectedRankErrorUB)
        numSuccessRounds[i]++;

    neighbors.reset();
    distances.reset();
  }

  // Find the 95%-tile threshold so that 95% of the queries should pass this
  // threshold.
  size_t threshold = floor(numRounds *
      (0.95 - (1.96 * sqrt(0.95 * 0.05 / numRounds))));
  size_t numQueriesFail = 0;
  for (size_t i = 0; i < queryData.n_cols; i++)
    if (numSuccessRounds[i] < threshold)
      numQueriesFail++;

  Log::Warn << "RANN-RS: RANN guarantee fails on " << numQueriesFail
      << " queries." << endl;

  // assert that at most 5% of the queries fall out of this threshold
  // 5% of 100 queries is 5.
  size_t maxNumQueriesFail = 6;

  BOOST_REQUIRE(numQueriesFail < maxNumQueriesFail);
}

// Test single-tree rank-approximate search (harder to test because of
// the randomness involved).
BOOST_AUTO_TEST_CASE(AllkRANNSingleTreeSearch)
{
  arma::mat refData;
  arma::mat queryData;

  data::Load("rann_test_r_3_900.csv", refData, true);
  data::Load("rann_test_q_3_100.csv", queryData, true);

  // Search for 1 rank-approximate nearest-neighbors in the top 30% of the point
  // (rank error of 3).
  arma::Mat<size_t> neighbors;
  arma::mat distances;

  RASearch<> tssRann(refData, queryData, false, true, 5);

  // The relative ranks for the given query reference pair
  arma::Mat<size_t> qrRanks;
  data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose.

  size_t numRounds = 1000;
  arma::Col<size_t> numSuccessRounds(queryData.n_cols);
  numSuccessRounds.fill(0);

  // 1% of 900 is 9, so the rank is expected to be less than 10.
  size_t expectedRankErrorUB = 10;

  for (size_t rounds = 0; rounds < numRounds; rounds++)
  {
    tssRann.Search(1, neighbors, distances, 1.0, 0.95, false, false, 5);

    for (size_t i = 0; i < queryData.n_cols; i++)
      if (qrRanks(i, neighbors(0, i)) < expectedRankErrorUB)
        numSuccessRounds[i]++;

    neighbors.reset();
    distances.reset();
  }

  // Find the 95%-tile threshold so that 95% of the queries should pass this
  // threshold.
  size_t threshold = floor(numRounds *
      (0.95 - (1.96 * sqrt(0.95 * 0.05 / numRounds))));
  size_t numQueriesFail = 0;
  for (size_t i = 0; i < queryData.n_cols; i++)
    if (numSuccessRounds[i] < threshold)
      numQueriesFail++;

  Log::Warn << "RANN-TSS: RANN guarantee fails on " << numQueriesFail
      << " queries." << endl;

  // Assert that at most 5% of the queries fall out of this threshold.
  // 5% of 100 queries is 5.
  size_t maxNumQueriesFail = 6;

  BOOST_REQUIRE(numQueriesFail < maxNumQueriesFail);
}

// Test dual-tree rank-approximate search (harder to test because of the
// randomness involved).
BOOST_AUTO_TEST_CASE(AllkRANNDualTreeSearch)
{
  arma::mat refData;
  arma::mat queryData;

  data::Load("rann_test_r_3_900.csv", refData, true);
  data::Load("rann_test_q_3_100.csv", queryData, true);

  // Search for 1 rank-approximate nearest-neighbors in the top 30% of the point
  // (rank error of 3).
  arma::Mat<size_t> neighbors;
  arma::mat distances;

  RASearch<> tsdRann(refData, queryData, false, false, 5);

  arma::Mat<size_t> qrRanks;
  data::Load("rann_test_qr_ranks.csv", qrRanks, true, false); // No transpose.

  size_t numRounds = 1000;
  arma::Col<size_t> numSuccessRounds(queryData.n_cols);
  numSuccessRounds.fill(0);

  // 1% of 900 is 9, so the rank is expected to be less than 10.
  size_t expectedRankErrorUB = 10;

  for (size_t rounds = 0; rounds < numRounds; rounds++)
  {
    tsdRann.Search(1, neighbors, distances, 1.0, 0.95, false, false, 5);

    for (size_t i = 0; i < queryData.n_cols; i++)
      if (qrRanks(i, neighbors(0, i)) < expectedRankErrorUB)
        numSuccessRounds[i]++;

    neighbors.reset();
    distances.reset();

    tsdRann.ResetQueryTree();
  }

  // Find the 95%-tile threshold so that 95% of the queries should pass this
  // threshold.
  size_t threshold = floor(numRounds *
      (0.95 - (1.96 * sqrt(0.95 * 0.05 / numRounds))));
  size_t numQueriesFail = 0;
  for (size_t i = 0; i < queryData.n_cols; i++)
    if (numSuccessRounds[i] < threshold)
      numQueriesFail++;

  Log::Warn << "RANN-TSD: RANN guarantee fails on " << numQueriesFail
      << " queries." << endl;

  // assert that at most 5% of the queries fall out of this threshold
  // 5% of 100 queries is 5.
  size_t maxNumQueriesFail = 6;

  BOOST_REQUIRE(numQueriesFail < maxNumQueriesFail);
}

BOOST_AUTO_TEST_SUITE_END();
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>
#include <no/nostring.h>
#include <no/noescape.h>

// GTest uses this function to output objects
static void PrintTo(const NoString& s, std::ostream* o)
{
    *o << '"' << No::Escape_n(s, No::AsciiFormat, No::DebugFormat) << '"';
}

class EscapeTest : public ::testing::Test
{
protected:
    void testEncode(const NoString& in, const NoString& expectedOut, No::EscapeFormat format)
    {
        // Encode, then decode again and check we still got the same string
        NoString out = No::Escape_n(in, No::AsciiFormat, format);
        EXPECT_EQ(expectedOut, out);
        out = No::Escape_n(out, format, No::AsciiFormat);
        EXPECT_EQ(in, out);
    }

    void testString(const NoString& in, const NoString& url, const NoString& html, const NoString& sql, const NoString& tag)
    {
        SCOPED_TRACE("String: " + in);

        testEncode(in, url, No::UrlFormat);
        testEncode(in, html, No::HtmlFormat);
        testEncode(in, sql, No::SqlFormat);
        testEncode(in, tag, No::MsgTagFormat);
    }
};

TEST_F(EscapeTest, Test)
{
    //          input     url          html             sql         msgtag
    testString("abcdefg", "abcdefg", "abcdefg", "abcdefg", "abcdefg");
    testString("\n\t\r", "%0A%09%0D", "\n\t\r", "\\n\\t\\r", "\\n\t\\r");
    testString("'\"", "%27%22", "'"", "\\'\\\"", "'\"");
    testString("&<>", "%26%3C%3E", "&<>", "&<>", "&<>");
    testString(" ;", "+%3B", " ;", " ;", "\\s\\:");
}

TEST(StringTest, Bool)
{
    EXPECT_EQ(true, NoString(true).ToBool());
    EXPECT_EQ(false, NoString(false).ToBool());
}

#define CS(s) (NoString((s), sizeof(s) - 1))

TEST(StringTest, Cmp)
{
    NoString s = "Bbb";

    EXPECT_EQ(NoString("Bbb"), s);
    EXPECT_LT(NoString("Aaa"), s);
    EXPECT_GT(NoString("Ccc"), s);
    EXPECT_EQ(0, s.Compare("Bbb", No::CaseSensitive));
    EXPECT_GT(0, s.Compare("bbb", No::CaseSensitive));
    EXPECT_LT(0, s.Compare("Aaa", No::CaseSensitive));
    EXPECT_GT(0, s.Compare("Ccc", No::CaseSensitive));
    EXPECT_EQ(0, s.Compare("Bbb", No::CaseInsensitive));
    EXPECT_EQ(0, s.Compare("bbb", No::CaseInsensitive));
    EXPECT_LT(0, s.Compare("Aaa", No::CaseInsensitive));
    EXPECT_GT(0, s.Compare("Ccc", No::CaseInsensitive));

    EXPECT_TRUE(s.Equals("bbb"));
    EXPECT_FALSE(s.Equals("bbb", No::CaseSensitive));
    EXPECT_FALSE(s.Equals("bb"));
}

TEST(StringTest, Wild)
{
    EXPECT_TRUE(NoString("").WildCmp("", No::CaseSensitive));
    EXPECT_TRUE(NoString("").WildCmp("", No::CaseInsensitive));

    EXPECT_FALSE(NoString("xy").WildCmp("*a*b*c*", No::CaseSensitive));
    EXPECT_FALSE(NoString("xy").WildCmp("*a*b*c*", No::CaseInsensitive));

    EXPECT_TRUE(NoString("I_am!~bar@foo").WildCmp("*!?bar@foo", No::CaseSensitive));
    EXPECT_TRUE(NoString("I_am!~bar@foo").WildCmp("*!?bar@foo", No::CaseInsensitive));

    EXPECT_FALSE(NoString("I_am!~bar@foo").WildCmp("*!?BAR@foo", No::CaseSensitive));
    EXPECT_TRUE(NoString("I_am!~bar@foo").WildCmp("*!?BAR@foo", No::CaseInsensitive));

    EXPECT_TRUE(NoString("abc").WildCmp("*a*b*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("abc").WildCmp("*a*b*c*", No::CaseInsensitive));

    EXPECT_FALSE(NoString("abc").WildCmp("*A*b*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("abc").WildCmp("*A*b*c*", No::CaseInsensitive));

    EXPECT_FALSE(NoString("Abc").WildCmp("*a*b*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("Abc").WildCmp("*a*b*c*", No::CaseInsensitive));

    EXPECT_TRUE(NoString("axbyc").WildCmp("*a*b*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("axbyc").WildCmp("*a*b*c*", No::CaseInsensitive));

    EXPECT_FALSE(NoString("AxByC").WildCmp("*a*B*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("AxByC").WildCmp("*a*B*c*", No::CaseInsensitive));
}

TEST(StringTest, Case)
{
    NoString x = CS("xx");
    NoString X = CS("XX");
    EXPECT_EQ(X, x.AsUpper());
    EXPECT_EQ(x, X.AsLower());
}

TEST(StringTest, Replace)
{
    EXPECT_EQ("(b()b)", NoString("(a()a)").Replace_n("a", "b"));
//    EXPECT_EQ("(a()b)", NoString("(a()a)").Replace_n("a", "b", "(", ")"));
//    EXPECT_EQ("a(b)", NoString("(a()a)").Replace_n("a", "b", "(", ")", true));
}

TEST(StringTest, LeftRight)
{
    EXPECT_EQ("Xy", CS("Xyz").Left(2));
    EXPECT_EQ("Xyz", CS("Xyz").Left(20));

    EXPECT_EQ("yz", CS("Xyz").Right(2));
    EXPECT_EQ("Xyz", CS("Xyz").Right(20));
}

TEST(StringTest, Split)
{
    EXPECT_EQ("a", CS("a b c").Token(0));
    EXPECT_EQ("b", CS("a b c").Token(1));
    EXPECT_EQ("", CS("a b c").Token(100));
    EXPECT_EQ("b c", CS("a b c").Tokens(1));
    EXPECT_EQ("c", CS("a  c").Token(1));
    EXPECT_EQ("c", CS("a  c").Token(1, " "));
    EXPECT_EQ("c", CS("a  c").Token(1, "  "));
    EXPECT_EQ(" c", CS("a   c").Token(1, "  "));
    EXPECT_EQ("c", CS("a    c").Token(1, "  "));
//    EXPECT_EQ("(b c)", CS("a (b c) d").Token(1, " ", "(", ")"));
//    EXPECT_EQ("d", CS("a (b c) d").Token(2, " ", "(", ")"));

    NoStringVector vexpected;
    vexpected.push_back("a");
    vexpected.push_back("b");
    vexpected.push_back("c");
    NoStringVector vresult = CS("a b c").Split(" ");
    EXPECT_EQ(vexpected, vresult);
}

TEST(StringTest, Equals)
{
    EXPECT_TRUE(CS("ABC").Equals("abc"));
    EXPECT_TRUE(CS("ABC").Equals("abc", No::CaseInsensitive));
    EXPECT_FALSE(CS("ABC").Equals("abc", No::CaseSensitive));
}

TEST(StringTest, Find)
{
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("Hello"), 0u);
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("Hello", No::CaseInsensitive), 0u);
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("Hello", No::CaseSensitive), 0u);

    EXPECT_EQ(NoString("Hello, I'm Bob").Find("i'm"), 7u);
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("i'm", No::CaseInsensitive), 7u);
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("i'm", No::CaseSensitive), NoString::npos);
}

TEST(StringTest, StartsWith)
{
    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("Hello"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("Hello", No::CaseInsensitive));
    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("Hello", No::CaseSensitive));

    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("hello"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("hello", No::CaseInsensitive));
    EXPECT_FALSE(NoString("Hello, I'm Bob").StartsWith("hello", No::CaseSensitive));
}

TEST(StringTest, EndsWith)
{
    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("Bob"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("Bob", No::CaseInsensitive));
    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("Bob", No::CaseSensitive));

    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("bob"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("bob", No::CaseInsensitive));
    EXPECT_FALSE(NoString("Hello, I'm Bob").EndsWith("bob", No::CaseSensitive));
}

TEST(StringTest, Contains)
{
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("Hello"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("Hello", No::CaseInsensitive));
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("Hello", No::CaseSensitive));

    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("i'm"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("i'm", No::CaseInsensitive));
    EXPECT_FALSE(NoString("Hello, I'm Bob").Contains("i'm", No::CaseSensitive));

    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("i'm bob"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("i'm bob", No::CaseInsensitive));
    EXPECT_FALSE(NoString("Hello, I'm Bob").Contains("i'm bob", No::CaseSensitive));
}
<commit_msg>Update StringTest<commit_after>/*
 * Copyright (C) 2004-2015 ZNC, see the NOTICE file for details.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>
#include <no/nostring.h>
#include <no/noescape.h>

// GTest uses this function to output objects
static void PrintTo(const NoString& s, std::ostream* o)
{
    *o << '"' << No::Escape_n(s, No::AsciiFormat, No::DebugFormat) << '"';
}

class EscapeTest : public ::testing::Test
{
protected:
    void testEncode(const NoString& in, const NoString& expectedOut, No::EscapeFormat format)
    {
        // Encode, then decode again and check we still got the same string
        NoString out = No::Escape_n(in, No::AsciiFormat, format);
        EXPECT_EQ(expectedOut, out);
        out = No::Escape_n(out, format, No::AsciiFormat);
        EXPECT_EQ(in, out);
    }

    void testString(const NoString& in, const NoString& url, const NoString& html, const NoString& sql, const NoString& tag)
    {
        SCOPED_TRACE("String: " + in);

        testEncode(in, url, No::UrlFormat);
        testEncode(in, html, No::HtmlFormat);
        testEncode(in, sql, No::SqlFormat);
        testEncode(in, tag, No::MsgTagFormat);
    }
};

TEST_F(EscapeTest, Test)
{
    //          input     url          html             sql         msgtag
    testString("abcdefg", "abcdefg", "abcdefg", "abcdefg", "abcdefg");
    testString("\n\t\r", "%0A%09%0D", "\n\t\r", "\\n\\t\\r", "\\n\t\\r");
    testString("'\"", "%27%22", "'"", "\\'\\\"", "'\"");
    testString("&<>", "%26%3C%3E", "&<>", "&<>", "&<>");
    testString(" ;", "+%3B", " ;", " ;", "\\s\\:");
}

TEST(StringTest, Bool)
{
    EXPECT_EQ(true, NoString(true).ToBool());
    EXPECT_EQ(false, NoString(false).ToBool());
}

#define NS(s) (NoString((s), sizeof(s) - 1))

TEST(StringTest, Cmp)
{
    NoString s = "Bbb";

    EXPECT_EQ(NoString("Bbb"), s);
    EXPECT_LT(NoString("Aaa"), s);
    EXPECT_GT(NoString("Ccc"), s);
    EXPECT_EQ(0, s.Compare("Bbb", No::CaseSensitive));
    EXPECT_GT(0, s.Compare("bbb", No::CaseSensitive));
    EXPECT_LT(0, s.Compare("Aaa", No::CaseSensitive));
    EXPECT_GT(0, s.Compare("Ccc", No::CaseSensitive));
    EXPECT_EQ(0, s.Compare("Bbb", No::CaseInsensitive));
    EXPECT_EQ(0, s.Compare("bbb", No::CaseInsensitive));
    EXPECT_LT(0, s.Compare("Aaa", No::CaseInsensitive));
    EXPECT_GT(0, s.Compare("Ccc", No::CaseInsensitive));

    EXPECT_TRUE(s.Equals("bbb"));
    EXPECT_FALSE(s.Equals("bbb", No::CaseSensitive));
    EXPECT_FALSE(s.Equals("bb"));
}

TEST(StringTest, Wild)
{
    EXPECT_TRUE(NoString("").WildCmp("", No::CaseSensitive));
    EXPECT_TRUE(NoString("").WildCmp("", No::CaseInsensitive));

    EXPECT_FALSE(NoString("xy").WildCmp("*a*b*c*", No::CaseSensitive));
    EXPECT_FALSE(NoString("xy").WildCmp("*a*b*c*", No::CaseInsensitive));

    EXPECT_TRUE(NoString("I_am!~bar@foo").WildCmp("*!?bar@foo", No::CaseSensitive));
    EXPECT_TRUE(NoString("I_am!~bar@foo").WildCmp("*!?bar@foo", No::CaseInsensitive));

    EXPECT_FALSE(NoString("I_am!~bar@foo").WildCmp("*!?BAR@foo", No::CaseSensitive));
    EXPECT_TRUE(NoString("I_am!~bar@foo").WildCmp("*!?BAR@foo", No::CaseInsensitive));

    EXPECT_TRUE(NoString("abc").WildCmp("*a*b*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("abc").WildCmp("*a*b*c*", No::CaseInsensitive));

    EXPECT_FALSE(NoString("abc").WildCmp("*A*b*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("abc").WildCmp("*A*b*c*", No::CaseInsensitive));

    EXPECT_FALSE(NoString("Abc").WildCmp("*a*b*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("Abc").WildCmp("*a*b*c*", No::CaseInsensitive));

    EXPECT_TRUE(NoString("axbyc").WildCmp("*a*b*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("axbyc").WildCmp("*a*b*c*", No::CaseInsensitive));

    EXPECT_FALSE(NoString("AxByC").WildCmp("*a*B*c*", No::CaseSensitive));
    EXPECT_TRUE(NoString("AxByC").WildCmp("*a*B*c*", No::CaseInsensitive));
}

TEST(StringTest, Case)
{
    NoString x = NS("xx");
    NoString X = NS("XX");
    EXPECT_EQ(X, x.AsUpper());
    EXPECT_EQ(x, X.AsLower());
}

TEST(StringTest, Replace)
{
    EXPECT_EQ("(b()b)", NoString("(a()a)").Replace_n("a", "b"));
//    EXPECT_EQ("(a()b)", NoString("(a()a)").Replace_n("a", "b", "(", ")"));
//    EXPECT_EQ("a(b)", NoString("(a()a)").Replace_n("a", "b", "(", ")", true));
}

TEST(StringTest, LeftRight)
{
    EXPECT_EQ("Xy", NS("Xyz").Left(2));
    EXPECT_EQ("Xyz", NS("Xyz").Left(20));

    EXPECT_EQ("yz", NS("Xyz").Right(2));
    EXPECT_EQ("Xyz", NS("Xyz").Right(20));
}

TEST(StringTest, Split)
{
    EXPECT_EQ("a", NS("a b c").Token(0));
    EXPECT_EQ("b", NS("a b c").Token(1));
    EXPECT_EQ("", NS("a b c").Token(100));
    EXPECT_EQ("b c", NS("a b c").Tokens(1));
    EXPECT_EQ("c", NS("a  c").Token(1));
    EXPECT_EQ("c", NS("a  c").Token(1, " "));
    EXPECT_EQ("c", NS("a  c").Token(1, "  "));
    EXPECT_EQ(" c", NS("a   c").Token(1, "  "));
    EXPECT_EQ("c", NS("a    c").Token(1, "  "));
//    EXPECT_EQ("(b c)", CS("a (b c) d").Token(1, " ", "(", ")"));
//    EXPECT_EQ("d", CS("a (b c) d").Token(2, " ", "(", ")"));

    NoStringVector vexpected;
    vexpected.push_back("a");
    vexpected.push_back("b");
    vexpected.push_back("c");
    NoStringVector vresult = NS("a b c").Split(" ");
    EXPECT_EQ(vexpected, vresult);
}

TEST(StringTest, Equals)
{
    EXPECT_TRUE(NS("ABC").Equals("abc"));
    EXPECT_TRUE(NS("ABC").Equals("abc", No::CaseInsensitive));
    EXPECT_FALSE(NS("ABC").Equals("abc", No::CaseSensitive));
}

TEST(StringTest, Find)
{
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("Hello"), 0u);
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("Hello", No::CaseInsensitive), 0u);
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("Hello", No::CaseSensitive), 0u);

    EXPECT_EQ(NoString("Hello, I'm Bob").Find("i'm"), 7u);
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("i'm", No::CaseInsensitive), 7u);
    EXPECT_EQ(NoString("Hello, I'm Bob").Find("i'm", No::CaseSensitive), NoString::npos);
}

TEST(StringTest, StartsWith)
{
    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("Hello"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("Hello", No::CaseInsensitive));
    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("Hello", No::CaseSensitive));

    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("hello"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").StartsWith("hello", No::CaseInsensitive));
    EXPECT_FALSE(NoString("Hello, I'm Bob").StartsWith("hello", No::CaseSensitive));
}

TEST(StringTest, EndsWith)
{
    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("Bob"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("Bob", No::CaseInsensitive));
    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("Bob", No::CaseSensitive));

    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("bob"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").EndsWith("bob", No::CaseInsensitive));
    EXPECT_FALSE(NoString("Hello, I'm Bob").EndsWith("bob", No::CaseSensitive));
}

TEST(StringTest, Contains)
{
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("Hello"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("Hello", No::CaseInsensitive));
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("Hello", No::CaseSensitive));

    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("i'm"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("i'm", No::CaseInsensitive));
    EXPECT_FALSE(NoString("Hello, I'm Bob").Contains("i'm", No::CaseSensitive));

    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("i'm bob"));
    EXPECT_TRUE(NoString("Hello, I'm Bob").Contains("i'm bob", No::CaseInsensitive));
    EXPECT_FALSE(NoString("Hello, I'm Bob").Contains("i'm bob", No::CaseSensitive));
}
<|endoftext|>


<commit_before>#ifndef PI
#define PI 3.14159265359f
#endif

#ifndef GLM_FORCE_RADIANS
#define GLM_FORCE_RADIANS
#define DEGREES_TO_RADIANS(x) (x * PI / 180.0f)
#endif

#include "ascii_grid_loader.hpp"
#include "code/ylikuutio/geometry/spherical_world_struct.hpp"
#include "code/ylikuutio/triangulation/triangulate_quads_struct.hpp"
#include "code/ylikuutio/triangulation/quad_triangulation.hpp"
#include "code/ylikuutio/string/ylikuutio_string.hpp"
#include "code/ylikuutio/common/pi.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <cmath>    // NAN, std::isnan, std::pow
#include <cstdio>   // std::FILE, std::fclose, std::fopen, std::fread, std::getchar, std::printf etc.
#include <iostream> // std::cout, std::cin, std::cerr
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string, std::stoi
#include <vector>   // std::vector

namespace loaders
{
    bool load_ASCII_grid(
            const std::string& ASCII_grid_file_name,
            std::vector<glm::vec3>& out_vertices,
            std::vector<glm::vec2>& out_UVs,
            std::vector<glm::vec3>& out_normals,
            const int32_t x_step,
            const int32_t z_step,
            const std::string& triangulation_type)
    {
        // Beginning of `L4133D.asc`.
        //
        // ncols        3000
        // nrows        3000
        // xllcorner    386000.000000000000
        // yllcorner    6672000.000000000000
        // cellsize     2.000000000000
        // NODATA_value  -9999.000
        // 34.315 34.467 34.441 34.260 33.972 33.564 33.229 33.130 33.102 33.024 32.902 32.669 32.305 32.013 31.937 31.893 31.831 31.832

        std::cout << "Loading ascii grid file " << ASCII_grid_file_name << " ...\n";

        // Open the file
        const char* char_ASCII_grid_file_name = ASCII_grid_file_name.c_str();
        std::FILE* file = std::fopen(char_ASCII_grid_file_name, "rb");
        if (!file)
        {
            std::cerr << ASCII_grid_file_name << " could not be opened.\n";
            return false;
        }

        // Find out file size.
        if (std::fseek(file, 0, SEEK_END) != 0)
        {
            std::cerr << "moving file pointer of file " << ASCII_grid_file_name << " failed!\n";
            std::fclose(file);
            return false;
        }

        int64_t file_size = std::ftell(file);

        if (file_size < 0)
        {
            std::cerr << "ftell failed for the file " << ASCII_grid_file_name << " !\n";
            std::fclose(file);
            return false;
        }

        // Move file pointer to the beginning of file.
        if (fseek(file, 0, SEEK_SET) != 0)
        {
            std::cerr << "moving file pointer of file " << ASCII_grid_file_name << " failed!\n";
            std::fclose(file);
            return false;
        }

        // Reserve enough memory.
        char* point_data = new char[file_size];

        if (point_data == nullptr)
        {
            std::cerr << "Reserving memory for point data failed.\n";
            std::fclose(file);
            return false;
        }

        char* point_data_pointer = point_data;

        // Read the point data from the file into the buffer.
        if (std::fread(point_data, 1, file_size, file) != file_size)
        {
            std::cerr << "Error while reading " << ASCII_grid_file_name << "\n";
            std::fclose(file);
            delete[] point_data;
            return false;
        }

        // Everything is in memory now, the file can be closed
        std::fclose(file);

        // All possible block identifier strings.
        std::vector<std::string> number_strings_vector = { "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        int32_t image_width = string::extract_int32_t_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "ncols");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        int32_t image_height = string::extract_int32_t_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "nrows");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        string::extract_float_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "xllcorner");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        string::extract_float_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "yllcorner");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        string::extract_float_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "cellsize");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        string::extract_float_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "nodata_value");

        // note: the value of `image_height_in_use` can be adjusted here (for testing purposes).
        int32_t image_height_in_use = image_height;

        float* vertex_data;
        vertex_data = new float[image_width * image_height_in_use];

        if (vertex_data == nullptr)
        {
            std::cerr << "Reserving memory for vertex data failed.\n";
            delete[] point_data;
            return false;
        }

        float* vertex_pointer;
        vertex_pointer = vertex_data;

        // start processing image_data.
        std::cout << "Processing image data.\n";

        int32_t last_percent = -1;
        int32_t current_percent = -1;

        for (int32_t z = 0; z < image_height_in_use; z++)
        {
            // show progress in percents.
            current_percent = static_cast<int32_t>(floor(100.0f * ((double) z / (double) (image_height_in_use - 1))));

            if (current_percent > last_percent)
            {
                std::cout << current_percent << "% ";
                last_percent = current_percent;
            }

            for (int32_t x = 0; x < image_width; x++)
            {
                while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, file_size, number_strings_vector))
                {
                    point_data_pointer++;
                }
                *vertex_pointer++ = string::extract_float_value_from_string(
                        point_data,
                        --point_data_pointer,
                        file_size,
                        (const char* const) " \n",
                        (const char* const) nullptr);
            }
        }

        delete[] point_data;

        std::cout << "Triangulating ascii grid data.\n";

        geometry::TriangulateQuadsStruct triangulate_quads_struct;
        triangulate_quads_struct.image_width = image_width;
        triangulate_quads_struct.image_height = image_height_in_use;
        triangulate_quads_struct.x_step = x_step;
        triangulate_quads_struct.z_step = z_step;
        triangulate_quads_struct.triangulation_type = triangulation_type;
        triangulate_quads_struct.sphere_radius = NAN;
        triangulate_quads_struct.spherical_world_struct = geometry::SphericalWorldStruct(); // not used, but is needed in the function call.

        bool result = geometry::triangulate_quads(vertex_data, triangulate_quads_struct, out_vertices, out_UVs, out_normals);
        delete vertex_data;
        return result;
    }
}
<commit_msg>Bugfix `loaders::load_ASCII_grid`: `delete` -> `delete[]`.<commit_after>#ifndef PI
#define PI 3.14159265359f
#endif

#ifndef GLM_FORCE_RADIANS
#define GLM_FORCE_RADIANS
#define DEGREES_TO_RADIANS(x) (x * PI / 180.0f)
#endif

#include "ascii_grid_loader.hpp"
#include "code/ylikuutio/geometry/spherical_world_struct.hpp"
#include "code/ylikuutio/triangulation/triangulate_quads_struct.hpp"
#include "code/ylikuutio/triangulation/quad_triangulation.hpp"
#include "code/ylikuutio/string/ylikuutio_string.hpp"
#include "code/ylikuutio/common/pi.hpp"

// Include GLM
#ifndef __GLM_GLM_HPP_INCLUDED
#define __GLM_GLM_HPP_INCLUDED
#include <glm/glm.hpp> // glm
#endif

// Include standard headers
#include <cmath>    // NAN, std::isnan, std::pow
#include <cstdio>   // std::FILE, std::fclose, std::fopen, std::fread, std::getchar, std::printf etc.
#include <iostream> // std::cout, std::cin, std::cerr
#include <stdint.h> // uint32_t etc.
#include <string>   // std::string, std::stoi
#include <vector>   // std::vector

namespace loaders
{
    bool load_ASCII_grid(
            const std::string& ASCII_grid_file_name,
            std::vector<glm::vec3>& out_vertices,
            std::vector<glm::vec2>& out_UVs,
            std::vector<glm::vec3>& out_normals,
            const int32_t x_step,
            const int32_t z_step,
            const std::string& triangulation_type)
    {
        // Beginning of `L4133D.asc`.
        //
        // ncols        3000
        // nrows        3000
        // xllcorner    386000.000000000000
        // yllcorner    6672000.000000000000
        // cellsize     2.000000000000
        // NODATA_value  -9999.000
        // 34.315 34.467 34.441 34.260 33.972 33.564 33.229 33.130 33.102 33.024 32.902 32.669 32.305 32.013 31.937 31.893 31.831 31.832

        std::cout << "Loading ascii grid file " << ASCII_grid_file_name << " ...\n";

        // Open the file
        const char* char_ASCII_grid_file_name = ASCII_grid_file_name.c_str();
        std::FILE* file = std::fopen(char_ASCII_grid_file_name, "rb");
        if (!file)
        {
            std::cerr << ASCII_grid_file_name << " could not be opened.\n";
            return false;
        }

        // Find out file size.
        if (std::fseek(file, 0, SEEK_END) != 0)
        {
            std::cerr << "moving file pointer of file " << ASCII_grid_file_name << " failed!\n";
            std::fclose(file);
            return false;
        }

        int64_t file_size = std::ftell(file);

        if (file_size < 0)
        {
            std::cerr << "ftell failed for the file " << ASCII_grid_file_name << " !\n";
            std::fclose(file);
            return false;
        }

        // Move file pointer to the beginning of file.
        if (fseek(file, 0, SEEK_SET) != 0)
        {
            std::cerr << "moving file pointer of file " << ASCII_grid_file_name << " failed!\n";
            std::fclose(file);
            return false;
        }

        // Reserve enough memory.
        char* point_data = new char[file_size];

        if (point_data == nullptr)
        {
            std::cerr << "Reserving memory for point data failed.\n";
            std::fclose(file);
            return false;
        }

        char* point_data_pointer = point_data;

        // Read the point data from the file into the buffer.
        if (std::fread(point_data, 1, file_size, file) != file_size)
        {
            std::cerr << "Error while reading " << ASCII_grid_file_name << "\n";
            std::fclose(file);
            delete[] point_data;
            return false;
        }

        // Everything is in memory now, the file can be closed
        std::fclose(file);

        // All possible block identifier strings.
        std::vector<std::string> number_strings_vector = { "-", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        int32_t image_width = string::extract_int32_t_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "ncols");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        int32_t image_height = string::extract_int32_t_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "nrows");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        string::extract_float_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "xllcorner");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        string::extract_float_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "yllcorner");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        string::extract_float_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "cellsize");

        while (!string::check_and_report_if_some_string_matches(point_data, ++point_data_pointer, file_size, number_strings_vector));
        string::extract_float_value_from_string(
                point_data,
                --point_data_pointer,
                file_size,
                (const char* const) " \n",
                (const char* const) "nodata_value");

        // note: the value of `image_height_in_use` can be adjusted here (for testing purposes).
        int32_t image_height_in_use = image_height;

        float* vertex_data;
        vertex_data = new float[image_width * image_height_in_use];

        if (vertex_data == nullptr)
        {
            std::cerr << "Reserving memory for vertex data failed.\n";
            delete[] point_data;
            return false;
        }

        float* vertex_pointer;
        vertex_pointer = vertex_data;

        // start processing image_data.
        std::cout << "Processing image data.\n";

        int32_t last_percent = -1;
        int32_t current_percent = -1;

        for (int32_t z = 0; z < image_height_in_use; z++)
        {
            // show progress in percents.
            current_percent = static_cast<int32_t>(floor(100.0f * ((double) z / (double) (image_height_in_use - 1))));

            if (current_percent > last_percent)
            {
                std::cout << current_percent << "% ";
                last_percent = current_percent;
            }

            for (int32_t x = 0; x < image_width; x++)
            {
                while (!string::check_and_report_if_some_string_matches(point_data, point_data_pointer, file_size, number_strings_vector))
                {
                    point_data_pointer++;
                }
                *vertex_pointer++ = string::extract_float_value_from_string(
                        point_data,
                        --point_data_pointer,
                        file_size,
                        (const char* const) " \n",
                        (const char* const) nullptr);
            }
        }

        delete[] point_data;

        std::cout << "Triangulating ascii grid data.\n";

        geometry::TriangulateQuadsStruct triangulate_quads_struct;
        triangulate_quads_struct.image_width = image_width;
        triangulate_quads_struct.image_height = image_height_in_use;
        triangulate_quads_struct.x_step = x_step;
        triangulate_quads_struct.z_step = z_step;
        triangulate_quads_struct.triangulation_type = triangulation_type;
        triangulate_quads_struct.sphere_radius = NAN;
        triangulate_quads_struct.spherical_world_struct = geometry::SphericalWorldStruct(); // not used, but is needed in the function call.

        bool result = geometry::triangulate_quads(vertex_data, triangulate_quads_struct, out_vertices, out_UVs, out_normals);
        delete[] vertex_data;
        return result;
    }
}
<|endoftext|>


<commit_before>
#include "CPipelineState.h"
#include <ionWindow.h>
#include <glad/glad.h>

namespace ion
{
	namespace Graphics
	{
		namespace GL
		{
			CPipelineState::CPipelineState(CWindow * Window)
			{
				this->Window = Window;
			}

			CPipelineState::~CPipelineState()
			{
			}

			void CPipelineState::SetProgram(SharedPointer<IShaderProgram> inShaderProgram)
			{
				if (inShaderProgram)
				{
					ShaderProgram = std::dynamic_pointer_cast<CShaderProgram>(inShaderProgram);
					if (! ShaderProgram->Linked)
					{
						ShaderProgram->Link();

						if (! ShaderProgram->Linked)
						{
							Log::Error("Failed to link shader prograg in PipelineState creation, unsetting shader.");
							ShaderProgram = nullptr;
							return;
						}
					}

					UnboundUniforms = KeySet(ShaderProgram->Uniforms);
					UnboundAttributes = KeySet(ShaderProgram->Attributes);

					Loaded = false;
				}
			}

			void CPipelineState::SetVertexBuffer(uint const Index, SharedPointer<IVertexBuffer> inVertexBuffer)
			{
				if (Index >= VertexBuffers.size())
				{
					VertexBuffers.resize(Index + 1);
				}

				VertexBuffers[Index] = std::dynamic_pointer_cast<CVertexBuffer>(inVertexBuffer);
				// Bound VBOs are not part of VAO state

				Loaded = false;
			}

			void CPipelineState::SetIndexBuffer(SharedPointer<IIndexBuffer> inIndexBuffer)
			{
				IndexBuffer = std::dynamic_pointer_cast<CIndexBuffer>(inIndexBuffer);
				Window->MakeContextCurrent();
				SafeGLCall(glBindVertexArray, (VertexArrayHandle));
				SafeGLCall(glBindBuffer, (GL_ELEMENT_ARRAY_BUFFER, IndexBuffer->Handle));
				SafeGLCall(glBindVertexArray, (0));

				Loaded = false;
			}

			void CPipelineState::SetUniform(string const & Name, SharedPointer<IUniform> Uniform)
			{
				if (! ShaderProgram)
				{
					Log::Error("Cannot set uniforms or textures on a PipelineState with no specified shader program.");
					return;
				}

				if (Uniform)
				{
					if (UnboundUniforms.count(Name) == 1)
					{
						Uniforms[Name] = Uniform;
						UnboundUniforms.erase(Name);
					}
					else
					{
						Log::Warn("Attempting to set uniform or texture '%s' that is not required by shader, ignoring.", Name);
					}
				}
				else
				{
					if (Uniforms.erase(Name) == 1)
					{
						UnboundUniforms.insert(Name);
					}
					else
					{
						Log::Error("Attempting to remove uniform or texture '%s' that was never specified, ignoring.", Name);
					}
				}
			}

			void CPipelineState::SetTexture(string const & Name, SharedPointer<ITexture> Texture)
			{
				if (! ShaderProgram)
				{
					Log::Error("Cannot set uniforms or textures on a PipelineState with no specified shader program.");
					return;
				}

				if (Texture)
				{
					if (UnboundUniforms.count(Name) == 1)
					{
						Textures[Name] = Texture;
						UnboundUniforms.erase(Name);
					}
					else
					{
						Log::Warn("Attempting to set uniform or texture '%s' that is not required by shader, ignoring.", Name);
					}
				}
				else
				{
					if (Textures.erase(Name) == 1)
					{
						UnboundUniforms.insert(Name);
					}
					else
					{
						Log::Error("Attempting to remove uniform or texture '%s' that was never specified, ignoring.", Name);
					}
				}
			}

			void CPipelineState::SetFeatureEnabled(EDrawFeature const Feature, bool const Enabled)
			{
				switch (Feature)
				{
				case EDrawFeature::Wireframe:
					DrawWireframe = Enabled;
					break;
				case EDrawFeature::CullFront:
					CullFront = Enabled;
					break;
				case EDrawFeature::CullBack:
					CullBack = Enabled;
					break;
				case EDrawFeature::DisableDepthTest:
					DisableDepthTest = Enabled;
					break;
				case EDrawFeature::DisableDepthWrite:
					DisableDepthWrite = Enabled;
					break;
				}
			}

			void CPipelineState::SetBlendMode(EBlendMode const BlendMode)
			{
				this->BlendMode = BlendMode;
			}

			void CPipelineState::OfferUniform(string const & Name, SharedPointer<IUniform> Uniform)
			{
				if (! ShaderProgram)
				{
					Log::Error("Cannot set uniforms or textures on a PipelineState with no specified shader program.");
					return;
				}

				if (! Uniform)
				{
					Log::Error("Invalid paramter to CPipelineState::OfferUniform: expected non-null Uniform");
					return;
				}

				if (UnboundUniforms.count(Name) == 1)
				{
					Uniforms[Name] = Uniform;
					UnboundUniforms.erase(Name);
				}
			}

			void CPipelineState::OfferTexture(string const & Name, SharedPointer<ITexture> Texture)
			{
				if (! ShaderProgram)
				{
					Log::Error("Cannot set uniforms or textures on a PipelineState with no specified shader program.");
					return;
				}

				if (! Texture)
				{
					Log::Error("Invalid paramter to CPipelineState::OfferTexture: expected non-null Texture");
					return;
				}

				if (UnboundUniforms.count(Name) == 1)
				{
					Textures[Name] = Texture;
					UnboundUniforms.erase(Name);
				}
			}

			void CPipelineState::IgnoreUniform(string const & Name)
			{
				UnboundUniforms.erase(Name);
			}

			set<string> CPipelineState::GetUnboundUniforms() const
			{
				return UnboundUniforms;
			}

			void CPipelineState::Load()
			{
				if (! ShaderProgram || VertexBuffers.empty() || ! IndexBuffer)
				{
					Log::Error("Attempting to load an invalid PipelineState");
					return;
				}

				Window->MakeContextCurrent();
				CheckedGLCall(glUseProgram(ShaderProgram->Handle));
				CheckedGLCall(glBindVertexArray(VertexArrayHandle));

				for (auto & VertexBuffer : VertexBuffers)
				{

					CheckedGLCall(glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer->Handle));

					//////////////////////////////
					// Set up VBOs (attributes) //
					//////////////////////////////

					// Calculate stride of VBO data
					size_t TotalStride = 0;
					for (auto & InputLayoutElement : VertexBuffer->InputLayout)
					{
						TotalStride += GetAttributeTypeSize(InputLayoutElement.Type) * InputLayoutElement.Components;
					}

					size_t CurrentOffset = 0;
					for (auto & InputLayoutElement : VertexBuffer->InputLayout)
					{
						pair<uint, uint> AttributeInfo;
						if (TryMapAccess(ShaderProgram->Attributes, InputLayoutElement.Name, AttributeInfo))
						{
							uint const AttributeLocation = AttributeInfo.first;
							uint const AttributeType = AttributeInfo.second;

							// Validate Attribute Type (does the VBO layout match what the shader wants?)
							{
								bool IsAttributeTypeCorrect = false;
								string ShaderAttributeTypeString = "Unknown";
								switch (AttributeType)
								{
								default:
									Log::Error("Unexpected type for attribute %s: %u", InputLayoutElement.Name, AttributeType);
									break;
								case GL_FLOAT:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Float && InputLayoutElement.Components == 1);
									ShaderAttributeTypeString = "GL_FLOAT";
									break;
								case GL_FLOAT_VEC2:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Float && InputLayoutElement.Components == 2);
									ShaderAttributeTypeString = "GL_FLOAT_VEC2";
									break;
								case GL_FLOAT_VEC3:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Float && InputLayoutElement.Components == 3);
									ShaderAttributeTypeString = "GL_FLOAT_VEC3";
									break;
								case GL_FLOAT_VEC4:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Float && InputLayoutElement.Components == 4);
									ShaderAttributeTypeString = "GL_FLOAT_VEC4";
									break;
								case GL_INT:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Int && InputLayoutElement.Components == 1);
									ShaderAttributeTypeString = "GL_INT";
									break;
								case GL_INT_VEC2:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Int && InputLayoutElement.Components == 2);
									ShaderAttributeTypeString = "GL_INT_VEC2";
									break;
								case GL_INT_VEC3:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Int && InputLayoutElement.Components == 3);
									ShaderAttributeTypeString = "GL_INT_VEC3";
									break;
								case GL_INT_VEC4:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Int && InputLayoutElement.Components == 4);
									ShaderAttributeTypeString = "GL_INT_VEC4";
									break;
								}

								if (! IsAttributeTypeCorrect)
								{
									Log::Error("Mistmatch for attribute type '%s': VBO supplied %d components of type %s but shader expected '%s'",
										InputLayoutElement.Name,
										InputLayoutElement.Components,
										GetAttributeTypeString(InputLayoutElement.Type),
										ShaderAttributeTypeString);
								}
							}

							CheckedGLCall(glEnableVertexAttribArray(AttributeLocation));

							switch (AttributeType)
							{
							case GL_FLOAT:
							case GL_FLOAT_VEC2:
							case GL_FLOAT_VEC3:
							case GL_FLOAT_VEC4:
								CheckedGLCall(glVertexAttribPointer(
									AttributeLocation,
									InputLayoutElement.Components,
									GetAttributeTypeOpenGLEnum(InputLayoutElement.Type),
									GL_FALSE,
									(int) TotalStride,
									(void *) CurrentOffset));
								break;
							case GL_INT:
							case GL_INT_VEC2:
							case GL_INT_VEC3:
							case GL_INT_VEC4:
								CheckedGLCall(glVertexAttribIPointer(
									AttributeLocation,
									InputLayoutElement.Components,
									GetAttributeTypeOpenGLEnum(InputLayoutElement.Type),
									(int) TotalStride,
									(void *) CurrentOffset));
								break;
							}

							if (VertexBuffer->Instancing)
							{
								CheckedGLCall(glVertexAttribDivisor(AttributeLocation, 1));
							}

							UnboundAttributes.erase(InputLayoutElement.Name);
						}

						CurrentOffset += GetAttributeTypeSize(InputLayoutElement.Type) * InputLayoutElement.Components;
					}

					CheckedGLCall(glBindBuffer(GL_ARRAY_BUFFER, 0)); // Remember, VBOs are not part of VAO state (that's why we never leave them set in the VAO)
				}

				std::for_each(UnboundAttributes.begin(), UnboundAttributes.end(), [](string const & Attribuite)
				{
					Log::Error("Attribute expected by shader but not provided by VBO: %s", Attribuite);
				});

				CheckedGLCall(glBindVertexArray(0));
				CheckedGLCall(glUseProgram(0));

				/////////////////////
				// Set up Uniforms //
				/////////////////////

				BoundUniforms.clear();
				for (auto const & it : Uniforms)
				{
					uint Handle = 0;
					if (TryMapAccess(ShaderProgram->Uniforms, it.first, Handle))
					{
						BoundUniforms[Handle] = it.second;
					}
				}
				for (auto const & it : Textures)
				{
					uint Handle = 0;
					if (TryMapAccess(ShaderProgram->Uniforms, it.first, Handle))
					{
						BoundTextures[Handle] = it.second;
					}
				}

				std::for_each(UnboundUniforms.begin(), UnboundUniforms.end(), [](string const & Uniform)
				{
					Log::Error("Uniform expected by shader but not provided by PSO: %s", Uniform);
				});

				Loaded = true;
			}

		}
	}
}
<commit_msg>[ionGraphicsGL] Fix warnings when 'gl_VertexID' is used in a shader<commit_after>
#include "CPipelineState.h"
#include <ionWindow.h>
#include <glad/glad.h>

namespace ion
{
	namespace Graphics
	{
		namespace GL
		{
			CPipelineState::CPipelineState(CWindow * Window)
			{
				this->Window = Window;
			}

			CPipelineState::~CPipelineState()
			{
			}

			void CPipelineState::SetProgram(SharedPointer<IShaderProgram> inShaderProgram)
			{
				if (inShaderProgram)
				{
					ShaderProgram = std::dynamic_pointer_cast<CShaderProgram>(inShaderProgram);
					if (! ShaderProgram->Linked)
					{
						ShaderProgram->Link();

						if (! ShaderProgram->Linked)
						{
							Log::Error("Failed to link shader prograg in PipelineState creation, unsetting shader.");
							ShaderProgram = nullptr;
							return;
						}
					}

					UnboundUniforms = KeySet(ShaderProgram->Uniforms);
					UnboundAttributes = KeySet(ShaderProgram->Attributes);
					UnboundAttributes.erase("gl_VertexID");

					Loaded = false;
				}
			}

			void CPipelineState::SetVertexBuffer(uint const Index, SharedPointer<IVertexBuffer> inVertexBuffer)
			{
				if (Index >= VertexBuffers.size())
				{
					VertexBuffers.resize(Index + 1);
				}

				VertexBuffers[Index] = std::dynamic_pointer_cast<CVertexBuffer>(inVertexBuffer);
				// Bound VBOs are not part of VAO state

				Loaded = false;
			}

			void CPipelineState::SetIndexBuffer(SharedPointer<IIndexBuffer> inIndexBuffer)
			{
				IndexBuffer = std::dynamic_pointer_cast<CIndexBuffer>(inIndexBuffer);
				Window->MakeContextCurrent();
				SafeGLCall(glBindVertexArray, (VertexArrayHandle));
				SafeGLCall(glBindBuffer, (GL_ELEMENT_ARRAY_BUFFER, IndexBuffer->Handle));
				SafeGLCall(glBindVertexArray, (0));

				Loaded = false;
			}

			void CPipelineState::SetUniform(string const & Name, SharedPointer<IUniform> Uniform)
			{
				if (! ShaderProgram)
				{
					Log::Error("Cannot set uniforms or textures on a PipelineState with no specified shader program.");
					return;
				}

				if (Uniform)
				{
					if (UnboundUniforms.count(Name) == 1)
					{
						Uniforms[Name] = Uniform;
						UnboundUniforms.erase(Name);
					}
					else
					{
						Log::Warn("Attempting to set uniform or texture '%s' that is not required by shader, ignoring.", Name);
					}
				}
				else
				{
					if (Uniforms.erase(Name) == 1)
					{
						UnboundUniforms.insert(Name);
					}
					else
					{
						Log::Error("Attempting to remove uniform or texture '%s' that was never specified, ignoring.", Name);
					}
				}
			}

			void CPipelineState::SetTexture(string const & Name, SharedPointer<ITexture> Texture)
			{
				if (! ShaderProgram)
				{
					Log::Error("Cannot set uniforms or textures on a PipelineState with no specified shader program.");
					return;
				}

				if (Texture)
				{
					if (UnboundUniforms.count(Name) == 1)
					{
						Textures[Name] = Texture;
						UnboundUniforms.erase(Name);
					}
					else
					{
						Log::Warn("Attempting to set uniform or texture '%s' that is not required by shader, ignoring.", Name);
					}
				}
				else
				{
					if (Textures.erase(Name) == 1)
					{
						UnboundUniforms.insert(Name);
					}
					else
					{
						Log::Error("Attempting to remove uniform or texture '%s' that was never specified, ignoring.", Name);
					}
				}
			}

			void CPipelineState::SetFeatureEnabled(EDrawFeature const Feature, bool const Enabled)
			{
				switch (Feature)
				{
				case EDrawFeature::Wireframe:
					DrawWireframe = Enabled;
					break;
				case EDrawFeature::CullFront:
					CullFront = Enabled;
					break;
				case EDrawFeature::CullBack:
					CullBack = Enabled;
					break;
				case EDrawFeature::DisableDepthTest:
					DisableDepthTest = Enabled;
					break;
				case EDrawFeature::DisableDepthWrite:
					DisableDepthWrite = Enabled;
					break;
				}
			}

			void CPipelineState::SetBlendMode(EBlendMode const BlendMode)
			{
				this->BlendMode = BlendMode;
			}

			void CPipelineState::OfferUniform(string const & Name, SharedPointer<IUniform> Uniform)
			{
				if (! ShaderProgram)
				{
					Log::Error("Cannot set uniforms or textures on a PipelineState with no specified shader program.");
					return;
				}

				if (! Uniform)
				{
					Log::Error("Invalid paramter to CPipelineState::OfferUniform: expected non-null Uniform");
					return;
				}

				if (UnboundUniforms.count(Name) == 1)
				{
					Uniforms[Name] = Uniform;
					UnboundUniforms.erase(Name);
				}
			}

			void CPipelineState::OfferTexture(string const & Name, SharedPointer<ITexture> Texture)
			{
				if (! ShaderProgram)
				{
					Log::Error("Cannot set uniforms or textures on a PipelineState with no specified shader program.");
					return;
				}

				if (! Texture)
				{
					Log::Error("Invalid paramter to CPipelineState::OfferTexture: expected non-null Texture");
					return;
				}

				if (UnboundUniforms.count(Name) == 1)
				{
					Textures[Name] = Texture;
					UnboundUniforms.erase(Name);
				}
			}

			void CPipelineState::IgnoreUniform(string const & Name)
			{
				UnboundUniforms.erase(Name);
			}

			set<string> CPipelineState::GetUnboundUniforms() const
			{
				return UnboundUniforms;
			}

			void CPipelineState::Load()
			{
				if (! ShaderProgram || VertexBuffers.empty() || ! IndexBuffer)
				{
					Log::Error("Attempting to load an invalid PipelineState");
					return;
				}

				Window->MakeContextCurrent();
				CheckedGLCall(glUseProgram(ShaderProgram->Handle));
				CheckedGLCall(glBindVertexArray(VertexArrayHandle));

				for (auto & VertexBuffer : VertexBuffers)
				{

					CheckedGLCall(glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer->Handle));

					//////////////////////////////
					// Set up VBOs (attributes) //
					//////////////////////////////

					// Calculate stride of VBO data
					size_t TotalStride = 0;
					for (auto & InputLayoutElement : VertexBuffer->InputLayout)
					{
						TotalStride += GetAttributeTypeSize(InputLayoutElement.Type) * InputLayoutElement.Components;
					}

					size_t CurrentOffset = 0;
					for (auto & InputLayoutElement : VertexBuffer->InputLayout)
					{
						pair<uint, uint> AttributeInfo;
						if (TryMapAccess(ShaderProgram->Attributes, InputLayoutElement.Name, AttributeInfo))
						{
							uint const AttributeLocation = AttributeInfo.first;
							uint const AttributeType = AttributeInfo.second;

							// Validate Attribute Type (does the VBO layout match what the shader wants?)
							{
								bool IsAttributeTypeCorrect = false;
								string ShaderAttributeTypeString = "Unknown";
								switch (AttributeType)
								{
								default:
									Log::Error("Unexpected type for attribute %s: %u", InputLayoutElement.Name, AttributeType);
									break;
								case GL_FLOAT:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Float && InputLayoutElement.Components == 1);
									ShaderAttributeTypeString = "GL_FLOAT";
									break;
								case GL_FLOAT_VEC2:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Float && InputLayoutElement.Components == 2);
									ShaderAttributeTypeString = "GL_FLOAT_VEC2";
									break;
								case GL_FLOAT_VEC3:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Float && InputLayoutElement.Components == 3);
									ShaderAttributeTypeString = "GL_FLOAT_VEC3";
									break;
								case GL_FLOAT_VEC4:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Float && InputLayoutElement.Components == 4);
									ShaderAttributeTypeString = "GL_FLOAT_VEC4";
									break;
								case GL_INT:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Int && InputLayoutElement.Components == 1);
									ShaderAttributeTypeString = "GL_INT";
									break;
								case GL_INT_VEC2:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Int && InputLayoutElement.Components == 2);
									ShaderAttributeTypeString = "GL_INT_VEC2";
									break;
								case GL_INT_VEC3:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Int && InputLayoutElement.Components == 3);
									ShaderAttributeTypeString = "GL_INT_VEC3";
									break;
								case GL_INT_VEC4:
									IsAttributeTypeCorrect = (InputLayoutElement.Type == EAttributeType::Int && InputLayoutElement.Components == 4);
									ShaderAttributeTypeString = "GL_INT_VEC4";
									break;
								}

								if (! IsAttributeTypeCorrect)
								{
									Log::Error("Mistmatch for attribute type '%s': VBO supplied %d components of type %s but shader expected '%s'",
										InputLayoutElement.Name,
										InputLayoutElement.Components,
										GetAttributeTypeString(InputLayoutElement.Type),
										ShaderAttributeTypeString);
								}
							}

							CheckedGLCall(glEnableVertexAttribArray(AttributeLocation));

							switch (AttributeType)
							{
							case GL_FLOAT:
							case GL_FLOAT_VEC2:
							case GL_FLOAT_VEC3:
							case GL_FLOAT_VEC4:
								CheckedGLCall(glVertexAttribPointer(
									AttributeLocation,
									InputLayoutElement.Components,
									GetAttributeTypeOpenGLEnum(InputLayoutElement.Type),
									GL_FALSE,
									(int) TotalStride,
									(void *) CurrentOffset));
								break;
							case GL_INT:
							case GL_INT_VEC2:
							case GL_INT_VEC3:
							case GL_INT_VEC4:
								CheckedGLCall(glVertexAttribIPointer(
									AttributeLocation,
									InputLayoutElement.Components,
									GetAttributeTypeOpenGLEnum(InputLayoutElement.Type),
									(int) TotalStride,
									(void *) CurrentOffset));
								break;
							}

							if (VertexBuffer->Instancing)
							{
								CheckedGLCall(glVertexAttribDivisor(AttributeLocation, 1));
							}

							UnboundAttributes.erase(InputLayoutElement.Name);
						}

						CurrentOffset += GetAttributeTypeSize(InputLayoutElement.Type) * InputLayoutElement.Components;
					}

					CheckedGLCall(glBindBuffer(GL_ARRAY_BUFFER, 0)); // Remember, VBOs are not part of VAO state (that's why we never leave them set in the VAO)
				}

				std::for_each(UnboundAttributes.begin(), UnboundAttributes.end(), [](string const & Attribuite)
				{
					Log::Error("Attribute expected by shader but not provided by VBO: %s", Attribuite);
				});

				CheckedGLCall(glBindVertexArray(0));
				CheckedGLCall(glUseProgram(0));

				/////////////////////
				// Set up Uniforms //
				/////////////////////

				BoundUniforms.clear();
				for (auto const & it : Uniforms)
				{
					uint Handle = 0;
					if (TryMapAccess(ShaderProgram->Uniforms, it.first, Handle))
					{
						BoundUniforms[Handle] = it.second;
					}
				}
				for (auto const & it : Textures)
				{
					uint Handle = 0;
					if (TryMapAccess(ShaderProgram->Uniforms, it.first, Handle))
					{
						BoundTextures[Handle] = it.second;
					}
				}

				std::for_each(UnboundUniforms.begin(), UnboundUniforms.end(), [](string const & Uniform)
				{
					Log::Error("Uniform expected by shader but not provided by PSO: %s", Uniform);
				});

				Loaded = true;
			}

		}
	}
}
<|endoftext|>


<commit_before>/*
* Cryptobox Message Routines
* (C) 2009 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/cryptobox.h>
#include <botan/cipher_mode.h>
#include <botan/mac.h>
#include <botan/rng.h>
#include <botan/pwdhash.h>
#include <botan/data_src.h>
#include <botan/pem.h>
#include <botan/internal/loadstor.h>
#include <botan/mem_ops.h>

namespace Botan {

namespace CryptoBox {

namespace {

/*
First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits
for later use as flags, etc if needed
*/
const uint32_t CRYPTOBOX_VERSION_CODE = 0xEFC22400;

const size_t VERSION_CODE_LEN = 4;
const size_t CIPHER_KEY_LEN = 32;
const size_t CIPHER_IV_LEN = 16;
const size_t MAC_KEY_LEN = 32;
const size_t MAC_OUTPUT_LEN = 20;
const size_t PBKDF_SALT_LEN = 10;
const size_t PBKDF_ITERATIONS = 8 * 1024;

const size_t PBKDF_OUTPUT_LEN = CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN;
const size_t CRYPTOBOX_HEADER_LEN = VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN;

}

std::string encrypt(const uint8_t input[], size_t input_len,
                    const std::string& passphrase,
                    RandomNumberGenerator& rng)
   {
   /*
   Output format is:
      version # (4 bytes)
      salt (10 bytes)
      mac (20 bytes)
      ciphertext
   */
   secure_vector<uint8_t> out_buf(CRYPTOBOX_HEADER_LEN + input_len);
   for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
     out_buf[i] = get_byte(i, CRYPTOBOX_VERSION_CODE);
   rng.randomize(&out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN);
   // space left for MAC here
   if(input_len > 0)
      copy_mem(&out_buf[CRYPTOBOX_HEADER_LEN], input, input_len);

   // Generate the keys and IV

   auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
   auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);

   secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);

   pbkdf->derive_key(
      master_key.data(), master_key.size(),
      passphrase.data(), passphrase.size(),
      &out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN);

   const uint8_t* mk = master_key.data();
   const uint8_t* cipher_key = mk;
   const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
   const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;

   // Now encrypt and authenticate
   std::unique_ptr<Cipher_Mode> ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", ENCRYPTION);
   ctr->set_key(cipher_key, CIPHER_KEY_LEN);
   ctr->start(iv, CIPHER_IV_LEN);
   ctr->finish(out_buf, CRYPTOBOX_HEADER_LEN);

   std::unique_ptr<MessageAuthenticationCode> hmac =
      MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
   hmac->set_key(mac_key, MAC_KEY_LEN);
   if(input_len > 0)
      hmac->update(&out_buf[CRYPTOBOX_HEADER_LEN], input_len);

   // Can't write directly because of MAC truncation
   secure_vector<uint8_t> mac = hmac->final();
   copy_mem(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], mac.data(), MAC_OUTPUT_LEN);

   return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE");
   }

secure_vector<uint8_t>
decrypt_bin(const uint8_t input[], size_t input_len,
            const std::string& passphrase)
   {
   DataSource_Memory input_src(input, input_len);
   secure_vector<uint8_t> ciphertext =
      PEM_Code::decode_check_label(input_src,
                                   "BOTAN CRYPTOBOX MESSAGE");

   if(ciphertext.size() < CRYPTOBOX_HEADER_LEN)
      throw Decoding_Error("Invalid CryptoBox input");

   for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
      if(ciphertext[i] != get_byte(i, CRYPTOBOX_VERSION_CODE))
         throw Decoding_Error("Bad CryptoBox version");

   const uint8_t* pbkdf_salt = &ciphertext[VERSION_CODE_LEN];
   const uint8_t* box_mac = &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN];

   auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
   auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);

   secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);

   pbkdf->derive_key(
      master_key.data(), master_key.size(),
      passphrase.data(), passphrase.size(),
      pbkdf_salt, PBKDF_SALT_LEN);

   const uint8_t* mk = master_key.data();
   const uint8_t* cipher_key = mk;
   const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
   const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;

   // Now authenticate and decrypt
   std::unique_ptr<MessageAuthenticationCode> hmac =
      MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
   hmac->set_key(mac_key, MAC_KEY_LEN);

   if(ciphertext.size() > CRYPTOBOX_HEADER_LEN)
      {
      hmac->update(&ciphertext[CRYPTOBOX_HEADER_LEN],
                   ciphertext.size() - CRYPTOBOX_HEADER_LEN);
      }
   secure_vector<uint8_t> computed_mac = hmac->final();

   if(!constant_time_compare(computed_mac.data(), box_mac, MAC_OUTPUT_LEN))
      throw Decoding_Error("CryptoBox integrity failure");

   std::unique_ptr<Cipher_Mode> ctr(Cipher_Mode::create_or_throw("Serpent/CTR-BE", DECRYPTION));
   ctr->set_key(cipher_key, CIPHER_KEY_LEN);
   ctr->start(iv, CIPHER_IV_LEN);
   ctr->finish(ciphertext, CRYPTOBOX_HEADER_LEN);

   ciphertext.erase(ciphertext.begin(), ciphertext.begin() + CRYPTOBOX_HEADER_LEN);
   return ciphertext;
   }

secure_vector<uint8_t> decrypt_bin(const std::string& input,
                                   const std::string& passphrase)
   {
   return decrypt_bin(cast_char_ptr_to_uint8(input.data()),
                      input.size(),
                      passphrase);
   }

std::string decrypt(const uint8_t input[], size_t input_len,
                    const std::string& passphrase)
   {
   const secure_vector<uint8_t> bin = decrypt_bin(input, input_len, passphrase);

   return std::string(cast_uint8_ptr_to_char(&bin[0]),
                      bin.size());
   }

std::string decrypt(const std::string& input,
                    const std::string& passphrase)
   {
   return decrypt(cast_char_ptr_to_uint8(input.data()),
                  input.size(), passphrase);
   }

}

}
<commit_msg>Remove unused variable<commit_after>/*
* Cryptobox Message Routines
* (C) 2009 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/cryptobox.h>
#include <botan/cipher_mode.h>
#include <botan/mac.h>
#include <botan/rng.h>
#include <botan/pwdhash.h>
#include <botan/data_src.h>
#include <botan/pem.h>
#include <botan/internal/loadstor.h>
#include <botan/mem_ops.h>

namespace Botan {

namespace CryptoBox {

namespace {

/*
First 24 bits of SHA-256("Botan Cryptobox"), followed by 8 0 bits
for later use as flags, etc if needed
*/
const uint32_t CRYPTOBOX_VERSION_CODE = 0xEFC22400;

const size_t VERSION_CODE_LEN = 4;
const size_t CIPHER_KEY_LEN = 32;
const size_t CIPHER_IV_LEN = 16;
const size_t MAC_KEY_LEN = 32;
const size_t MAC_OUTPUT_LEN = 20;
const size_t PBKDF_SALT_LEN = 10;
const size_t PBKDF_ITERATIONS = 8 * 1024;

const size_t CRYPTOBOX_HEADER_LEN = VERSION_CODE_LEN + PBKDF_SALT_LEN + MAC_OUTPUT_LEN;

}

std::string encrypt(const uint8_t input[], size_t input_len,
                    const std::string& passphrase,
                    RandomNumberGenerator& rng)
   {
   /*
   Output format is:
      version # (4 bytes)
      salt (10 bytes)
      mac (20 bytes)
      ciphertext
   */
   secure_vector<uint8_t> out_buf(CRYPTOBOX_HEADER_LEN + input_len);
   for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
     out_buf[i] = get_byte(i, CRYPTOBOX_VERSION_CODE);
   rng.randomize(&out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN);
   // space left for MAC here
   if(input_len > 0)
      copy_mem(&out_buf[CRYPTOBOX_HEADER_LEN], input, input_len);

   // Generate the keys and IV

   auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
   auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);

   secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);

   pbkdf->derive_key(
      master_key.data(), master_key.size(),
      passphrase.data(), passphrase.size(),
      &out_buf[VERSION_CODE_LEN], PBKDF_SALT_LEN);

   const uint8_t* mk = master_key.data();
   const uint8_t* cipher_key = mk;
   const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
   const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;

   // Now encrypt and authenticate
   std::unique_ptr<Cipher_Mode> ctr = Cipher_Mode::create_or_throw("Serpent/CTR-BE", ENCRYPTION);
   ctr->set_key(cipher_key, CIPHER_KEY_LEN);
   ctr->start(iv, CIPHER_IV_LEN);
   ctr->finish(out_buf, CRYPTOBOX_HEADER_LEN);

   std::unique_ptr<MessageAuthenticationCode> hmac =
      MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
   hmac->set_key(mac_key, MAC_KEY_LEN);
   if(input_len > 0)
      hmac->update(&out_buf[CRYPTOBOX_HEADER_LEN], input_len);

   // Can't write directly because of MAC truncation
   secure_vector<uint8_t> mac = hmac->final();
   copy_mem(&out_buf[VERSION_CODE_LEN + PBKDF_SALT_LEN], mac.data(), MAC_OUTPUT_LEN);

   return PEM_Code::encode(out_buf, "BOTAN CRYPTOBOX MESSAGE");
   }

secure_vector<uint8_t>
decrypt_bin(const uint8_t input[], size_t input_len,
            const std::string& passphrase)
   {
   DataSource_Memory input_src(input, input_len);
   secure_vector<uint8_t> ciphertext =
      PEM_Code::decode_check_label(input_src,
                                   "BOTAN CRYPTOBOX MESSAGE");

   if(ciphertext.size() < CRYPTOBOX_HEADER_LEN)
      throw Decoding_Error("Invalid CryptoBox input");

   for(size_t i = 0; i != VERSION_CODE_LEN; ++i)
      if(ciphertext[i] != get_byte(i, CRYPTOBOX_VERSION_CODE))
         throw Decoding_Error("Bad CryptoBox version");

   const uint8_t* pbkdf_salt = &ciphertext[VERSION_CODE_LEN];
   const uint8_t* box_mac = &ciphertext[VERSION_CODE_LEN + PBKDF_SALT_LEN];

   auto pbkdf_fam = PasswordHashFamily::create_or_throw("PBKDF2(HMAC(SHA-512))");
   auto pbkdf = pbkdf_fam->from_params(PBKDF_ITERATIONS);

   secure_vector<uint8_t> master_key(CIPHER_KEY_LEN + MAC_KEY_LEN + CIPHER_IV_LEN);

   pbkdf->derive_key(
      master_key.data(), master_key.size(),
      passphrase.data(), passphrase.size(),
      pbkdf_salt, PBKDF_SALT_LEN);

   const uint8_t* mk = master_key.data();
   const uint8_t* cipher_key = mk;
   const uint8_t* mac_key = mk + CIPHER_KEY_LEN;
   const uint8_t* iv = mk + CIPHER_KEY_LEN + MAC_KEY_LEN;

   // Now authenticate and decrypt
   std::unique_ptr<MessageAuthenticationCode> hmac =
      MessageAuthenticationCode::create_or_throw("HMAC(SHA-512)");
   hmac->set_key(mac_key, MAC_KEY_LEN);

   if(ciphertext.size() > CRYPTOBOX_HEADER_LEN)
      {
      hmac->update(&ciphertext[CRYPTOBOX_HEADER_LEN],
                   ciphertext.size() - CRYPTOBOX_HEADER_LEN);
      }
   secure_vector<uint8_t> computed_mac = hmac->final();

   if(!constant_time_compare(computed_mac.data(), box_mac, MAC_OUTPUT_LEN))
      throw Decoding_Error("CryptoBox integrity failure");

   std::unique_ptr<Cipher_Mode> ctr(Cipher_Mode::create_or_throw("Serpent/CTR-BE", DECRYPTION));
   ctr->set_key(cipher_key, CIPHER_KEY_LEN);
   ctr->start(iv, CIPHER_IV_LEN);
   ctr->finish(ciphertext, CRYPTOBOX_HEADER_LEN);

   ciphertext.erase(ciphertext.begin(), ciphertext.begin() + CRYPTOBOX_HEADER_LEN);
   return ciphertext;
   }

secure_vector<uint8_t> decrypt_bin(const std::string& input,
                                   const std::string& passphrase)
   {
   return decrypt_bin(cast_char_ptr_to_uint8(input.data()),
                      input.size(),
                      passphrase);
   }

std::string decrypt(const uint8_t input[], size_t input_len,
                    const std::string& passphrase)
   {
   const secure_vector<uint8_t> bin = decrypt_bin(input, input_len, passphrase);

   return std::string(cast_uint8_ptr_to_char(&bin[0]),
                      bin.size());
   }

std::string decrypt(const std::string& input,
                    const std::string& passphrase)
   {
   return decrypt(cast_char_ptr_to_uint8(input.data()),
                  input.size(), passphrase);
   }

}

}
<|endoftext|>


<commit_before>/*
 * PlasticConnTestProbe.cpp
 *
 *  Created on:
 *      Author: garkenyon
 */

#include "PlasticConnTestProbe.hpp"
#include <string.h>
#include <assert.h>

namespace PV {

/**
 * @filename
 * @type
 * @msg
 */
PlasticConnTestProbe::PlasticConnTestProbe(const char * probename, const char * filename, HyPerCol * hc, int kernelIndex, int arborId)
{
   initialize(probename, filename, hc, kernelIndex, arborId);
}

int PlasticConnTestProbe::initialize(const char * probename, const char * filename, HyPerCol * hc, int kernelIndex, int arborId) {
   errorPresent = false;
   return KernelProbe::initialize(probename, filename, hc, kernelIndex, arborId);
}
/**
 * @timef
 * @l
 */
int PlasticConnTestProbe::outputState(float timef, HyPerConn * c) {
#ifdef PV_USE_MPI
   InterColComm * icComm = c->getParent()->icCommunicator();
   const int rcvProc = 0;
   if( icComm->commRank() != rcvProc ) {
      return PV_SUCCESS;
   }
#endif // PV_USE_MPI
   KernelConn * kconn = dynamic_cast<KernelConn *>(c);
   if( kconn == NULL ) {
      fprintf(stderr, "PlasticConnTestProbe \"%s\": connection \"%s\" is not a KernelConn.\n", name, c->getName() );
      return PV_FAILURE;
   }
   fprintf(fp, "    Time %f, connection \"%s\":\n", timef, kconn->getName());
   const PVPatch * wPatch = kconn->getKernelPatch(arborID, kernelIndex);
   const pvdata_t * w = wPatch->data;
   const pvdata_t * dw = kconn->get_dKernelData(arborID, kernelIndex);
   if( outputPlasticIncr && dw == NULL ) {
      fprintf(stderr, "PlasticConnTestProbe \"%s\": connection \"%s\" has dKernelData(%d,%d) set to null.\n", name, kconn->getName(), kernelIndex, arborID);
      assert(false);
   }
   int nxp = kconn->xPatchSize();
   int nyp = kconn->yPatchSize();
   int nfp = kconn->fPatchSize();
   int status = PV_SUCCESS;
   for( int k=0; k<nxp*nyp*nfp; k++ ) {
      int x=kxPos(k,nxp,nyp,nfp);
      int wx = (nxp-1)/2 - x; // assumes connection is one-to-one
      if(outputWeights) {
         pvdata_t wCorrect = timef*wx;
         pvdata_t wObserved = w[k];
         if( fabs( (wObserved - wCorrect)/timef ) > 1e-4 ) {
            status = PV_FAILURE;
            int y=kyPos(k,nxp,nyp,nfp);
            int f=featureIndex(k,nxp,nyp,nfp);
            fprintf(fp, "        index %d (x=%d, y=%d, f=%d: w = %f, should be %f\n", k, x, y, f, wObserved, wCorrect);
         }
      }
      if(timef > 0 && outputPlasticIncr && dw != NULL) {
         pvdata_t dwCorrect = wx;
         pvdata_t dwObserved = dw[k];
         if( dwObserved != dwCorrect ) {
            status = PV_FAILURE;
            int y=kyPos(k,nxp,nyp,nfp);
            int f=featureIndex(k,nxp,nyp,nfp);
            fprintf(fp, "        index %d (x=%d, y=%d, f=%d: dw = %f, should be %f\n", k, x, y, f, dwObserved, dwCorrect);
         }
      }
   }
   // assert(status==PV_SUCCESS);
   if( status == PV_SUCCESS ) {
      if( outputWeights ) fprintf(fp, "        All weights are correct.\n");
      if( outputPlasticIncr ) fprintf(fp, "        All plastic increments are correct.\n");
   }
   if(outputPatchIndices) {
      patchIndices(kconn);
   }

   return PV_SUCCESS;
}

PlasticConnTestProbe::~PlasticConnTestProbe() {
   if( !errorPresent ) {
      fprintf(fp, "No errors detected\n");
   }
}

}  // end of namespace PV block
<commit_msg>Restored an assert that got commented out at some point<commit_after>/*
 * PlasticConnTestProbe.cpp
 *
 *  Created on:
 *      Author: garkenyon
 */

#include "PlasticConnTestProbe.hpp"
#include <string.h>
#include <assert.h>

namespace PV {

/**
 * @filename
 * @type
 * @msg
 */
PlasticConnTestProbe::PlasticConnTestProbe(const char * probename, const char * filename, HyPerCol * hc, int kernelIndex, int arborId)
{
   initialize(probename, filename, hc, kernelIndex, arborId);
}

int PlasticConnTestProbe::initialize(const char * probename, const char * filename, HyPerCol * hc, int kernelIndex, int arborId) {
   errorPresent = false;
   return KernelProbe::initialize(probename, filename, hc, kernelIndex, arborId);
}
/**
 * @timef
 * @l
 */
int PlasticConnTestProbe::outputState(float timef, HyPerConn * c) {
#ifdef PV_USE_MPI
   InterColComm * icComm = c->getParent()->icCommunicator();
   const int rcvProc = 0;
   if( icComm->commRank() != rcvProc ) {
      return PV_SUCCESS;
   }
#endif // PV_USE_MPI
   KernelConn * kconn = dynamic_cast<KernelConn *>(c);
   if( kconn == NULL ) {
      fprintf(stderr, "PlasticConnTestProbe \"%s\": connection \"%s\" is not a KernelConn.\n", name, c->getName() );
      return PV_FAILURE;
   }
   fprintf(fp, "    Time %f, connection \"%s\":\n", timef, kconn->getName());
   const PVPatch * wPatch = kconn->getKernelPatch(arborID, kernelIndex);
   const pvdata_t * w = wPatch->data;
   const pvdata_t * dw = kconn->get_dKernelData(arborID, kernelIndex);
   if( outputPlasticIncr && dw == NULL ) {
      fprintf(stderr, "PlasticConnTestProbe \"%s\": connection \"%s\" has dKernelData(%d,%d) set to null.\n", name, kconn->getName(), kernelIndex, arborID);
      assert(false);
   }
   int nxp = kconn->xPatchSize();
   int nyp = kconn->yPatchSize();
   int nfp = kconn->fPatchSize();
   int status = PV_SUCCESS;
   for( int k=0; k<nxp*nyp*nfp; k++ ) {
      int x=kxPos(k,nxp,nyp,nfp);
      int wx = (nxp-1)/2 - x; // assumes connection is one-to-one
      if(outputWeights) {
         pvdata_t wCorrect = timef*wx;
         pvdata_t wObserved = w[k];
         if( fabs( (wObserved - wCorrect)/timef ) > 1e-4 ) {
            status = PV_FAILURE;
            int y=kyPos(k,nxp,nyp,nfp);
            int f=featureIndex(k,nxp,nyp,nfp);
            fprintf(fp, "        index %d (x=%d, y=%d, f=%d: w = %f, should be %f\n", k, x, y, f, wObserved, wCorrect);
         }
      }
      if(timef > 0 && outputPlasticIncr && dw != NULL) {
         pvdata_t dwCorrect = wx;
         pvdata_t dwObserved = dw[k];
         if( dwObserved != dwCorrect ) {
            status = PV_FAILURE;
            int y=kyPos(k,nxp,nyp,nfp);
            int f=featureIndex(k,nxp,nyp,nfp);
            fprintf(fp, "        index %d (x=%d, y=%d, f=%d: dw = %f, should be %f\n", k, x, y, f, dwObserved, dwCorrect);
         }
      }
   }
   assert(status==PV_SUCCESS);
   if( status == PV_SUCCESS ) {
      if( outputWeights ) fprintf(fp, "        All weights are correct.\n");
      if( outputPlasticIncr ) fprintf(fp, "        All plastic increments are correct.\n");
   }
   if(outputPatchIndices) {
      patchIndices(kconn);
   }

   return PV_SUCCESS;
}

PlasticConnTestProbe::~PlasticConnTestProbe() {
   if( !errorPresent ) {
      fprintf(fp, "No errors detected\n");
   }
}

}  // end of namespace PV block
<|endoftext|>


<commit_before>#include <ros/ros.h>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <sensor_msgs/image_encodings.h>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

static const std::string OPENCV_WINDOW = "Image window";

class ImageConverter
{
  ros::NodeHandle nh_;
  image_transport::ImageTransport it_;
  image_transport::Subscriber image_sub_;
  image_transport::Publisher image_pub_;

public:
  ImageConverter()
    : it_(nh_)
  {
    // Subscrive to input video feed and publish output video feed
    image_sub_ = it_.subscribe("/pioneer3at_ros/camera_ros/image", 1,
      &ImageConverter::imageCb, this);
    image_pub_ = it_.advertise("/image_converter/output_video", 1);

    cv::namedWindow(OPENCV_WINDOW);
  }

  ~ImageConverter()
  {
    cv::destroyWindow(OPENCV_WINDOW);
  }

  void imageCb(const sensor_msgs::ImageConstPtr& msg)
  {
    cv_bridge::CvImagePtr cv_ptr;
    try
    {
      cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);
    }
    catch (cv_bridge::Exception& e)
    {
      ROS_ERROR("cv_bridge exception: %s", e.what());
      return;
    }

    // Draw an example circle on the video stream
    if (cv_ptr->image.rows > 60 && cv_ptr->image.cols > 60)
      cv::circle(cv_ptr->image, cv::Point(50, 50), 10, CV_RGB(255,0,0));

    // Update GUI Window
    cv::imshow(OPENCV_WINDOW, cv_ptr->image);
    cv::waitKey(3);

    // Output modified video stream
    image_pub_.publish(cv_ptr->toImageMsg());
  }
};

int main(int argc, char** argv)
{
  ros::init(argc, argv, "image_converter");
  ImageConverter ic;
  ros::spin();
  return 0;
}
<commit_msg>Delete image_converter_OLD.cpp<commit_after><|endoftext|>