TEST(RangeFilterTest, negativeValues) { BOX3D srcBounds(0.0, 0.0, -10.0, 0.0, 0.0, 10.0); Options ops; ops.add("bounds", srcBounds); ops.add("mode", "ramp"); ops.add("count", 21); FauxReader reader; reader.setOptions(ops); Options rangeOps; rangeOps.add("limits", "Z[-1:1)"); RangeFilter filter; filter.setOptions(rangeOps); filter.setInput(reader); PointTable table; filter.prepare(table); PointViewSet viewSet = filter.execute(table); PointViewPtr view = *viewSet.begin(); EXPECT_EQ(1u, viewSet.size()); EXPECT_EQ(2u, view->size()); EXPECT_FLOAT_EQ(-1.0, view->getFieldAs<double>(Dimension::Id::Z, 0)); EXPECT_FLOAT_EQ(0.0, view->getFieldAs<double>(Dimension::Id::Z, 1)); }
TEST(RangeFilterTest, simple_logic) { Options ops; ops.add("bounds", BOX3D(1, 101, 201, 10, 110, 210)); ops.add("mode", "ramp"); ops.add("count", 10); FauxReader reader; reader.setOptions(ops); Options rangeOps; rangeOps.add("limits", "Y[108:109], X[2:5], Z[1:1000], X[7:9], Y[103:105]"); RangeFilter filter; filter.setOptions(rangeOps); filter.setInput(reader); PointTable table; filter.prepare(table); PointViewSet viewSet = filter.execute(table); PointViewPtr view = *viewSet.begin(); EXPECT_EQ(1u, viewSet.size()); EXPECT_EQ(5u, view->size()); EXPECT_EQ(view->getFieldAs<int>(Dimension::Id::X, 0), 3); EXPECT_EQ(view->getFieldAs<int>(Dimension::Id::X, 1), 4); EXPECT_EQ(view->getFieldAs<int>(Dimension::Id::X, 2), 5); EXPECT_EQ(view->getFieldAs<int>(Dimension::Id::X, 3), 8); EXPECT_EQ(view->getFieldAs<int>(Dimension::Id::X, 4), 9); }
TEST(DecimationFilterTest, DecimationFilterTest_test1) { BOX3D srcBounds(0.0, 0.0, 0.0, 100.0, 100.0, 100.0); Options ops; ops.add("bounds", srcBounds); ops.add("mode", "random"); ops.add("num_points", 30); FauxReader reader; reader.setOptions(ops); Options decimationOps; decimationOps.add("step", 10); DecimationFilter filter; filter.setOptions(decimationOps); filter.setInput(reader); PointTable table; filter.prepare(table); PointViewSet viewSet = filter.execute(table); EXPECT_EQ(viewSet.size(), 1u); PointViewPtr view = *viewSet.begin(); EXPECT_EQ(view->size(), 3u); uint64_t t0 = view->getFieldAs<uint64_t>(Dimension::Id::OffsetTime, 0); uint64_t t1 = view->getFieldAs<uint64_t>(Dimension::Id::OffsetTime, 1); uint64_t t2 = view->getFieldAs<uint64_t>(Dimension::Id::OffsetTime, 2); EXPECT_EQ(t0, 0u); EXPECT_EQ(t1, 10u); EXPECT_EQ(t2, 20u); }
TEST(RangeFilterTest, negation) { BOX3D srcBounds(0.0, 0.0, 1.0, 0.0, 0.0, 10.0); Options ops; ops.add("bounds", srcBounds); ops.add("mode", "ramp"); ops.add("count", 10); StageFactory f; FauxReader reader; reader.setOptions(ops); Options rangeOps; rangeOps.add("limits", "Z![2:5]"); RangeFilter filter; filter.setOptions(rangeOps); filter.setInput(reader); PointTable table; filter.prepare(table); PointViewSet viewSet = filter.execute(table); PointViewPtr view = *viewSet.begin(); EXPECT_EQ(1u, viewSet.size()); EXPECT_EQ(6u, view->size()); EXPECT_FLOAT_EQ(1.0, view->getFieldAs<double>(Dimension::Id::Z, 0)); EXPECT_FLOAT_EQ(6.0, view->getFieldAs<double>(Dimension::Id::Z, 1)); EXPECT_FLOAT_EQ(7.0, view->getFieldAs<double>(Dimension::Id::Z, 2)); EXPECT_FLOAT_EQ(8.0, view->getFieldAs<double>(Dimension::Id::Z, 3)); EXPECT_FLOAT_EQ(9.0, view->getFieldAs<double>(Dimension::Id::Z, 4)); EXPECT_FLOAT_EQ(10.0, view->getFieldAs<double>(Dimension::Id::Z, 5)); }
bool genlas(const ossimFilename& fname) { cout << "Generating file <"<<fname<<">"<<endl; FauxReader reader; Options roptions; BOX3D bbox(-0.001, -0.001, -100.0, 0.001, 0.001, 100.0); roptions.add("bounds", bbox); roptions.add("num_points", 11); roptions.add("mode", "ramp"); reader.setOptions(roptions); LasWriter writer; Options woptions; woptions.add("filename", fname.string()); woptions.add("a_srs", "EPSG:4326"); // causes core dump when ossimInit::initialize() called on startup woptions.add("scale_x", 0.0000001); woptions.add("scale_y", 0.0000001); writer.setOptions(woptions); writer.setInput(reader); PointTable wtable; writer.prepare(wtable); writer.execute(wtable); return true; }
TEST(RandomizeFilterTest, simple) { // This isn't a real test. It's just here to allow easy debugging. point_count_t count = 1000; Options readerOps; readerOps.add("bounds", BOX3D(1, 1, 1, (double)count, (double)count, (double)count)); readerOps.add("mode", "ramp"); readerOps.add("count", count); FauxReader r; r.setOptions(readerOps); RandomizeFilter f; f.setInput(r); PointTable t; f.prepare(t); PointViewSet s = f.execute(t); EXPECT_EQ(s.size(), 1u); PointViewPtr v = *s.begin(); EXPECT_EQ(v->size(), (size_t)count); /** for (PointId i = 0; i < count; i++) std::cerr << "X[" << i << "] = " << v->getFieldAs<double>(Dimension::Id::X, i) << "!\n"; **/ }
TEST(RangeFilterTest, multipleDimensions) { BOX3D srcBounds(0.0, 1.0, 1.0, 0.0, 10.0, 10.0); Options ops; ops.add("bounds", srcBounds); ops.add("mode", "ramp"); ops.add("count", 10); FauxReader reader; reader.setOptions(ops); Options rangeOps; rangeOps.add("limits", "Y[4.00e0:+6]"); rangeOps.add("limits", "Z[4:6]"); RangeFilter filter; filter.setOptions(rangeOps); filter.setInput(reader); PointTable table; filter.prepare(table); PointViewSet viewSet = filter.execute(table); PointViewPtr view = *viewSet.begin(); EXPECT_EQ(1u, viewSet.size()); EXPECT_EQ(3u, view->size()); EXPECT_FLOAT_EQ(4.0, view->getFieldAs<double>(Dimension::Id::Y, 0)); EXPECT_FLOAT_EQ(5.0, view->getFieldAs<double>(Dimension::Id::Y, 1)); EXPECT_FLOAT_EQ(6.0, view->getFieldAs<double>(Dimension::Id::Y, 2)); EXPECT_FLOAT_EQ(4.0, view->getFieldAs<double>(Dimension::Id::Z, 0)); EXPECT_FLOAT_EQ(5.0, view->getFieldAs<double>(Dimension::Id::Z, 1)); EXPECT_FLOAT_EQ(6.0, view->getFieldAs<double>(Dimension::Id::Z, 2)); }
TEST(CropFilterTest, test_crop) { BOX3D srcBounds(0.0, 0.0, 0.0, 10.0, 100.0, 1000.0); Options opts; opts.add("bounds", srcBounds); opts.add("num_points", 1000); opts.add("mode", "ramp"); FauxReader reader; reader.setOptions(opts); // crop the window to 1/3rd the size in each dimension BOX2D dstBounds(3.33333, 33.33333, 6.66666, 66.66666); Options cropOpts; cropOpts.add("bounds", dstBounds); CropFilter filter; filter.setOptions(cropOpts); filter.setInput(reader); Options statOpts; StatsFilter stats; stats.setOptions(statOpts); stats.setInput(filter); PointTable table; stats.prepare(table); PointViewSet viewSet = stats.execute(table); EXPECT_EQ(viewSet.size(), 1u); PointViewPtr buf = *viewSet.begin(); const stats::Summary& statsX = stats.getStats(Dimension::Id::X); const stats::Summary& statsY = stats.getStats(Dimension::Id::Y); const stats::Summary& statsZ = stats.getStats(Dimension::Id::Z); EXPECT_EQ(buf->size(), 333u); const double minX = statsX.minimum(); const double minY = statsY.minimum(); const double minZ = statsZ.minimum(); const double maxX = statsX.maximum(); const double maxY = statsY.maximum(); const double maxZ = statsZ.maximum(); const double avgX = statsX.average(); const double avgY = statsY.average(); const double avgZ = statsZ.average(); const double delX = 10.0 / 999.0 * 100.0; const double delY = 100.0 / 999.0 * 100.0; const double delZ = 1000.0 / 999.0 * 100.0; EXPECT_NEAR(minX, 3.33333, delX); EXPECT_NEAR(minY, 33.33333, delY); EXPECT_NEAR(minZ, 333.33333, delZ); EXPECT_NEAR(maxX, 6.66666, delX); EXPECT_NEAR(maxY, 66.66666, delY); EXPECT_NEAR(maxZ, 666.66666, delZ); EXPECT_NEAR(avgX, 5.00000, delX); EXPECT_NEAR(avgY, 50.00000, delY); EXPECT_NEAR(avgZ, 500.00000, delZ); }
TEST_F(PredicateFilterTest, PredicateFilterTest_test_programmable) { StageFactory f; BOX3D bounds(0.0, 0.0, 0.0, 2.0, 2.0, 2.0); Options readerOps; readerOps.add("bounds", bounds); readerOps.add("count", 1000); readerOps.add("mode", "ramp"); FauxReader reader; reader.setOptions(readerOps); // keep all points where x less than 1.0 const Option source("source", // "X < 1.0" "import numpy as np\n" "def yow1(ins,outs):\n" " X = ins['X']\n" " Mask = np.less(X, 1.0)\n" " #print X\n" " #print Mask\n" " outs['Mask'] = Mask\n" " return True\n" ); const Option module("module", "MyModule1"); const Option function("function", "yow1"); Options opts; opts.add(source); opts.add(module); opts.add(function); Stage* filter(f.createStage("filters.python")); filter->setOptions(opts); filter->setInput(reader); Options statOpts; std::unique_ptr<StatsFilter> stats(new StatsFilter); stats->setOptions(statOpts); stats->setInput(*filter); PointTable table; stats->prepare(table); PointViewSet viewSet = stats->execute(table); EXPECT_EQ(viewSet.size(), 1u); const stats::Summary& statsX = stats->getStats(Dimension::Id::X); const stats::Summary& statsY = stats->getStats(Dimension::Id::Y); const stats::Summary& statsZ = stats->getStats(Dimension::Id::Z); EXPECT_TRUE(Utils::compare_approx(statsX.minimum(), 0.0, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsY.minimum(), 0.0, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsZ.minimum(), 0.0, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsX.maximum(), 1.0, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsY.maximum(), 1.0, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsZ.maximum(), 1.0, 0.01)); }
TEST(PredicateFilterTest, PredicateFilterTest_test2) { StageFactory f; // same as above, but with 'Y >' instead of 'X <' BOX3D bounds(0.0, 0.0, 0.0, 2.0, 2.0, 2.0); Options readerOps; readerOps.add("bounds", bounds); readerOps.add("num_points", 1000); readerOps.add("mode", "ramp"); FauxReader reader; reader.setOptions(readerOps); Option source("source", // "Y > 1.0" "import numpy as np\n" "def yow2(ins,outs):\n" " Y = ins['Y']\n" " Mask = np.greater(Y, 1.0)\n" " #print Mask\n" " outs['Mask'] = Mask\n" " return True\n" ); Option module("module", "MyModule1"); Option function("function", "yow2"); Options opts; opts.add(source); opts.add(module); opts.add(function); std::unique_ptr<Stage> filter(f.createStage("filters.predicate")); filter->setOptions(opts); filter->setInput(reader); Options statOpts; std::unique_ptr<StatsFilter> stats(new StatsFilter); stats->setOptions(statOpts); stats->setInput(*filter); PointTable table; stats->prepare(table); PointViewSet viewSet = stats->execute(table); EXPECT_EQ(viewSet.size(), 1u); const stats::Summary& statsX = stats->getStats(Dimension::Id::X); const stats::Summary& statsY = stats->getStats(Dimension::Id::Y); const stats::Summary& statsZ = stats->getStats(Dimension::Id::Z); EXPECT_TRUE(Utils::compare_approx<double>(statsX.minimum(), 1.0, 0.01)); EXPECT_TRUE(Utils::compare_approx<double>(statsY.minimum(), 1.0, 0.01)); EXPECT_TRUE(Utils::compare_approx<double>(statsZ.minimum(), 1.0, 0.01)); EXPECT_TRUE(Utils::compare_approx<double>(statsX.maximum(), 2.0, 0.01)); EXPECT_TRUE(Utils::compare_approx<double>(statsY.maximum(), 2.0, 0.01)); EXPECT_TRUE(Utils::compare_approx<double>(statsZ.maximum(), 2.0, 0.01)); }
TEST_F(PredicateFilterTest, PredicateFilterTest_test_programmable_4) { StageFactory f; // test the point counters in the Predicate's iterator BOX3D bounds(0.0, 0.0, 0.0, 2.0, 2.0, 2.0); Options readerOpts; readerOpts.add("bounds", bounds); readerOpts.add("count", 1000); readerOpts.add("mode", "ramp"); FauxReader reader; reader.setOptions(readerOpts); const Option source("source", // "Y > 0.5" "import numpy as np\n" "def yow2(ins,outs):\n" " Y = ins['Y']\n" " Mask = np.greater(Y, 0.5)\n" " #print Mask\n" " outs['Mask'] = Mask\n" " return True\n" ); const Option module("module", "MyModule1"); const Option function("function", "yow2"); Options opts; opts.add(source); opts.add(module); opts.add(function); Stage* filter(f.createStage("filters.python")); filter->setOptions(opts); filter->setInput(reader); PointTable table; PointViewPtr buf(new PointView(table)); filter->prepare(table); StageWrapper::ready(reader, table); PointViewSet viewSet = StageWrapper::run(reader, buf); StageWrapper::done(reader, table); EXPECT_EQ(viewSet.size(), 1u); buf = *viewSet.begin(); EXPECT_EQ(buf->size(), 1000u); StageWrapper::ready(*filter, table); viewSet = StageWrapper::run(*filter, buf); StageWrapper::done(*filter, table); EXPECT_EQ(viewSet.size(), 1u); buf = *viewSet.begin(); EXPECT_EQ(buf->size(), 750u); }
// This test make sure bounds are correct by using known and calculable counts. TEST(SplitterTest, test_buffer2) { Options readerOptions; readerOptions.add("mode", "grid"); readerOptions.add("bounds", BOX3D(0, 0, 0, 1000, 1000, 0)); FauxReader reader; reader.setOptions(readerOptions); Options splitterOptions; splitterOptions.add("length", 300); splitterOptions.add("origin_x", 500); splitterOptions.add("origin_y", 500); splitterOptions.add("buffer", 25); SplitterFilter splitter; splitter.setOptions(splitterOptions); splitter.setInput(reader); PointTable table; splitter.prepare(table); PointViewSet s = splitter.execute(table); EXPECT_EQ(s.size(), 16U); std::vector<PointViewPtr> vvec; std::map<PointViewPtr, BOX2D> bounds; for (PointViewPtr v : s) { BOX2D b; v->calculateBounds(b); bounds[v] = b; vvec.push_back(v); } auto sorter = [&bounds](PointViewPtr p1, PointViewPtr p2) { BOX2D b1 = bounds[p1]; BOX2D b2 = bounds[p2]; return b1.minx < b2.minx ? true : b1.minx > b2.minx ? false : b1.miny < b2.miny; }; std::sort(vvec.begin(), vvec.end(), sorter); size_t counts[] = { 50625, 78525, 78525, 50400, 78525, 121801, 121801, 78176, 78525, 121801, 121801, 78176, 50400, 78176, 78176, 50176 }; size_t i = 0; for (PointViewPtr v : vvec) EXPECT_EQ(v->size(), counts[i++]); }
TEST(ColorinterpFilterTest, minmax) { FauxReader f; Options options; options.add("count", 100); options.add("mode", "ramp"); options.add("bounds", "([0,99],[0,99],[0,99])"); f.setOptions(options); ColorinterpFilter c; Options coptions; coptions.add("minimum", 0); coptions.add("maximum", 99); coptions.add("ramp", makeColor()); c.setOptions(coptions); StreamCallbackFilter s; c.setInput(f); s.setInput(c); auto cb = [](PointRef& point) { int z = point.getFieldAs<int>(Dimension::Id::Z); int r = point.getFieldAs<int>(Dimension::Id::Red); int g = point.getFieldAs<int>(Dimension::Id::Green); int b = point.getFieldAs<int>(Dimension::Id::Blue); if (z != 99) EXPECT_EQ((int)(z / 25) + 1, r); if (z == 99) EXPECT_EQ(0, r); EXPECT_EQ(0, g); EXPECT_EQ(0, b); return true; }; s.setCallback(cb); FixedPointTable t(10); s.prepare(t); s.execute(t); PointTable t2; s.prepare(t2); s.execute(t2); }
TEST_F(PythonFilterTest, add_dimension) { StageFactory f; BOX3D bounds(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); Options ops; ops.add("bounds", bounds); ops.add("count", 10); ops.add("mode", "ramp"); FauxReader reader; reader.setOptions(ops); Option source("source", "import numpy\n" "def myfunc(ins,outs):\n" " outs['AddedIntensity'] = np.zeros(ins['X'].size, dtype=numpy.double) + 1\n" " outs['AddedPointSourceId'] = np.zeros(ins['X'].size, dtype=numpy.double) + 2\n" " return True\n" ); Option module("module", "MyModule"); Option function("function", "myfunc"); Option intensity("add_dimension", "AddedIntensity"); Option scanDirection("add_dimension", "AddedPointSourceId"); Options opts; opts.add(source); opts.add(module); opts.add(function); opts.add(intensity); opts.add(scanDirection); Stage* filter(f.createStage("filters.python")); filter->setOptions(opts); filter->setInput(reader); PointTable table; filter->prepare(table); PointViewSet viewSet = filter->execute(table); EXPECT_EQ(viewSet.size(), 1u); PointViewPtr view = *viewSet.begin(); PointLayoutPtr layout(table.layout()); Dimension::Id int_id = layout->findDim("AddedIntensity"); Dimension::Id psid_id = layout->findDim("AddedPointSourceId"); for (unsigned int i = 0; i < view->size(); ++i) { EXPECT_EQ(view->getFieldAs<uint16_t>(int_id, i), 1); EXPECT_EQ(view->getFieldAs<uint16_t>(psid_id, i), 2); } }
TEST_F(PythonFilterTest, metadata) { StageFactory f; BOX3D bounds(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); Options ops; ops.add("bounds", bounds); ops.add("count", 10); ops.add("mode", "ramp"); FauxReader reader; reader.setOptions(ops); Option source("source", "import numpy\n" "import sys\n" "import redirector\n" "def myfunc(ins,outs):\n" " global metadata\n" " #print('before', globals(), file=sys.stderr,)\n" " metadata = {'name': 'root', 'value': 'a string', 'type': 'string', 'description': 'a description', 'children': [{'name': 'filters.python', 'value': 52, 'type': 'integer', 'description': 'a filter description', 'children': []}, {'name': 'readers.faux', 'value': 'another string', 'type': 'string', 'description': 'a reader description', 'children': []}]}\n" " # print ('schema', schema, file=sys.stderr,)\n" " return True\n" ); Option module("module", "MyModule"); Option function("function", "myfunc"); Options opts; opts.add(source); opts.add(module); opts.add(function); Stage* filter(f.createStage("filters.python")); filter->setOptions(opts); filter->setInput(reader); PointTable table; filter->prepare(table); PointViewSet viewSet = filter->execute(table); EXPECT_EQ(viewSet.size(), 1u); PointViewPtr view = *viewSet.begin(); PointLayoutPtr layout(table.layout()); MetadataNode m = table.metadata(); m = m.findChild("filters.python"); MetadataNodeList l = m.children(); EXPECT_EQ(l.size(), 3u); EXPECT_EQ(l[0].name(), "filters.python"); EXPECT_EQ(l[0].value(), "52"); EXPECT_EQ(l[0].description(), "a filter description"); }
TEST(OptionsTest, test_static_options) { Options ops; FauxReader reader; reader.setOptions(ops); CropFilter crop; crop.setOptions(ops); crop.setInput(reader); auto opts = crop.getDefaultOptions(); EXPECT_EQ(opts.getOptions().size(), 4u); EXPECT_TRUE(opts.hasOption("bounds")); EXPECT_TRUE(opts.hasOption("inside")); EXPECT_TRUE(opts.hasOption("polygon")); EXPECT_FALSE(opts.hasOption("metes")); }
TEST(RangeFilterTest, stream_logic) { Options ops; ops.add("bounds", BOX3D(1, 101, 201, 10, 110, 210)); ops.add("mode", "ramp"); ops.add("count", 10); FauxReader reader; reader.setOptions(ops); Options rangeOps; rangeOps.add("limits", "Y[108:109], X[2:5], Z[1:1000], X[7:9], Y[103:105]"); RangeFilter range; range.setOptions(rangeOps); range.setInput(reader); StreamCallbackFilter f; f.setInput(range); FixedPointTable table(20); f.prepare(table); auto cb = [](PointRef& point) { static int i = 0; int x = point.getFieldAs<int>(Dimension::Id::X); if (i == 0) EXPECT_EQ(x, 3); else if (i == 1) EXPECT_EQ(x, 4); else if (i == 2) EXPECT_EQ(x, 5); else if (i == 3) EXPECT_EQ(x, 8); else if (i == 4) EXPECT_EQ(x, 9); EXPECT_TRUE(i < 5); ++i; return true; }; f.setCallback(cb); f.execute(table); }
TEST(DividerFilterTest, round_robin_capacity) { point_count_t count = 1000; Options readerOps; readerOps.add("bounds", BOX3D(1, 1, 1, count, count, count)); readerOps.add("mode", "ramp"); readerOps.add("count", count); FauxReader r; r.setOptions(readerOps); Options filterOps; filterOps.add("capacity", 25); filterOps.add("mode", "round_robin"); DividerFilter f; f.setInput(r); f.setOptions(filterOps); PointTable t; f.prepare(t); PointViewSet s = f.execute(t); EXPECT_EQ(s.size(), 40u); PointId i = 0; for (PointViewPtr v : s) EXPECT_EQ(v->size(), 25u); unsigned viewNum = 0; PointId start = 1; for (PointViewPtr v : s) { double value = start; for (PointId i = 0 ; i < v->size(); i++) { EXPECT_DOUBLE_EQ((double)value, v->getFieldAs<double>(Dimension::Id::X, i)); value += 40; } start++; } }
TEST_F(PythonFilterTest, pdalargs) { StageFactory f; BOX3D bounds(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); Options ops; ops.add("bounds", bounds); ops.add("count", 10); ops.add("mode", "ramp"); FauxReader reader; reader.setOptions(ops); Option source("source", "import numpy\n" "import sys\n" "import redirector\n" "def myfunc(ins,outs):\n" " pdalargs['name']\n" "# print ('pdalargs', pdalargs, file=sys.stderr,)\n" " return True\n" ); Option module("module", "MyModule"); Option function("function", "myfunc"); Option args("pdalargs", "{\"name\":\"Howard\",\"something\":42, \"another\": \"True\"}"); Options opts; opts.add(source); opts.add(module); opts.add(function); opts.add(args); Stage* filter(f.createStage("filters.python")); filter->setOptions(opts); filter->setInput(reader); PointTable table; filter->prepare(table); PointViewSet viewSet = filter->execute(table); EXPECT_EQ(viewSet.size(), 1u); PointViewPtr view = *viewSet.begin(); // Not throwing anything is success for now }
TEST(DecimationFilterTest, stream) { BOX3D srcBounds(0.0, 0.0, 0.0, 99.0, 99.0, 99.0); Options ops; ops.add("bounds", srcBounds); ops.add("mode", "ramp"); ops.add("num_points", 100); FauxReader reader; reader.setOptions(ops); Options decimationOps; decimationOps.add("step", 10); decimationOps.add("offset", 10); decimationOps.add("limit", 90); DecimationFilter dec; dec.setOptions(decimationOps); dec.setInput(reader); StreamCallbackFilter filter; auto cb = [](PointRef& point) { static int i = 0; int x = point.getFieldAs<int>(Dimension::Id::X); int y = point.getFieldAs<int>(Dimension::Id::Y); EXPECT_EQ(x, (i + 1) * 10); EXPECT_EQ(y, (i + 1) * 10); EXPECT_TRUE(i < 8); i++; return true; }; filter.setCallback(cb); filter.setInput(dec); FixedPointTable t(2); filter.prepare(t); filter.execute(t); }
TEST(FerryFilterTest, stream) { FauxReader r; Options ro; ro.add("mode", "ramp"); ro.add("bounds", BOX3D(0, 0, 0, 99, 99, 99)); ro.add("num_points", 100); r.setOptions(ro); Options fo; fo.add("dimensions", "X=FooX,Y=BarY"); FerryFilter f; f.setOptions(fo); f.setInput(r); StreamCallbackFilter c; c.setInput(f); FixedPointTable t(10); c.prepare(t); auto foox = t.layout()->findDim("FooX"); auto fooy = t.layout()->findDim("BarY"); auto cb = [foox,fooy](PointRef& point) { static int i = 0; EXPECT_EQ(point.getFieldAs<int>(Dimension::Id::X), point.getFieldAs<int>(foox)); EXPECT_EQ(point.getFieldAs<int>(Dimension::Id::Y), point.getFieldAs<int>(fooy)); EXPECT_EQ(i, point.getFieldAs<int>(foox)); ++i; return true; }; c.setCallback(cb); c.execute(t); }
TEST(PredicateFilterTest, PredicateFilterTest_test5) { StageFactory f; // test error handling if missing Mask BOX3D bounds(0.0, 0.0, 0.0, 2.0, 2.0, 2.0); Options readerOpts; readerOpts.add("bounds", bounds); readerOpts.add("num_points", 1000); readerOpts.add("mode", "ramp"); FauxReader reader; reader.setOptions(readerOpts); const Option source("source", // "Y > 0.5" "import numpy as np\n" "def yow2(ins,outs):\n" " Y = ins['Y']\n" " Mask = np.greater(Y, 0.5)\n" " #print Mask\n" " outs['xxxMaskxxx'] = Mask # delierbately rong\n" " return True\n" ); const Option module("module", "MyModule1"); const Option function("function", "yow2"); Options opts; opts.add(source); opts.add(module); opts.add(function); std::unique_ptr<Stage> filter(f.createStage("filters.predicate")); filter->setOptions(opts); filter->setInput(reader); PointTable table; filter->prepare(table); ASSERT_THROW(filter->execute(table), plang::error); }
TEST(ColorinterpFilterTest, cantstream) { FauxReader f; Options options; options.add("count", 100); options.add("mode", "ramp"); options.add("bounds", "([0,99],[0,99],[0,99])"); f.setOptions(options); ColorinterpFilter c; Options coptions; coptions.add("minimum", 0); coptions.add("ramp", makeColor()); c.setOptions(coptions); c.setInput(f); FixedPointTable t(10); c.prepare(t); EXPECT_FALSE(c.pipelineStreamable()); }
TEST(RangeFilterTest, multipleDimsBusted) { BOX3D srcBounds(1, 3, 5, 1, 3, 5); Options ops; ops.add("bounds", srcBounds); ops.add("mode", "ramp"); ops.add("count", 1); FauxReader reader; reader.setOptions(ops); Options rangeOps1; rangeOps1.add("limits", "X[1:1], Y[27:27]"); RangeFilter f1; f1.setOptions(rangeOps1); f1.setInput(reader); PointTable t1; f1.prepare(t1); PointViewSet s1 = f1.execute(t1); PointViewPtr v1 = *s1.begin(); Options rangeOps2; rangeOps2.add("limits", "Y[27:27], X[1:1]"); RangeFilter f2; f2.setOptions(rangeOps2); f2.setInput(reader); PointTable t2; f2.prepare(t2); PointViewSet s2 = f2.execute(t2); PointViewPtr v2 = *s2.begin(); EXPECT_EQ(v1->size(), v2->size()); }
TEST(DividerFilterTest, partition_capacity) { point_count_t count = 1000; Options readerOps; readerOps.add("bounds", BOX3D(1, 1, 1, count, count, count)); readerOps.add("mode", "ramp"); readerOps.add("count", count); FauxReader r; r.setOptions(readerOps); Options filterOps; filterOps.add("capacity", 25); DividerFilter f; f.setInput(r); f.setOptions(filterOps); PointTable t; f.prepare(t); PointViewSet s = f.execute(t); EXPECT_EQ(s.size(), 40u); PointId i = 0; for (PointViewPtr v : s) { EXPECT_EQ(v->size(), 25u); for (PointId p = 0; p < v->size(); ++p) { EXPECT_DOUBLE_EQ((double)(i + 1), v->getFieldAs<double>(Dimension::Id::X, p)); i++; } } }
TEST(ColorinterpFilterTest, badramp) { FauxReader f; Options options; options.add("count", 100); options.add("mode", "ramp"); options.add("bounds", "([0,99],[0,99],[0,99])"); f.setOptions(options); ColorinterpFilter c; Options coptions; coptions.add("minimum", 0); coptions.add("maximum", 100); coptions.add("ramp", "ramp_that_doesnt_exist"); c.setOptions(coptions); c.setInput(f); PointTable t; c.prepare(t); EXPECT_THROW(c.execute(t), pdal_error); }
TEST_F(PythonFilterTest, PythonFilterTest_modify) { StageFactory f; BOX3D bounds(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); Options ops; ops.add("bounds", bounds); ops.add("count", 10); ops.add("mode", "ramp"); FauxReader reader; reader.setOptions(ops); Option source("source", "import numpy as np\n" "def myfunc(ins,outs):\n" " X = ins['X']\n" " Y = ins['Y']\n" " Z = ins['Z']\n" " X = np.delete(X, (9), axis=0)\n" " Y = np.delete(Y, (9), axis=0)\n" " Z = np.delete(Z, (9), axis=0)\n" " Z = np.append(Z,100)\n" " Y = np.append(Y,200)\n" "# print (Z)\n" "# print (X)\n" " outs['Z'] = Z\n" " outs['Y'] = Y\n" " outs['X'] = X\n" "# print (len(X), len(Y), len(Z))\n" " return True\n" ); Option module("module", "MyModule"); Option function("function", "myfunc"); Options opts; opts.add(source); opts.add(module); opts.add(function); Stage* filter(f.createStage("filters.python")); filter->setOptions(opts); filter->setInput(reader); std::unique_ptr<StatsFilter> stats(new StatsFilter); stats->setInput(*filter); PointTable table; stats->prepare(table); PointViewSet viewSet = stats->execute(table); EXPECT_EQ(viewSet.size(), 1u); PointViewPtr view = *viewSet.begin(); const stats::Summary& statsX = stats->getStats(Dimension::Id::X); const stats::Summary& statsY = stats->getStats(Dimension::Id::Y); const stats::Summary& statsZ = stats->getStats(Dimension::Id::Z); EXPECT_EQ(view->size(), 10u); EXPECT_DOUBLE_EQ(statsX.minimum(), 0.0); EXPECT_DOUBLE_EQ(statsX.maximum(), 1.0); EXPECT_DOUBLE_EQ(statsY.minimum(), 0.0); EXPECT_DOUBLE_EQ(statsY.maximum(), 200.0); EXPECT_DOUBLE_EQ(statsZ.minimum(), 0.0); EXPECT_DOUBLE_EQ(statsZ.maximum(), 100); }
TEST(PLangTest, log) { // verify we can redirect the stdout inside the python script Options reader_opts; { BOX3D bounds(1.0, 2.0, 3.0, 101.0, 102.0, 103.0); Option opt1("bounds", bounds); Option opt2("count", 750); Option opt3("mode", "constant"); reader_opts.add(opt1); reader_opts.add(opt2); reader_opts.add(opt3); Option optlog("log", Support::temppath("mylog_three.txt")); reader_opts.add(optlog); } Options xfilter_opts; { const Option source("source", "import numpy as np\n" "import sys\n" "def xfunc(ins,outs):\n" " X = ins['X']\n" " print (\"Testing log output through python script.\")\n" " X = X + 1.0\n" " outs['X'] = X\n" " sys.stdout.flush()\n" " return True\n" ); const Option module("module", "xModule"); const Option function("function", "xfunc"); xfilter_opts.add("log", Support::temppath("mylog_three.txt")); xfilter_opts.add(source); xfilter_opts.add(module); xfilter_opts.add(function); } StageFactory f; { FauxReader reader; reader.setOptions(reader_opts); Stage* xfilter(f.createStage("filters.python")); xfilter->setOptions(xfilter_opts); xfilter->setInput(reader); PointTable table; xfilter->prepare(table); PointViewSet pvSet = xfilter->execute(table); EXPECT_EQ(pvSet.size(), 1u); PointViewPtr view = *pvSet.begin(); EXPECT_EQ(view->size(), 750u); } bool ok = Support::compare_text_files( Support::temppath("mylog_three.txt"), Support::datapath("logs/log_py.txt")); // TODO: fails on Windows // unknown file: error: C++ exception with description "pdalboost::filesystem::remove: // The process cannot access the file because it is being used by another process: // "C:/projects/pdal/test/data/../temp/mylog_three.txt"" thrown in the test body. //if (ok) // FileUtils::deleteFile(Support::temppath("mylog_three.txt")); EXPECT_TRUE(ok); }
TEST_F(PythonFilterTest, PythonFilterTest_test1) { StageFactory f; BOX3D bounds(0.0, 0.0, 0.0, 1.0, 1.0, 1.0); Options ops; ops.add("bounds", bounds); ops.add("count", 10); ops.add("mode", "ramp"); FauxReader reader; reader.setOptions(ops); Option source("source", "import numpy as np\n" "def myfunc(ins,outs):\n" " X = ins['X']\n" " Y = ins['Y']\n" " Z = ins['Z']\n" " #print ins['X']\n" " X = X + 10.0\n" " # Y: leave as-is, don't export back out\n" " # Z: goofiness to make it a numpy array of a constant\n" " Z = np.zeros(X.size) + 3.14\n" " outs['X'] = X\n" " #print outs['X']\n" " outs['Z'] = Z\n" " return True\n" ); Option module("module", "MyModule"); Option function("function", "myfunc"); Options opts; opts.add(source); opts.add(module); opts.add(function); Stage* filter(f.createStage("filters.python")); filter->setOptions(opts); filter->setInput(reader); std::unique_ptr<StatsFilter> stats(new StatsFilter); stats->setInput(*filter); PointTable table; stats->prepare(table); PointViewSet viewSet = stats->execute(table); EXPECT_EQ(viewSet.size(), 1u); PointViewPtr view = *viewSet.begin(); const stats::Summary& statsX = stats->getStats(Dimension::Id::X); const stats::Summary& statsY = stats->getStats(Dimension::Id::Y); const stats::Summary& statsZ = stats->getStats(Dimension::Id::Z); EXPECT_DOUBLE_EQ(statsX.minimum(), 10.0); EXPECT_DOUBLE_EQ(statsX.maximum(), 11.0); EXPECT_DOUBLE_EQ(statsY.minimum(), 0.0); EXPECT_DOUBLE_EQ(statsY.maximum(), 1.0); EXPECT_DOUBLE_EQ(statsZ.minimum(), 3.14); EXPECT_DOUBLE_EQ(statsZ.maximum(), 3.14); }
TEST_F(PredicateFilterTest, PredicateFilterTest_test_programmable_3) { StageFactory f; // can we make a pipeline with TWO python filters in it? BOX3D bounds(0.0, 0.0, 0.0, 2.0, 2.0, 2.0); Options readerOpts; readerOpts.add("bounds", bounds); readerOpts.add("count", 1000); readerOpts.add("mode", "ramp"); FauxReader reader; reader.setOptions(readerOpts); // keep all points where x less than 1.0 const Option source1("source", // "X < 1.0" "import numpy as np\n" "def yow1(ins,outs):\n" " X = ins['X']\n" " Mask = np.less(X, 1.0)\n" " #print X\n" " #print Mask\n" " outs['Mask'] = Mask\n" " return True\n" ); const Option module1("module", "MyModule1"); const Option function1("function", "yow1"); Options opts1; opts1.add(source1); opts1.add(module1); opts1.add(function1); Stage* filter1(f.createStage("filters.python")); filter1->setOptions(opts1); filter1->setInput(reader); // keep all points where y greater than 0.5 const Option source2("source", // "Y > 0.5" "import numpy as np\n" "def yow2(ins,outs):\n" " Y = ins['Y']\n" " Mask = np.greater(Y, 0.5)\n" " #print X\n" " #print Mask\n" " outs['Mask'] = Mask\n" " return True\n" ); const Option module2("module", "MyModule2"); const Option function2("function", "yow2"); Options opts2; opts2.add(source2); opts2.add(module2); opts2.add(function2); Stage* filter2(f.createStage("filters.python")); filter2->setOptions(opts2); filter2->setInput(*filter1); Options statOpts; std::unique_ptr<StatsFilter> stats(new StatsFilter); stats->setOptions(statOpts); stats->setInput(*filter2); PointTable table; stats->prepare(table); stats->execute(table); const stats::Summary& statsX = stats->getStats(Dimension::Id::X); const stats::Summary& statsY = stats->getStats(Dimension::Id::Y); const stats::Summary& statsZ = stats->getStats(Dimension::Id::Z); EXPECT_TRUE(Utils::compare_approx(statsX.minimum(), 0.5, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsY.minimum(), 0.5, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsZ.minimum(), 0.5, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsX.maximum(), 1.0, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsY.maximum(), 1.0, 0.01)); EXPECT_TRUE(Utils::compare_approx(statsZ.maximum(), 1.0, 0.01)); }