From 8cbc93aa1794cca0f6d72e56fb10139aa50fcc21 Mon Sep 17 00:00:00 2001 From: Eric Lidwa Date: Fri, 3 Jan 2025 19:50:42 +0000 Subject: [PATCH] added luaBatchSample, updated bluetopo tests --- clients/python/tests/test_bluetopo.py | 13 +- .../bluetopo/selftests/bluetopo_reader.lua | 10 +- datasets/icesat2/package/MeritRaster.cpp | 13 +- datasets/icesat2/package/MeritRaster.h | 2 +- datasets/pgc/package/PgcDemStripsRaster.cpp | 4 +- .../pgc/selftests/arcticdem_reader_batch.lua | 81 +++++++ packages/arrow/ArrowSamplerImpl.cpp | 4 +- packages/geo/GeoIndexedRaster.h | 2 +- packages/geo/GeoIndexedRasterBatch.cpp | 8 +- packages/geo/GeoIndexedRasterSerial.cpp | 6 +- packages/geo/GeoRaster.cpp | 5 +- packages/geo/GeoRaster.h | 2 +- packages/geo/RasterObject.cpp | 207 ++++++++++++++---- packages/geo/RasterObject.h | 9 +- packages/geo/RasterSampler.cpp | 6 +- packages/geo/UT_RasterSample.cpp | 24 +- packages/geo/UT_RasterSubset.cpp | 8 +- scripts/selftests/test_runner.lua | 1 + 18 files changed, 305 insertions(+), 100 deletions(-) create mode 100644 datasets/pgc/selftests/arcticdem_reader_batch.lua diff --git a/clients/python/tests/test_bluetopo.py b/clients/python/tests/test_bluetopo.py index 8fb5533c..06e0b953 100644 --- a/clients/python/tests/test_bluetopo.py +++ b/clients/python/tests/test_bluetopo.py @@ -8,14 +8,13 @@ sigma = 1.0e-9 -lon = -80.87 -lat = 32.06 +lon = -81.02 +lat = 31.86 -file = '/vsis3/noaa-ocs-nationalbathymetry-pds/BlueTopo/BH4SX59B/BlueTopo_BH4SX59B_20241203.tiff' - -expElevation = -4.14 -expUncertainty = 1.03 -expContributor = 63824 +file = '/vsis3/noaa-ocs-nationalbathymetry-pds/BlueTopo/BH4SV597/BlueTopo_BH4SV597_20241219.tiff' +expElevation = -14.10 +expUncertainty = 2.58 +expContributor = 63846 @pytest.mark.network class TestBlueTopo: diff --git a/datasets/bluetopo/selftests/bluetopo_reader.lua b/datasets/bluetopo/selftests/bluetopo_reader.lua index 7c09662d..7411f5c7 100644 --- a/datasets/bluetopo/selftests/bluetopo_reader.lua +++ b/datasets/bluetopo/selftests/bluetopo_reader.lua @@ -11,13 +11,13 @@ local assets = asset.loaddir() -- Correct values test for different POIs -local lons = {-80.87, -81.02, -89.66, -94.72} -local lats = { 32.06, 31.86, 29.99, 29.35} +local lons = {-81.02, -89.66, -94.72} +local lats = { 31.86, 29.99, 29.35} height = 0 -local expElevation = { -4.14, -14.10, -4.28, -17.18} -local expUncertainty = { 1.03, 2.58, 0.34, 1.32} -local expContributor = { 63824, 63846, 24955, 45641} +local expElevation = {-14.10, -4.28, -17.18} +local expUncertainty = { 2.58, 0.34, 1.32} +local expContributor = { 63846, 24955, 45641} local elevation_tolerance = 0.01; diff --git a/datasets/icesat2/package/MeritRaster.cpp b/datasets/icesat2/package/MeritRaster.cpp index 90bad325..7accc8d2 100644 --- a/datasets/icesat2/package/MeritRaster.cpp +++ b/datasets/icesat2/package/MeritRaster.cpp @@ -112,26 +112,25 @@ MeritRaster::MeritRaster(lua_State *L, RequestFields* rqst_parms, const char* ke /*---------------------------------------------------------------------------- * getSamples *----------------------------------------------------------------------------*/ -uint32_t MeritRaster::getSamples (const MathLib::point_3d_t& point, int64_t gps, List& slist, void* param) +uint32_t MeritRaster::getSamples (const point_info_t& pinfo, sample_list_t& slist, void* param) { (void)param; - (void)gps; lockSampling(); /* Determine Upper Left Coordinates */ - int left_lon = ((int)floor(point.x / 5.0)) * 5; - int upper_lat = ((int)ceil(point.y / 5.0)) * 5; + int left_lon = ((int)floor(pinfo.point3d.x / 5.0)) * 5; + int upper_lat = ((int)ceil(pinfo.point3d.y / 5.0)) * 5; /* Calculate Pixel Location */ - const int x_offset = (int)(((double)point.x - left_lon) / X_SCALE); - const int y_offset = (int)(((double)point.y - upper_lat) / Y_SCALE); + const int x_offset = (int)(((double)pinfo.point3d.x - left_lon) / X_SCALE); + const int y_offset = (int)(((double)pinfo.point3d.y - upper_lat) / Y_SCALE); /* Check Pixel Location */ if( x_offset < 0 || x_offset >= X_MAX || y_offset < 0 || y_offset >= Y_MAX ) { - mlog(ERROR, "Invalid pixel location for MERIT DEM at %lf, %lf: %d, %d\n", point.x, point.y, x_offset, y_offset); + mlog(ERROR, "Invalid pixel location for MERIT DEM at %lf, %lf: %d, %d\n", pinfo.point3d.x, pinfo.point3d.y, x_offset, y_offset); return SS_OUT_OF_BOUNDS_ERROR; } diff --git a/datasets/icesat2/package/MeritRaster.h b/datasets/icesat2/package/MeritRaster.h index ce45dbc2..5e9d4e30 100644 --- a/datasets/icesat2/package/MeritRaster.h +++ b/datasets/icesat2/package/MeritRaster.h @@ -77,7 +77,7 @@ class MeritRaster: public RasterObject *--------------------------------------------------------------------*/ MeritRaster (lua_State *L, RequestFields* rqst_parms, const char* key); - uint32_t getSamples (const MathLib::point_3d_t& point, int64_t gps, List& slist, void* param=NULL) final; + uint32_t getSamples (const point_info_t& pinfo, sample_list_t& slist, void* param=NULL) final; uint32_t getSubsets (const MathLib::extent_t& extent, int64_t gps, List& slist, void* param=NULL) final; private: diff --git a/datasets/pgc/package/PgcDemStripsRaster.cpp b/datasets/pgc/package/PgcDemStripsRaster.cpp index 6a1bdd36..015c57e7 100644 --- a/datasets/pgc/package/PgcDemStripsRaster.cpp +++ b/datasets/pgc/package/PgcDemStripsRaster.cpp @@ -180,10 +180,10 @@ void PgcDemStripsRaster::getIndexFile(const std::vector* points, s /* Get all geojson files for all points */ std::vector files; - for(const auto& p : *points) + for(const auto& pinfo : *points) { std::string newFile; - _getIndexFile(p.point.x, p.point.y, newFile); + _getIndexFile(pinfo.point3d.x, pinfo.point3d.y, newFile); if(!newFile.empty()) { files.push_back(newFile); diff --git a/datasets/pgc/selftests/arcticdem_reader_batch.lua b/datasets/pgc/selftests/arcticdem_reader_batch.lua new file mode 100644 index 00000000..e5191f8d --- /dev/null +++ b/datasets/pgc/selftests/arcticdem_reader_batch.lua @@ -0,0 +1,81 @@ +local runner = require("test_executive") +local console = require("console") +local asset = require("asset") +local csv = require("csv") +local json = require("json") + +-- console.monitor:config(core.LOG, core.DEBUG) +-- sys.setlvl(core.LOG, core.DEBUG) + +local assets = asset.loaddir() + +-- Unit Test -- + +local demTypes = {"arcticdem-mosaic", "arcticdem-strips"} + +-- Correct values test for different POIs + +local sigma = 1.0e-9 + +local lons = {-150, -40, 100, 150} +local lats = { 70, 70, 70, 75} +local heights = {0, 0, 0, 0} + +local expResultsMosaic = { 116.250000000, 2968.085937500, 475.742187500, 19.890625000} +local expResultsStrips = { 119.554687500, 2968.015625000, 474.156250000, 10.296875000} -- Only first strip samples for each lon/lat strip group + +local expSamplesCnt = {8, 8, 4, 14} + +for i = 1, #demTypes do + + local demType = demTypes[i]; + print(string.format("\n--------------------------------\nTest: %s Correct Values\n--------------------------------", demType)) + local dem = geo.raster(geo.parms({ asset = demType, algorithm = "NearestNeighbour", sort_by_index=true})) + local tbl, err = dem:batchsample(lons, lats, heights) + + if err ~= 0 then + print("FAILED to batchsample") + runner.check(false) + else + for j, pointSamples in ipairs(tbl) do + local lon, lat = lons[j], lats[j] + local sampleCnt = #pointSamples + print(string.format("Point: %d, (%.3f, %.3f) Sample Count: %d", j, lon, lat, sampleCnt)) + + if sampleCnt > 0 then + for k, sample in ipairs(pointSamples) do + local el = sample["value"] + local fname = sample["file"] + print(string.format(" Sample (%02d): %16.9fm %s", k, el, fname)) + + if k == 1 then -- Check all mosaics but only first strip for each POI + local expElevation + if demType == "arcticdem-mosaic" then + expElevation = expResultsMosaic[j] + else + expElevation = expResultsStrips[j] + end + runner.check(math.abs(el - expElevation) < sigma) + else + runner.check(el > 10) -- Check all other samples + end + end + else + print(string.format("Point: %d, (%.3f, %.3f) ======> FAILED to read samples", j, lon, lat)) + end + + local expectedSamplesCnt + if demType == "arcticdem-mosaic" then + expectedSamplesCnt = 1 + else + expectedSamplesCnt = expSamplesCnt[j] + end + runner.check(sampleCnt == expectedSamplesCnt) + end + end +end + +-- Report Results -- + +runner.report() + diff --git a/packages/arrow/ArrowSamplerImpl.cpp b/packages/arrow/ArrowSamplerImpl.cpp index 93b413ee..9bc3c475 100644 --- a/packages/arrow/ArrowSamplerImpl.cpp +++ b/packages/arrow/ArrowSamplerImpl.cpp @@ -323,7 +323,7 @@ void ArrowSamplerImpl::getXYPoints(std::vector& points) const double x = x_column->Value(i); const double y = y_column->Value(i); - points.emplace_back(point_info_t({{x, y, 0.0}, 0.0})); + points.emplace_back(point_info_t({{x, y, 0.0}, 0})); } mlog(DEBUG, "Read %zu points from file", points.size()); } @@ -352,7 +352,7 @@ void ArrowSamplerImpl::getGeoPoints(std::vector& points) const std::string wkb_data = binary_array->GetString(i); /* Get WKB data as string (binary data) */ const ArrowCommon::wkbpoint_t point = convertWKBToPoint(wkb_data); - points.emplace_back(point_info_t({{point.x, point.y, 0.0}, 0.0})); + points.emplace_back(point_info_t({{point.x, point.y, 0.0}, 0})); } mlog(INFO, "Read %zu geo points from file", points.size()); } diff --git a/packages/geo/GeoIndexedRaster.h b/packages/geo/GeoIndexedRaster.h index 8eacc121..65ed3ed4 100644 --- a/packages/geo/GeoIndexedRaster.h +++ b/packages/geo/GeoIndexedRaster.h @@ -200,7 +200,7 @@ class GeoIndexedRaster: public RasterObject static void init (void); static void deinit (void); - uint32_t getSamples (const MathLib::point_3d_t& point, int64_t gps_secs, List& slist, void* param=NULL) final; + uint32_t getSamples (const point_info_t& pinfo, sample_list_t& slist, void* param=NULL) final; uint32_t getSamples (const std::vector& points, List& sllist, void* param=NULL) final; uint32_t getSubsets (const MathLib::extent_t& extent, int64_t gps, List& slist, void* param=NULL) final; diff --git a/packages/geo/GeoIndexedRasterBatch.cpp b/packages/geo/GeoIndexedRasterBatch.cpp index a095c2c5..f2c5c836 100644 --- a/packages/geo/GeoIndexedRasterBatch.cpp +++ b/packages/geo/GeoIndexedRasterBatch.cpp @@ -446,7 +446,7 @@ void* GeoIndexedRaster::groupsFinderThread(void *param) } const point_info_t& pinfo = gf->points->at(i); - const OGRPoint ogrPoint(pinfo.point.x, pinfo.point.y, pinfo.point.z); + const OGRPoint ogrPoint(pinfo.point3d.x, pinfo.point3d.y, pinfo.point3d.z); /* Query the R-tree with the OGRPoint and get the result features */ std::vector foundFeatures; @@ -955,10 +955,10 @@ OGRGeometry* GeoIndexedRaster::getConvexHull(const std::vector* po mlog(INFO, "Creating convex hull from %zu points", points->size()); /* Collect all points into a geometry collection */ - for(const point_info_t& point_info : *points) + for(const point_info_t& pinfo : *points) { - const double lon = point_info.point.x; - const double lat = point_info.point.y; + const double lon = pinfo.point3d.x; + const double lat = pinfo.point3d.y; OGRPoint* point = new OGRPoint(lon, lat); geometryCollection.addGeometryDirectly(point); diff --git a/packages/geo/GeoIndexedRasterSerial.cpp b/packages/geo/GeoIndexedRasterSerial.cpp index 20f48ebd..b2598fba 100644 --- a/packages/geo/GeoIndexedRasterSerial.cpp +++ b/packages/geo/GeoIndexedRasterSerial.cpp @@ -78,7 +78,7 @@ GeoIndexedRaster::Reader::~Reader (void) /*---------------------------------------------------------------------------- * getSamples - serial sampling *----------------------------------------------------------------------------*/ -uint32_t GeoIndexedRaster::getSamples(const MathLib::point_3d_t& point, int64_t gps, List& slist, void* param) +uint32_t GeoIndexedRaster::getSamples(const point_info_t& pinfo, sample_list_t& slist, void* param) { static_cast(param); @@ -86,12 +86,12 @@ uint32_t GeoIndexedRaster::getSamples(const MathLib::point_3d_t& point, int64_t try { GroupOrdering groupList; - OGRPoint ogrPoint(point.x, point.y, point.z); + OGRPoint ogrPoint(pinfo.point3d.x, pinfo.point3d.y, pinfo.point3d.z); ssErrors = SS_NO_ERRORS; /* Sample Rasters */ - if(serialSample(&ogrPoint, gps, &groupList)) + if(serialSample(&ogrPoint, pinfo.gps, &groupList)) { /* Populate Return List of Samples (slist) */ const GroupOrdering::Iterator iter(groupList); diff --git a/packages/geo/GeoRaster.cpp b/packages/geo/GeoRaster.cpp index 2ff9193c..4472c291 100644 --- a/packages/geo/GeoRaster.cpp +++ b/packages/geo/GeoRaster.cpp @@ -79,9 +79,8 @@ GeoRaster::~GeoRaster(void) = default; /*---------------------------------------------------------------------------- * getSamples *----------------------------------------------------------------------------*/ -uint32_t GeoRaster::getSamples(const MathLib::point_3d_t& point, int64_t gps, List& slist, void* param) +uint32_t GeoRaster::getSamples(const point_info_t& pinfo, sample_list_t& slist, void* param) { - static_cast(gps); static_cast(param); lockSampling(); @@ -92,7 +91,7 @@ uint32_t GeoRaster::getSamples(const MathLib::point_3d_t& point, int64_t gps, Li for(const int bandNum : bands) { /* Must create OGRPoint for each bandNum, samplePOI projects it to raster CRS */ - OGRPoint ogr_point(point.x, point.y, point.z); + OGRPoint ogr_point(pinfo.point3d.x, pinfo.point3d.y, pinfo.point3d.z); RasterSample* sample = raster.samplePOI(&ogr_point, bandNum); if(sample) slist.add(sample); diff --git a/packages/geo/GeoRaster.h b/packages/geo/GeoRaster.h index 1b0f3a92..75ede7dc 100644 --- a/packages/geo/GeoRaster.h +++ b/packages/geo/GeoRaster.h @@ -64,7 +64,7 @@ class GeoRaster: public RasterObject GeoRaster (lua_State* L, RequestFields* rqst_parms, const char* key, const std::string& _fileName, double _gpsTime, int elevationBandNum=GdalRaster::NO_BAND, int flagsBandNum=GdalRaster::NO_BAND, GdalRaster::overrideCRS_t cb=NULL); ~GeoRaster (void) override; - uint32_t getSamples (const MathLib::point_3d_t& point, int64_t gps, List& slist, void* param=NULL) final; + uint32_t getSamples (const point_info_t& pinfo, sample_list_t& slist, void* param=NULL) final; uint32_t getSubsets (const MathLib::extent_t& extent, int64_t gps, List& slist, void* param=NULL) final; uint8_t* getPixels (uint32_t ulx, uint32_t uly, uint32_t xsize=0, uint32_t ysize=0, int bandNum=1, void* param=NULL) override; diff --git a/packages/geo/RasterObject.cpp b/packages/geo/RasterObject.cpp index 35bc758c..dfb98bd0 100644 --- a/packages/geo/RasterObject.cpp +++ b/packages/geo/RasterObject.cpp @@ -353,10 +353,124 @@ RasterObject::RasterObject(lua_State *L, RequestFields* rqst_parms, const char* samplingEnabled(true) { /* Add Lua Functions */ + LuaEngine::setAttrFunc(L, "batchsample", luaBatchSamples); LuaEngine::setAttrFunc(L, "sample", luaSamples); LuaEngine::setAttrFunc(L, "subset", luaSubsets); } +/*---------------------------------------------------------------------------- + * luaBatchSamples - :batchsample(lons, lats, heights, [gps]) --> in|out + *----------------------------------------------------------------------------*/ +int RasterObject::luaBatchSamples(lua_State *L) +{ + uint32_t err = SS_NO_ERRORS; + int num_ret = 1; + + RasterObject *lua_obj = NULL; + List sllist; + + try + { + /* Validate Input Arguments */ + if (!lua_istable(L, 2) || !lua_istable(L, 3) || !lua_istable(L, 4)) + { + throw RunTimeException(CRITICAL, RTE_ERROR, "Expected three arrays (tables) as arguments for lon, lat, and height"); + } + + /* Get Self */ + lua_obj = dynamic_cast(getLuaSelf(L, 1)); + + std::vector lonVec; + std::vector latVec; + std::vector heightVec; + + /* Helper Lambda to Read Lua Table into Vector */ + auto luaTableToVector = [&](int tableIndex, std::vector &vec) + { + lua_pushnil(L); // Start at the beginning of the table + while (lua_next(L, tableIndex) != 0) + { + if (lua_isnumber(L, -1)) + { + vec.push_back(lua_tonumber(L, -1)); + } + else + { + throw RunTimeException(CRITICAL, RTE_ERROR, "Non-numeric value found in table"); + } + lua_pop(L, 1); // Remove value, keep key for next iteration + } + }; + + /* Read Tables */ + luaTableToVector(2, lonVec); // lon table + luaTableToVector(3, latVec); // lat table + luaTableToVector(4, heightVec); // height table + + /* Validate Sizes */ + if (lonVec.size() != latVec.size() || lonVec.size() != heightVec.size()) + { + throw RunTimeException(CRITICAL, RTE_ERROR, "Input arrays (lon, lat, height) must have the same size"); + } + + const char* closest_time_str = getLuaString(L, 5, true, NULL); + + /* Get gps closest time (overrides params provided closest time) */ + int64_t gps = 0; + if(closest_time_str != NULL) + { + gps = TimeLib::str2gpstime(closest_time_str) / 1000; + } + + /* Create point_info_t vector from tables */ + std::vector points; + for (size_t i = 0; i < lonVec.size(); i++) + { + points.push_back({{lonVec[i], latVec[i], heightVec[i]}, gps}); + } + + mlog(DEBUG, "Batch sample received %lu points", points.size()); + + /* Get samples */ + err = lua_obj->getSamples(points, sllist, NULL); + if(err == SS_NO_ERRORS) + { + mlog(DEBUG, "Batch sample received %d samples lists", sllist.length()); + + /* Create parent table with space for `points.size()` entries */ + lua_createtable(L, points.size(), 0); + num_ret++; + + /* Process samples list for each point */ + for(size_t i = 0; i < points.size(); i++) + { + const sample_list_t* slist = sllist[i]; + + /* Create sample table for this point */ + lua_createtable(L, slist->length(), 0); + + /* Populate table with samples */ + setLuaSamples(L, *slist, lua_obj); + + /* Insert table into parent table */ + lua_rawseti(L, -2, i + 1); + } + } + else + { + throw RunTimeException(CRITICAL, RTE_ERROR, "Failed to get samples"); + } + } + catch (const RunTimeException &e) + { + mlog(e.level(), "Failed to read samples: %s", e.what()); + } + + /* Return Errors and Table of Samples */ + lua_pushinteger(L, err); + return num_ret; +} + /*---------------------------------------------------------------------------- * luaSamples - :sample(lon, lat, [height], [gps]) --> in|out *----------------------------------------------------------------------------*/ @@ -388,8 +502,8 @@ int RasterObject::luaSamples(lua_State *L) /* Get samples */ bool listvalid = true; - const MathLib::point_3d_t point = {lon, lat, height}; - err = lua_obj->getSamples(point, gps, slist, NULL); + const point_info_t pinfo = {{lon, lat, height}, gps}; + err = lua_obj->getSamples(pinfo, slist, NULL); if(err & SS_THREADS_LIMIT_ERROR) { @@ -410,36 +524,7 @@ int RasterObject::luaSamples(lua_State *L) /* Populate samples */ if(listvalid && !slist.empty()) { - for(int i = 0; i < slist.length(); i++) - { - const RasterSample* sample = slist[i]; - const char* fileName = lua_obj->fileDict.get(sample->fileId); - - lua_createtable(L, 0, 4); - LuaEngine::setAttrStr(L, "file", fileName); - - if(lua_obj->parms->zonal_stats) /* Include all zonal stats */ - { - LuaEngine::setAttrNum(L, "mad", sample->stats.mad); - LuaEngine::setAttrNum(L, "stdev", sample->stats.stdev); - LuaEngine::setAttrNum(L, "median", sample->stats.median); - LuaEngine::setAttrNum(L, "mean", sample->stats.mean); - LuaEngine::setAttrNum(L, "max", sample->stats.max); - LuaEngine::setAttrNum(L, "min", sample->stats.min); - LuaEngine::setAttrNum(L, "count", sample->stats.count); - } - - if(lua_obj->parms->flags_file) /* Include flags */ - { - LuaEngine::setAttrNum(L, "flags", sample->flags); - } - - LuaEngine::setAttrInt(L, "fileid", sample->fileId); - LuaEngine::setAttrNum(L, "time", sample->time); - LuaEngine::setAttrNum(L, "value", sample->value); - LuaEngine::setAttrStr(L, "band", sample->bandName.c_str()); - lua_rawseti(L, -2, i+1); - } + setLuaSamples(L, slist, lua_obj); } else mlog(DEBUG, "No samples read for (%.2lf, %.2lf)", lon, lat); } catch (const RunTimeException &e) @@ -600,6 +685,57 @@ void RasterObject::fileDictSetSamples(List* slist) } } + +/*---------------------------------------------------------------------------- + * setLuaSamples + *----------------------------------------------------------------------------*/ +void RasterObject::setLuaSamples(lua_State *L, const List &slist, RasterObject *lua_obj) +{ + if (!lua_obj || slist.empty()) + { + mlog(DEBUG, "No samples to populate"); + return; + } + + /* Populate samples */ + for (int i = 0; i < slist.length(); i++) + { + const RasterSample* sample = slist[i]; + const char* fileName = lua_obj->fileDict.get(sample->fileId); + + lua_createtable(L, 0, 4); // Create a new table for the sample + + /* Add basic attributes */ + LuaEngine::setAttrStr(L, "file", fileName); + LuaEngine::setAttrNum(L, "value", sample->value); + LuaEngine::setAttrNum(L, "time", sample->time); + LuaEngine::setAttrInt(L, "fileid", sample->fileId); + LuaEngine::setAttrStr(L, "band", sample->bandName.c_str()); + + /* Add zonal statistics if enabled */ + if (lua_obj->parms->zonal_stats) + { + LuaEngine::setAttrNum(L, "mad", sample->stats.mad); + LuaEngine::setAttrNum(L, "stdev", sample->stats.stdev); + LuaEngine::setAttrNum(L, "median", sample->stats.median); + LuaEngine::setAttrNum(L, "mean", sample->stats.mean); + LuaEngine::setAttrNum(L, "max", sample->stats.max); + LuaEngine::setAttrNum(L, "min", sample->stats.min); + LuaEngine::setAttrNum(L, "count", sample->stats.count); + } + + /* Add flags if enabled */ + if (lua_obj->parms->flags_file) + { + LuaEngine::setAttrNum(L, "flags", sample->flags); + } + + /* Add sample table to parent Lua table, insert at index i+1 */ + lua_rawseti(L, -2, i + 1); + } +} + + /****************************************************************************** * PRIVATE METHODS ******************************************************************************/ @@ -707,13 +843,10 @@ uint32_t RasterObject::readSamples(RasterObject* robj, const range_t& range, break; } - const RasterObject::point_info_t& pinfo = points[i]; - const MathLib::point_3d_t& point = pinfo.point; - const int64_t gps = robj->usePOItime() ? pinfo.gps : 0.0; - sample_list_t* slist = new sample_list_t; + const RasterObject::point_info_t& pinfo = points[i]; + const uint32_t err = robj->getSamples(pinfo, *slist, NULL); bool listvalid = true; - const uint32_t err = robj->getSamples(point, gps, *slist, NULL); /* Acumulate errors from all getSamples calls */ ssErrors |= err; diff --git a/packages/geo/RasterObject.h b/packages/geo/RasterObject.h index 98512c5a..d97cc034 100644 --- a/packages/geo/RasterObject.h +++ b/packages/geo/RasterObject.h @@ -73,8 +73,8 @@ class RasterObject: public LuaObject typedef struct { - MathLib::point_3d_t point; - double gps; + MathLib::point_3d_t point3d; + int64_t gps; } point_info_t; typedef struct @@ -104,7 +104,7 @@ class RasterObject: public LuaObject static void deinit (void); static int luaCreate (lua_State* L); static bool registerRaster (const char* _name, factory_f create); - virtual uint32_t getSamples (const MathLib::point_3d_t& point, int64_t gps, List& slist, void* param=NULL) = 0; + virtual uint32_t getSamples (const point_info_t& pinfo, sample_list_t& slist, void* param=NULL) = 0; virtual uint32_t getSamples (const std::vector& points, List& sllist, void* param=NULL); virtual uint32_t getSubsets (const MathLib::extent_t& extent, int64_t gps, List& slist, void* param=NULL) = 0; virtual uint8_t* getPixels (uint32_t ulx, uint32_t uly, uint32_t xsize=0, uint32_t ysize=0, int bandNum=1, void* param=NULL); @@ -173,6 +173,7 @@ class RasterObject: public LuaObject RasterObject (lua_State* L, RequestFields* rqst_parms, const char* key); + static int luaBatchSamples (lua_State* L); static int luaSamples (lua_State* L); static int luaSubsets (lua_State* L); static int luaPixels (lua_State *L); @@ -185,6 +186,8 @@ class RasterObject: public LuaObject void fileDictSetSamples(List* slist); + static void setLuaSamples(lua_State* L, const List& slist, RasterObject* lua_obj); + /*-------------------------------------------------------------------- * Data diff --git a/packages/geo/RasterSampler.cpp b/packages/geo/RasterSampler.cpp index effca4f7..5f20a60a 100644 --- a/packages/geo/RasterSampler.cpp +++ b/packages/geo/RasterSampler.cpp @@ -261,7 +261,7 @@ bool RasterSampler::processRecord (RecordObject* record, okey_t key, recVec_t* r lat_field.offset += (batchRecordSizeBytes * 8); /* Get Time */ - long gps = 0; + int64_t gps = 0; if(time_field.type != RecordObject::INVALID_FIELD) { const long time_val = record->getValueInteger(time_field); @@ -279,8 +279,8 @@ bool RasterSampler::processRecord (RecordObject* record, okey_t key, recVec_t* r /* Sample Raster */ List slist; - const MathLib::point_3d_t point = {lon_val, lat_val, height_val}; - const uint32_t err = raster->getSamples(point, gps, slist); + const RasterObject::point_info_t pinfo = {{lon_val, lat_val, height_val}, gps}; + const uint32_t err = raster->getSamples(pinfo, slist); const int num_samples = slist.length(); /* Generate Error Messages */ diff --git a/packages/geo/UT_RasterSample.cpp b/packages/geo/UT_RasterSample.cpp index 89874282..4b5eb4cd 100644 --- a/packages/geo/UT_RasterSample.cpp +++ b/packages/geo/UT_RasterSample.cpp @@ -111,13 +111,8 @@ bool UT_RasterSample::ReadPointsFile(std::vector& po while (fscanf(file, "%lf %lf", &lon, &lat) == 2) { - RasterObject::point_info_t pointInfo; - pointInfo.point.x = lon; - pointInfo.point.y = lat; - pointInfo.point.z = 0.0; - pointInfo.gps = 0.0; - - points.push_back(pointInfo); + const RasterObject::point_info_t pinfo = {{lon, lat, 0.0}, 0}; + points.push_back(pinfo); } fclose(file); @@ -250,13 +245,8 @@ int UT_RasterSample::luaSampleTest(lua_State* L) /* Create points to sample */ for(long i = 0; i < pointsCnt; i++) { - RasterObject::point_info_t point; - point.point.x = lon; - point.point.y = lat; - point.point.z = 0.0; - point.gps = 0.0; - - points2sample.push_back(point); + const RasterObject::point_info_t pinfo = { {lon, lat, 0.0}, 0 }; + points2sample.push_back(pinfo); lon += lonIncr; lat += latIncr; @@ -264,8 +254,8 @@ int UT_RasterSample::luaSampleTest(lua_State* L) } print2term("Points to sample: %zu\n", points2sample.size()); - print2term("Starting at (%.4lf, %.4lf), incrementing by (%+.4lf, %+.4lf)\n", points2sample[0].point.x, points2sample[0].point.y, lonIncr, latIncr); - print2term("Last point: (%.4lf, %.4lf)\n", points2sample[points2sample.size() - 1].point.x, points2sample[points2sample.size() - 1].point.y); + print2term("Starting at (%.4lf, %.4lf), incrementing by (%+.4lf, %+.4lf)\n", points2sample[0].point3d.x, points2sample[0].point3d.y, lonIncr, latIncr); + print2term("Last point: (%.4lf, %.4lf)\n", points2sample[points2sample.size() - 1].point3d.x, points2sample[points2sample.size() - 1].point3d.y); /* Get samples using serial method */ print2term("Getting samples for %zu points using serial method\n", points2sample.size()); @@ -274,7 +264,7 @@ int UT_RasterSample::luaSampleTest(lua_State* L) for(uint32_t i = 0; i < points2sample.size(); i++) { RasterObject::sample_list_t* slist = new RasterObject::sample_list_t(); - lua_obj->raster->getSamples(points2sample[i].point, 0, *slist, NULL); + lua_obj->raster->getSamples(points2sample[i], *slist, NULL); /* Add to list */ serial_sllist.add(slist); diff --git a/packages/geo/UT_RasterSubset.cpp b/packages/geo/UT_RasterSubset.cpp index 1daa5137..a1789289 100644 --- a/packages/geo/UT_RasterSubset.cpp +++ b/packages/geo/UT_RasterSubset.cpp @@ -132,8 +132,8 @@ int UT_RasterSubset::luaSubsetTest(lua_State* L) const double height = 0.0; print2term("Point: %.2lf, %.2lf, %.2lf\n", lon, lat, height); - const MathLib::point_3d_t point = {lon, lat, height}; - errors += lua_obj->raster->getSamples(point, 0, samplesList, NULL); + const RasterObject::point_info_t pinfo = {{lon, lat, height}, 0}; + errors += lua_obj->raster->getSamples(pinfo, samplesList, NULL); for(int i = 0; i < samplesList.length(); i++) { const RasterSample* sample = samplesList[i]; @@ -150,8 +150,8 @@ int UT_RasterSubset::luaSubsetTest(lua_State* L) /* Get samples */ samplesList.clear(); - const MathLib::point_3d_t _point = {lon, lat, height}; - errors += srobj->getSamples(_point, 0, samplesList, NULL); + const RasterObject::point_info_t _pinfo = { {lon, lat, height}, 0 }; + errors += srobj->getSamples(_pinfo, samplesList, NULL); for(int j = 0; j < samplesList.length(); j++) { diff --git a/scripts/selftests/test_runner.lua b/scripts/selftests/test_runner.lua index ce413e4c..104b4e99 100644 --- a/scripts/selftests/test_runner.lua +++ b/scripts/selftests/test_runner.lua @@ -84,6 +84,7 @@ if __pgc__ and incloud then local pgc_td = td .. "../../datasets/pgc/selftests/" runner.script(pgc_td .. "plugin_unittest.lua") runner.script(pgc_td .. "arcticdem_reader.lua") + runner.script(pgc_td .. "arcticdem_reader_batch.lua") runner.script(pgc_td .. "temporal_filter_test.lua") runner.script(pgc_td .. "url_filter_test.lua") runner.script(pgc_td .. "zonal_stats_test.lua")