From 7fe4981aa98658a03ae1d3579337e6506e95ca52 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Wed, 21 Aug 2024 17:09:16 -0700 Subject: [PATCH 01/21] added README.md --- isis/src/base/apps/pixel2map/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 isis/src/base/apps/pixel2map/README.md diff --git a/isis/src/base/apps/pixel2map/README.md b/isis/src/base/apps/pixel2map/README.md new file mode 100644 index 0000000000..79c3c83163 --- /dev/null +++ b/isis/src/base/apps/pixel2map/README.md @@ -0,0 +1 @@ +pixel2map as of July 2023 From 68fbd2d911d7f9e14c9392f469833a13a93a095d Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Wed, 21 Aug 2024 17:11:54 -0700 Subject: [PATCH 02/21] added pixel2map '23 mods --- isis/src/base/apps/pixel2map/main.cpp | 146 ++++++++++++++++++++- isis/src/base/apps/pixel2map/pixel2map.xml | 33 ++++- 2 files changed, 173 insertions(+), 6 deletions(-) diff --git a/isis/src/base/apps/pixel2map/main.cpp b/isis/src/base/apps/pixel2map/main.cpp index 825a383f15..14c0d6f6a8 100755 --- a/isis/src/base/apps/pixel2map/main.cpp +++ b/isis/src/base/apps/pixel2map/main.cpp @@ -1,7 +1,6 @@ #define GUIHELPERS #include "Isis.h" - #include #include #include @@ -18,16 +17,21 @@ #include "ProcessRubberSheet.h" #include "ProjectionFactory.h" #include "Pvl.h" + #include "PvlGroup.h" #include "Target.h" #include "pixel2map.h" +#include "geos/geom/Geometry.h" +#include "geos/io/WKTWriter.h" + using namespace std; using namespace Isis; void PrintMap(); void rasterizePixel(Isis::Buffer &in); +void vectorizePixel(Isis::Buffer &in); map GuiHelpers() { map helper; @@ -39,6 +43,18 @@ map GuiHelpers() { ProcessGroundPolygons g_processGroundPolygons; Camera *g_incam; int g_numIFOVs = 0; +int g_vectorOut = 0; // to be set bool in future + +int csamples; +int clines; + +QString vectOut; +QString outvect; + +ofstream fout_csv; +QString ogc_SRS; + + void IsisMain() { @@ -64,6 +80,7 @@ void IsisMain() { } } + if (ui.GetString("FOVRANGE") == "INSTANTANEOUS") { g_numIFOVs = 1; } @@ -78,6 +95,8 @@ void IsisMain() { double maxlon = 0; PvlGroup camGrp; QString lastBandString; + + // Get the combined lat/lon range for all input cubes int bands = 1; @@ -93,6 +112,14 @@ void IsisMain() { icube.open( list[i].toString() ); bands = icube.bandCount(); g_incam = icube.camera(); + + csamples = g_incam->Samples(); + clines = g_incam->Lines(); + + + Spice spi(icube); + ogc_SRS = "IAU:" + Isis::toString(spi.target()->naifBodyCode()) + "00"; + //cout << ogc_SRS << endl; // Make sure it is not the sky if (g_incam->target()->isSky()) { @@ -298,6 +325,7 @@ void IsisMain() { Pvl pvl; pvl.addGroup(userGrp); + // If there is only one input cube, we need to attach an AlphaCube to the outputs. if (list.size() == 1) { Cube parent(list[0].toString()); @@ -315,7 +343,14 @@ void IsisMain() { } } - g_processGroundPolygons.SetStatCubes("TO", pvl, bands); + if ( ui.WasEntered("TO") ) { + g_processGroundPolygons.SetStatCubes("TO", pvl, bands); + } + + if ( ui.WasEntered("TOVECT") ) { + g_vectorOut = 1; + outvect = ui.GetFileName("TOVECT"); + } bool useCenter = true; if (ui.GetString("METHOD") == "CENTER") { @@ -327,6 +362,7 @@ void IsisMain() { g_processGroundPolygons.SetIntersectAlgorithm(useCenter); + for (int f = 0; f < list.size(); f++) { Cube cube(list[f].toString(), "r"); @@ -338,13 +374,55 @@ void IsisMain() { CubeAttributeInput atts0(list[f]); Cube *icube = processBrick.SetInputCube(list[f].toString(), atts0, 0); g_incam = icube->camera(); - - processBrick.StartProcess(rasterizePixel); - processBrick.EndProcess(); + + if ( ui.WasEntered("TO") ) { + processBrick.StartProcess(rasterizePixel); + processBrick.EndProcess(); + } + if ( ui.WasEntered("TOVECT") ) { + + ofstream fout_vrt; + + QString outFileNameVRT = FileName( outvect.toLatin1().data() ).removeExtension().addExtension("vrt").expanded(); + QString layer_name = FileName( outvect.toLatin1().data() ).baseName(); + QString csv_fname = FileName( outvect.toLatin1().data() ).name(); + + fout_vrt.open( outFileNameVRT.toLatin1().data() ); + + fout_vrt << "" << endl; + fout_vrt << " " << endl; + fout_vrt << " " << csv_fname.toLatin1().data() << "" << endl; + fout_vrt << " wkbPolygon" << endl; + fout_vrt << " "<< ogc_SRS.toLatin1().data() << "" << endl; + fout_vrt << " "<< endl; + fout_vrt << " "<< endl; + fout_vrt << " " << endl; + fout_vrt << " " << endl; + fout_vrt << " " << endl; + fout_vrt << "" << endl; + + fout_vrt.close(); + + + + // write the header + fout_csv.open( outvect.toLatin1().data() ); + fout_csv << "sampleno" << "," << "lineno" << "," << "pixelvalue" << "," << "geom" << endl; + fout_csv.close(); + // open in append mode + fout_csv.open( outvect.toLatin1().data(), std::ios_base::app ); + + processBrick.StartProcess(vectorizePixel); + processBrick.EndProcess(); + fout_csv.close(); + } // IF TOVECT + } + if ( ui.WasEntered("TO") ) { // When there is only one input cube, we want to propagate IsisCube labels to output cubes if (list.size() == 1) { + // g_incam->SetImage(csamples,clines); // Note that polygons and original labels are not propagated g_processGroundPolygons.PropagateLabels(list[0].toString()); // Tell Process which tables we want to propagate @@ -352,6 +430,7 @@ void IsisMain() { tablesToPropagate << "InstrumentPointing" << "InstrumentPosition" << "BodyRotation" << "SunPosition"; g_processGroundPolygons.PropagateTables(list[0].toString(), tablesToPropagate); + } } g_processGroundPolygons.EndProcess(); @@ -419,3 +498,60 @@ void rasterizePixel(Isis::Buffer &in) { } } } + +/** + * This method uses the ProcessGroundPolygons object to vectorize each + * pixel in the given buffer. + * + * @param in Input ProcessByBrick buffer. + */ +void vectorizePixel(Isis::Buffer &in) { + + std::vectorlat, lon; + std::vectordns; + geos::geom::Geometry* GndPixel; + + + // Setup the WKT writer + geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); + + + for (int i = 0; i < in.size(); i++) { + dns.push_back(in[i]); + } + + int l = in.Line(); + int s = in.Sample(); + + // DO: This needs to be done for each band for band dependent instruments + // Note: This can slow this down a lot + + // Get the IFOVs in lat/lon space + PixelFOV fov; + QList< QList< QPointF > > fovVertices = fov.latLonVertices(*g_incam, l, s, g_numIFOVs); + + + // loop through each ifov list + for (int ifov = 0; ifov < fovVertices.size(); ifov++) { + // we need at least 3 vertices for a polygon + if (fovVertices[ifov].size() > 3) { + // Get lat/lon for each vertex of the ifov + for (int point = 0; point < fovVertices[ifov].size(); point++) { + lat.push_back(fovVertices[ifov][point].x()); + lon.push_back(fovVertices[ifov][point].y()); + } + // rasterize this ifov and clear vectors for next ifov + // add Vectorize method + GndPixel = g_processGroundPolygons.Vectorize(lat, lon, dns); + //cout << dns[0] << endl; + if ( dns[0] != Isis::Null ) + { fout_csv << s << "," << l << "," << dns[0] << ",\"" << wkt->write(GndPixel) << "\"" << endl;} + + lat.clear(); + lon.clear(); + } + } +} + + + diff --git a/isis/src/base/apps/pixel2map/pixel2map.xml b/isis/src/base/apps/pixel2map/pixel2map.xml index 0cce8b7b57..e87a8f4e7a 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.xml +++ b/isis/src/base/apps/pixel2map/pixel2map.xml @@ -323,6 +323,9 @@ Updated documentation and added examples. Fixes #4537. + + Added Vector output + @@ -418,10 +421,13 @@ + + cube output - real + real + Null Newly mapped cube @@ -431,10 +437,35 @@ filename with '-count-' appended. The DN values in this output cube indicate how many input pixels were included in the average calculation to create the output pixel. + + TOVECT + *.cub + + + filename + output + Null + + Geospatial VRT Vector File + + + The output file will be a VRT File and a comma-delimited file. This file format + can easily be imported into Open Gis Consortium (OGC) compatible Geospatial tools. + + + TO + + + *.csv + + + + + From a7dddec786912d08a681f946982175c0ae6faf8f Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Wed, 21 Aug 2024 17:45:18 -0700 Subject: [PATCH 03/21] updated the 2023 code to the current dev branch --- .../ProcessGroundPolygons.cpp | 111 +++++++++++++++++- .../ProcessGroundPolygons.h | 4 + 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp index 4f5a1907f6..34fad07ed3 100644 --- a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp +++ b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp @@ -9,7 +9,9 @@ find files of those names at the top level of this repository. **/ #include #include "geos/geom/CoordinateSequence.h" +#include "geos/geom/CoordinateArraySequence.h" #include "geos/geom/LineString.h" +#include "geos/io/WKTWriter.h" #include "Application.h" #include "BoxcarCachingAlgorithm.h" @@ -52,14 +54,14 @@ namespace Isis { if (crosses) { // Make a polygon from the lat/lon vectors and split it on 360 - geos::geom::CoordinateSequence pts; + geos::geom::CoordinateArraySequence *pts = new geos::geom::CoordinateArraySequence(); for (unsigned int i = 0; i < lat.size(); i++) { - pts.add(geos::geom::Coordinate(lon[i], lat[i])); + pts->add(geos::geom::Coordinate(lon[i], lat[i])); } - pts.add(geos::geom::Coordinate(lon[0], lat[0])); + pts->add(geos::geom::Coordinate(lon[0], lat[0])); geos::geom::Polygon *crossingPoly = Isis::globalFactory->createPolygon( - globalFactory->createLinearRing(pts)).release(); + globalFactory->createLinearRing(pts), NULL); geos::geom::MultiPolygon *splitPoly = NULL; try { @@ -104,6 +106,105 @@ namespace Isis { } + + +/** + * This method gets called from the application with the lat/lon + * vertices of a polygon along with a vector of values. + * + * it returns a geos::geom::Geometry* WKT representation of the + * geometry + * + * @param lat + * @param lon + * @param values + */ +geos::geom::Geometry* ProcessGroundPolygons::Vectorize(std::vector &lat, + std::vector &lon, + std::vector &values) + { + + + // Decide if we need to split the poly on the 360 boundry + // Yes, we can do this better. The lat and lon vectors should be passed in as polygons, but + // for now this is reusing older code. + bool crosses = false; + for (unsigned int i = 0; i < lon.size() - 1; i++) { + if (fabs(lon[i] - lon[i+1]) > 180.0) { + crosses = true; + break; + } + } + + + if (crosses) { + // Make a polygon from the lat/lon vectors and split it on 360 + geos::geom::CoordinateArraySequence *pts = new geos::geom::CoordinateArraySequence(); + for (unsigned int i = 0; i < lat.size(); i++) { + pts->add(geos::geom::Coordinate(lon[i], lat[i])); + } + pts->add(geos::geom::Coordinate(lon[0], lat[0])); + + geos::geom::Polygon *crossingPoly = Isis::globalFactory->createPolygon( + globalFactory->createLinearRing(pts), NULL); + + geos::geom::MultiPolygon *splitPoly = NULL; + try { + splitPoly = PolygonTools::SplitPolygonOn360(crossingPoly); + } + // Ignore any pixel footprints that could not be split. This should only be pixels + // that contain the pole. + catch (IException &) { + // See leading comment + } + + + delete crossingPoly; + + if (splitPoly != NULL) { + // Process the polygons in the split multipolygon as if we were still using the lat/lon vectors + for (unsigned int g = 0; g < splitPoly->getNumGeometries(); ++g) { + const geos::geom::Polygon *poly = + dynamic_cast(splitPoly->getGeometryN(g)); + + geos::geom::CoordinateSequence *llcoords = + poly->getExteriorRing()->getCoordinates().release(); + + // Move each coordinate in the exterior ring of this lat/lon polygon to vectors + // Ignore any holes in the polygon + std::vector tlat; + std::vector tlon; + for (unsigned int cord = 0; cord < llcoords->getSize() - 1; ++cord) { + tlon.push_back(llcoords->getAt(cord).x); + tlat.push_back(llcoords->getAt(cord).y); + } + + + Convert(tlat, tlon); + //ProcessPolygons::Rasterize(p_samples, p_lines, values); + } + return splitPoly; + delete splitPoly; + } + } + else { // if does not crosses + + // Make a polygon from the lat/lon vectors and split it on 360 + geos::geom::CoordinateArraySequence *pts = new geos::geom::CoordinateArraySequence(); + for (unsigned int i = 0; i < lat.size(); i++) { + pts->add(geos::geom::Coordinate(lon[i], lat[i])); + } + pts->add(geos::geom::Coordinate(lon[0], lat[0])); + + geos::geom::Polygon *crossingPoly = Isis::globalFactory->createPolygon( + globalFactory->createLinearRing(pts), NULL); + + return crossingPoly; + //ProcessPolygons::Rasterize(p_samples, p_lines, values); + } + +} + /** * This method gets called from the application with the lat/lon * verticies of a polygon along with the band number and the @@ -234,7 +335,7 @@ namespace Isis { /** * This is a method that is called directly from the * application. Using the "TO" parameter we also create a - * count cube name. The we call the overloaded SetStatCubes + * count cube name. Then we call the overloaded SetStatCubes * method above. * * @param parameter diff --git a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h index 3ccb449308..085c0e9327 100644 --- a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h +++ b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h @@ -73,6 +73,10 @@ namespace Isis { void Rasterize(std::vector &lat, std::vector &lon, int &band, double &value); + + geos::geom::Geometry* Vectorize (std::vector &lat, + std::vector &lon, + std::vector &values); void EndProcess(); void Finalize(); From fb58d902be71c0204c4834c2ae163200cb0a6d6c Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Wed, 21 Aug 2024 18:02:51 -0700 Subject: [PATCH 04/21] Started the refactoring --- isis/src/base/apps/pixel2map/pixel2map.cpp | 506 +++++++++++++++++++++ 1 file changed, 506 insertions(+) create mode 100644 isis/src/base/apps/pixel2map/pixel2map.cpp diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp new file mode 100644 index 0000000000..7c2df7655d --- /dev/null +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -0,0 +1,506 @@ +#include + +#include "pixel2map.h" + +using namespace std; + +namespace Isis { + + + g_incam = NULL; + + // Get the map projection file provided by the user + UserInterface &ui = Application::GetUserInterface(); + Pvl userMap; + userMap.read(ui.GetFileName("MAP")); + PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); + + FileList list; + if (ui.GetString("FROMTYPE") == "FROM") { + // GetAsString will capture the entire string, including attributes + list.push_back(FileName(ui.GetAsString("FROM"))); + } + else { + try { + list.read(ui.GetFileName("FROMLIST")); + } + catch (IException &e) { + throw IException(e); + } + } + + + if (ui.GetString("FOVRANGE") == "INSTANTANEOUS") { + g_numIFOVs = 1; + } + else { + g_numIFOVs = ui.GetInteger("NUMIFOV"); + } + + double newminlat, newmaxlat, newminlon, newmaxlon; + double minlat = 90; + double maxlat = -90; + double minlon = 360.0; + double maxlon = 0; + PvlGroup camGrp; + QString lastBandString; + + + + // Get the combined lat/lon range for all input cubes + int bands = 1; + for (int i = 0; i < list.size(); i++) { + + // Open the input cube and get the camera + CubeAttributeInput atts0(list[i]); + Cube icube; + if(atts0.bands().size() != 0) { + vector lame = atts0.bands(); + icube.setVirtualBands(lame); + } + icube.open( list[i].toString() ); + bands = icube.bandCount(); + g_incam = icube.camera(); + + csamples = g_incam->Samples(); + clines = g_incam->Lines(); + + + Spice spi(icube); + ogc_SRS = "IAU:" + Isis::toString(spi.target()->naifBodyCode()) + "00"; + //cout << ogc_SRS << endl; + + // Make sure it is not the sky + if (g_incam->target()->isSky()) { + QString msg = "The image [" + list[i].toString() + + "] is targeting the sky, use skymap instead."; + throw IException(IException::User, msg, _FILEINFO_); + } + + // Make sure all the bands for all the files match + if (i >= 1 && atts0.bandsString() != lastBandString) { + QString msg = "The Band numbers for all the files do not match."; + throw IException(IException::User, msg, _FILEINFO_); + } + else { + lastBandString = atts0.bandsString(); + } + + // Get the mapping group + Pvl camMap; + g_incam->BasicMapping(camMap); + camGrp = camMap.findGroup("Mapping"); + + g_incam->GroundRange(newminlat, newmaxlat, newminlon, newmaxlon, userMap); + //set min lat/lon + if (newminlat < minlat) { + minlat = newminlat; + } + if (newminlon < minlon) { + minlon = newminlon; + } + + //set max lat/lon + if (newmaxlat > maxlat) { + maxlat = newmaxlat; + } + if (newmaxlon > maxlon) { + maxlon = newmaxlon; + } + + // The camera will be deleted when the Cube is deleted so NULL g_incam + g_incam = NULL; + } //end for list.size + + camGrp.addKeyword(PvlKeyword("MinimumLatitude", toString(minlat)), Pvl::Replace); + camGrp.addKeyword(PvlKeyword("MaximumLatitude", toString(maxlat)), Pvl::Replace); + camGrp.addKeyword(PvlKeyword("MinimumLongitude", toString(minlon)), Pvl::Replace); + camGrp.addKeyword(PvlKeyword("MaximumLongitude", toString(maxlon)), Pvl::Replace); + + + // We want to delete the keywords we just added if the user wants the range + // out of the mapfile, otherwise they will replace any keywords not in the + // mapfile + if (ui.GetString("DEFAULTRANGE") == "MAP") { + camGrp.deleteKeyword("MinimumLatitude"); + camGrp.deleteKeyword("MaximumLatitude"); + camGrp.deleteKeyword("MinimumLongitude"); + camGrp.deleteKeyword("MaximumLongitude"); + } + + // Otherwise, remove the keywords from the map file so the camera keywords + // will be propogated correctly + else { + while (userGrp.hasKeyword("MinimumLatitude")) { + userGrp.deleteKeyword("MinimumLatitude"); + } + while (userGrp.hasKeyword("MinimumLongitude")) { + userGrp.deleteKeyword("MinimumLongitude"); + } + while (userGrp.hasKeyword("MaximumLatitude")) { + userGrp.deleteKeyword("MaximumLatitude"); + } + while (userGrp.hasKeyword("MaximumLongitude")) { + userGrp.deleteKeyword("MaximumLongitude"); + } + } + + // If the user decided to enter a ground range then override + if (ui.WasEntered("MINLON")) { + userGrp.addKeyword(PvlKeyword("MinimumLongitude", + toString(ui.GetDouble("MINLON"))), Pvl::Replace); + } + + if (ui.WasEntered("MAXLON")) { + userGrp.addKeyword(PvlKeyword("MaximumLongitude", + toString(ui.GetDouble("MAXLON"))), Pvl::Replace); + } + + if (ui.WasEntered("MINLAT")) { + userGrp.addKeyword(PvlKeyword("MinimumLatitude", + toString(ui.GetDouble("MINLAT"))), Pvl::Replace); + } + + if (ui.WasEntered("MAXLAT")) { + userGrp.addKeyword(PvlKeyword("MaximumLatitude", + toString(ui.GetDouble("MAXLAT"))), Pvl::Replace); + } + + // If they want the res. from the mapfile, delete it from the camera so + // nothing gets overriden + if (ui.GetString("PIXRES") == "MAP") { + camGrp.deleteKeyword("PixelResolution"); + } + // Otherwise, delete any resolution keywords from the mapfile so the camera + // info is propogated over + else if (ui.GetString("PIXRES") == "CAMERA") { + if (userGrp.hasKeyword("Scale")) { + userGrp.deleteKeyword("Scale"); + } + if (userGrp.hasKeyword("PixelResolution")) { + userGrp.deleteKeyword("PixelResolution"); + } + } + + // Copy any defaults that are not in the user map from the camera map file + for (int k = 0; k < camGrp.keywords(); k++) { + if (!userGrp.hasKeyword(camGrp[k].name())) { + userGrp += camGrp[k]; + } + } + + // If the user decided to enter a resolution then override + if (ui.GetString("PIXRES") == "MPP") { + userGrp.addKeyword(PvlKeyword("PixelResolution", + toString(ui.GetDouble("RESOLUTION"))), + Pvl::Replace); + if (userGrp.hasKeyword("Scale")) { + userGrp.deleteKeyword("Scale"); + } + } + else if (ui.GetString("PIXRES") == "PPD") { + userGrp.addKeyword(PvlKeyword("Scale", + toString(ui.GetDouble("RESOLUTION"))), + Pvl::Replace); + if (userGrp.hasKeyword("PixelResolution")) { + userGrp.deleteKeyword("PixelResolution"); + } + } + + // See if the user want us to handle the longitude seam + if (ui.GetString("DEFAULTRANGE") == "CAMERA" || ui.GetString("DEFAULTRANGE") == "MINIMIZE") { + + // Open the last cube and use its camera + CubeAttributeInput atts0( list.back() ); + Cube icube; + if(atts0.bands().size() != 0) { + vector lame = atts0.bands(); + icube.setVirtualBands(lame); + } + icube.open( list.back().toString() ); + g_incam = icube.camera(); + + if (g_incam->IntersectsLongitudeDomain(userMap)) { + if (ui.GetString("LONSEAM") == "AUTO") { + if ((int) userGrp["LongitudeDomain"] == 360) { + userGrp.addKeyword(PvlKeyword("LongitudeDomain", toString(180)), + Pvl::Replace); + if (g_incam->IntersectsLongitudeDomain(userMap)) { + // Its looks like a global image so switch back to the + // users preference + userGrp.addKeyword(PvlKeyword("LongitudeDomain", toString(360)), + Pvl::Replace); + } + } + else { + userGrp.addKeyword(PvlKeyword("LongitudeDomain", toString(360)), + Pvl::Replace); + if (g_incam->IntersectsLongitudeDomain(userMap)) { + // Its looks like a global image so switch back to the + // users preference + userGrp.addKeyword(PvlKeyword("LongitudeDomain", toString(180)), + Pvl::Replace); + } + } + // Make the target info match the new longitude domain + double minlat, maxlat, minlon, maxlon; + g_incam->GroundRange(minlat, maxlat, minlon, maxlon, userMap); + if (!ui.WasEntered("MINLAT")) { + userGrp.addKeyword(PvlKeyword("MinimumLatitude", toString(minlat)), Pvl::Replace); + } + if (!ui.WasEntered("MAXLAT")) { + userGrp.addKeyword(PvlKeyword("MaximumLatitude", toString(maxlat)), Pvl::Replace); + } + if (!ui.WasEntered("MINLON")) { + userGrp.addKeyword(PvlKeyword("MinimumLongitude", toString(minlon)), Pvl::Replace); + } + if (!ui.WasEntered("MAXLON")) { + userGrp.addKeyword(PvlKeyword("MaximumLongitude", toString(maxlon)), Pvl::Replace); + } + } + + else if (ui.GetString("LONSEAM") == "ERROR") { + QString msg = "The image [" + ui.GetCubeName("FROM") + "] crosses the " + + "longitude seam"; + throw IException(IException::User, msg, _FILEINFO_); + } + } + + // The camera will be deleted when the Cube is deleted so NULL g_incam + g_incam = NULL; + } + + + Pvl pvl; + pvl.addGroup(userGrp); + + + // If there is only one input cube, we need to attach an AlphaCube to the outputs. + if (list.size() == 1) { + Cube parent(list[0].toString()); + if (!parent.hasGroup("AlphaCube")) { + PvlGroup alpha("AlphaCube"); + alpha += PvlKeyword("AlphaSamples", toString(parent.sampleCount())); + alpha += PvlKeyword("AlphaLines", toString(parent.lineCount())); + alpha += PvlKeyword("AlphaStartingSample", toString(0.5)); + alpha += PvlKeyword("AlphaStartingLine", toString(0.5)); + alpha += PvlKeyword("AlphaEndingSample", toString(parent.sampleCount() + 0.5)); + alpha += PvlKeyword("AlphaEndingLine", toString(parent.lineCount() + 0.5)); + alpha += PvlKeyword("BetaSamples", toString(parent.sampleCount())); + alpha += PvlKeyword("BetaLines", toString(parent.lineCount())); + pvl.addGroup(alpha); + } + } + + if ( ui.WasEntered("TO") ) { + g_processGroundPolygons.SetStatCubes("TO", pvl, bands); + } + + if ( ui.WasEntered("TOVECT") ) { + g_vectorOut = 1; + outvect = ui.GetFileName("TOVECT"); + } + + bool useCenter = true; + if (ui.GetString("METHOD") == "CENTER") { + useCenter = true; + } + else if (ui.GetString("METHOD") == " WHOLEPIXEL") { + useCenter = false; + } + + g_processGroundPolygons.SetIntersectAlgorithm(useCenter); + + + for (int f = 0; f < list.size(); f++) { + + Cube cube(list[f].toString(), "r"); + // Loop through the input cube and get the all pixels values for all bands + ProcessByBrick processBrick; + processBrick.Progress()->SetText("Working on file: " + list[f].toString()); + processBrick.SetBrickSize(1, 1, bands); + // Recall list[f] is a FileName, which stores the attributes + CubeAttributeInput atts0(list[f]); + Cube *icube = processBrick.SetInputCube(list[f].toString(), atts0, 0); + g_incam = icube->camera(); + + if ( ui.WasEntered("TO") ) { + processBrick.StartProcess(rasterizePixel); + processBrick.EndProcess(); + } + if ( ui.WasEntered("TOVECT") ) { + + ofstream fout_vrt; + + QString outFileNameVRT = FileName( outvect.toLatin1().data() ).removeExtension().addExtension("vrt").expanded(); + QString layer_name = FileName( outvect.toLatin1().data() ).baseName(); + QString csv_fname = FileName( outvect.toLatin1().data() ).name(); + + fout_vrt.open( outFileNameVRT.toLatin1().data() ); + + fout_vrt << "" << endl; + fout_vrt << " " << endl; + fout_vrt << " " << csv_fname.toLatin1().data() << "" << endl; + fout_vrt << " wkbPolygon" << endl; + fout_vrt << " "<< ogc_SRS.toLatin1().data() << "" << endl; + fout_vrt << " "<< endl; + fout_vrt << " "<< endl; + fout_vrt << " " << endl; + fout_vrt << " " << endl; + fout_vrt << " " << endl; + fout_vrt << "" << endl; + + fout_vrt.close(); + + + + // write the header + fout_csv.open( outvect.toLatin1().data() ); + fout_csv << "sampleno" << "," << "lineno" << "," << "pixelvalue" << "," << "geom" << endl; + fout_csv.close(); + // open in append mode + fout_csv.open( outvect.toLatin1().data(), std::ios_base::app ); + + processBrick.StartProcess(vectorizePixel); + processBrick.EndProcess(); + fout_csv.close(); + } // IF TOVECT + + } + + if ( ui.WasEntered("TO") ) { + // When there is only one input cube, we want to propagate IsisCube labels to output cubes + if (list.size() == 1) { + // g_incam->SetImage(csamples,clines); + // Note that polygons and original labels are not propagated + g_processGroundPolygons.PropagateLabels(list[0].toString()); + // Tell Process which tables we want to propagate + QList tablesToPropagate; + tablesToPropagate << "InstrumentPointing" << "InstrumentPosition" << "BodyRotation" + << "SunPosition"; + g_processGroundPolygons.PropagateTables(list[0].toString(), tablesToPropagate); + } + } + g_processGroundPolygons.EndProcess(); + + // WARNING: rasterizePixel() method alters the current state of the camera. + // If any code is added after this point, you must call setImage to return + // to original camera state before rasterization. + + } + + + /** + * Helper function to print out mapfile to session log + */ + void PrintMap() { + UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap; + userMap.read(ui.GetFileName("MAP")); + PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); + + //Write map file out to the log + Isis::Application::GuiLog(userGrp); + } + + + /** + * This method uses the ProcessGroundPolygons object to rasterize each + * pixel in the given buffer. + * + * @param in Input ProcessByBrick buffer. + */ + void rasterizePixel(Isis::Buffer &in) { + + std::vectorlat, lon; + std::vectordns; + + for (int i = 0; i < in.size(); i++) { + dns.push_back(in[i]); + } + + int l = in.Line(); + int s = in.Sample(); + + // TODO: This needs to be done for each band for band dependant instruments + // Note: This can slow this down a lot + + // Get the IFOVs in lat/lon space + PixelFOV fov; + QList< QList< QPointF > > fovVertices = fov.latLonVertices(*g_incam, l, s, g_numIFOVs); + + // loop through each ifov list + for (int ifov = 0; ifov < fovVertices.size(); ifov++) { + // we need at least 3 vertices for a polygon + if (fovVertices[ifov].size() > 3) { + // Get lat/lon for each vertex of the ifov + for (int point = 0; point < fovVertices[ifov].size(); point++) { + lat.push_back(fovVertices[ifov][point].x()); + lon.push_back(fovVertices[ifov][point].y()); + } + // rasterize this ifov and clear vectors for next ifov + g_processGroundPolygons.Rasterize(lat, lon, dns); + lat.clear(); + lon.clear(); + } + } + } + + /** + * This method uses the ProcessGroundPolygons object to vectorize each + * pixel in the given buffer. + * + * @param in Input ProcessByBrick buffer. + */ + void vectorizePixel(Isis::Buffer &in) { + + std::vectorlat, lon; + std::vectordns; + geos::geom::Geometry* GndPixel; + + + // Setup the WKT writer + geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); + + + for (int i = 0; i < in.size(); i++) { + dns.push_back(in[i]); + } + + int l = in.Line(); + int s = in.Sample(); + + // DO: This needs to be done for each band for band dependent instruments + // Note: This can slow this down a lot + + // Get the IFOVs in lat/lon space + PixelFOV fov; + QList< QList< QPointF > > fovVertices = fov.latLonVertices(*g_incam, l, s, g_numIFOVs); + + + // loop through each ifov list + for (int ifov = 0; ifov < fovVertices.size(); ifov++) { + // we need at least 3 vertices for a polygon + if (fovVertices[ifov].size() > 3) { + // Get lat/lon for each vertex of the ifov + for (int point = 0; point < fovVertices[ifov].size(); point++) { + lat.push_back(fovVertices[ifov][point].x()); + lon.push_back(fovVertices[ifov][point].y()); + } + // rasterize this ifov and clear vectors for next ifov + // add Vectorize method + GndPixel = g_processGroundPolygons.Vectorize(lat, lon, dns); + //cout << dns[0] << endl; + if ( dns[0] != Isis::Null ) + { fout_csv << s << "," << l << "," << dns[0] << ",\"" << wkt->write(GndPixel) << "\"" << endl;} + + lat.clear(); + lon.clear(); + } + } // main + + +} // namespace Isis + From b555c3024b7c9db88fc89a0e8a44a4412461d0aa Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Wed, 21 Aug 2024 18:08:21 -0700 Subject: [PATCH 05/21] Added app functional test --- isis/tests/FunctionalTestsPixel2map.cpp | 46 +++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 isis/tests/FunctionalTestsPixel2map.cpp diff --git a/isis/tests/FunctionalTestsPixel2map.cpp b/isis/tests/FunctionalTestsPixel2map.cpp new file mode 100644 index 0000000000..43770beab7 --- /dev/null +++ b/isis/tests/FunctionalTestsPixel2map.cpp @@ -0,0 +1,46 @@ +#include +#include +#include + +#include "Fixtures.h" +#include "Camera.h" +#include "CameraFixtures.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "TestUtilities.h" +#include "XmlToPvlTranslationManager.h" +#include "UserInterface.h" + +#include "pixel2map.h" + +#include "gtest/gtest.h" + +using namespace Isis; + +static QString PIXEL2MAP_XML = FileName("$ISISROOT/bin/xml/pixel2map.xml").expanded(); + + +TEST_F(DefaultCube, FunctionalTestPixel2mapVector) { + QFile csvFile(tempDir.path() + "/vect.csv"); + QFile vrtFile(tempDir.path() + "/vect.vrt"); + //QString outCubeFileName = tempDir.path() + "/outTemp.cub"; + QVector args = {"tovect="+csvFile.fileName(), "from="+ testCube->fileName()}; + + UserInterface options(PIXEL2MAP_XML, args); + + //try { + // pixel2map(options); + //} + //catch (IException &e) { + // FAIL() << "Unable to open image: " << e.what() << std::endl; + //} + + // TEST 1: Check we have both csv and vrt file + + FileName csvFileOut(tempDir.path() + "/vect.csv"); + EXPECT_TRUE(csvFileOut.fileExists()); + + FileName vrtFileOut(tempDir.path() + "/vect.vrt"); + EXPECT_TRUE(vrtFileOut.fileExists()); + +} From 6920a551923774bb47415c66cb8211c6662c0623 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Wed, 21 Aug 2024 18:11:41 -0700 Subject: [PATCH 06/21] updated files for refactoring --- isis/src/base/apps/pixel2map/main.cpp | 543 +----------------- isis/src/base/apps/pixel2map/pixel2map.h | 61 ++ .../ProcessGroundPolygons.cpp | 25 +- 3 files changed, 75 insertions(+), 554 deletions(-) diff --git a/isis/src/base/apps/pixel2map/main.cpp b/isis/src/base/apps/pixel2map/main.cpp index 14c0d6f6a8..4c11cfa49e 100755 --- a/isis/src/base/apps/pixel2map/main.cpp +++ b/isis/src/base/apps/pixel2map/main.cpp @@ -1,557 +1,18 @@ -#define GUIHELPERS - #include "Isis.h" -#include -#include -#include -#include - -#include "Camera.h" -#include "Cube.h" -#include "CubeAttribute.h" -#include "FileList.h" -#include "IException.h" -#include "PixelFOV.h" -#include "ProcessByBrick.h" -#include "ProcessGroundPolygons.h" -#include "ProcessRubberSheet.h" -#include "ProjectionFactory.h" -#include "Pvl.h" - -#include "PvlGroup.h" -#include "Target.h" #include "pixel2map.h" -#include "geos/geom/Geometry.h" -#include "geos/io/WKTWriter.h" +#include "UserInterface.h" using namespace std; using namespace Isis; -void PrintMap(); -void rasterizePixel(Isis::Buffer &in); -void vectorizePixel(Isis::Buffer &in); - -map GuiHelpers() { - map helper; - helper ["PrintMap"] = (void *) PrintMap; - return helper; -} - -// Global variables -ProcessGroundPolygons g_processGroundPolygons; -Camera *g_incam; -int g_numIFOVs = 0; -int g_vectorOut = 0; // to be set bool in future - -int csamples; -int clines; - -QString vectOut; -QString outvect; - -ofstream fout_csv; -QString ogc_SRS; - - - void IsisMain() { - - g_incam = NULL; - - // Get the map projection file provided by the user - UserInterface &ui = Application::GetUserInterface(); - Pvl userMap; - userMap.read(ui.GetFileName("MAP")); - PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); - - FileList list; - if (ui.GetString("FROMTYPE") == "FROM") { - // GetAsString will capture the entire string, including attributes - list.push_back(FileName(ui.GetAsString("FROM"))); - } - else { - try { - list.read(ui.GetFileName("FROMLIST")); - } - catch (IException &e) { - throw IException(e); - } - } - - - if (ui.GetString("FOVRANGE") == "INSTANTANEOUS") { - g_numIFOVs = 1; - } - else { - g_numIFOVs = ui.GetInteger("NUMIFOV"); - } - - double newminlat, newmaxlat, newminlon, newmaxlon; - double minlat = 90; - double maxlat = -90; - double minlon = 360.0; - double maxlon = 0; - PvlGroup camGrp; - QString lastBandString; - - - - // Get the combined lat/lon range for all input cubes - int bands = 1; - for (int i = 0; i < list.size(); i++) { - - // Open the input cube and get the camera - CubeAttributeInput atts0(list[i]); - Cube icube; - if(atts0.bands().size() != 0) { - vector lame = atts0.bands(); - icube.setVirtualBands(lame); - } - icube.open( list[i].toString() ); - bands = icube.bandCount(); - g_incam = icube.camera(); - - csamples = g_incam->Samples(); - clines = g_incam->Lines(); - - - Spice spi(icube); - ogc_SRS = "IAU:" + Isis::toString(spi.target()->naifBodyCode()) + "00"; - //cout << ogc_SRS << endl; - - // Make sure it is not the sky - if (g_incam->target()->isSky()) { - QString msg = "The image [" + list[i].toString() + - "] is targeting the sky, use skymap instead."; - throw IException(IException::User, msg, _FILEINFO_); - } - - // Make sure all the bands for all the files match - if (i >= 1 && atts0.bandsString() != lastBandString) { - QString msg = "The Band numbers for all the files do not match."; - throw IException(IException::User, msg, _FILEINFO_); - } - else { - lastBandString = atts0.bandsString(); - } - - // Get the mapping group - Pvl camMap; - g_incam->BasicMapping(camMap); - camGrp = camMap.findGroup("Mapping"); - - g_incam->GroundRange(newminlat, newmaxlat, newminlon, newmaxlon, userMap); - //set min lat/lon - if (newminlat < minlat) { - minlat = newminlat; - } - if (newminlon < minlon) { - minlon = newminlon; - } - - //set max lat/lon - if (newmaxlat > maxlat) { - maxlat = newmaxlat; - } - if (newmaxlon > maxlon) { - maxlon = newmaxlon; - } - - // The camera will be deleted when the Cube is deleted so NULL g_incam - g_incam = NULL; - } //end for list.size - - camGrp.addKeyword(PvlKeyword("MinimumLatitude", toString(minlat)), Pvl::Replace); - camGrp.addKeyword(PvlKeyword("MaximumLatitude", toString(maxlat)), Pvl::Replace); - camGrp.addKeyword(PvlKeyword("MinimumLongitude", toString(minlon)), Pvl::Replace); - camGrp.addKeyword(PvlKeyword("MaximumLongitude", toString(maxlon)), Pvl::Replace); - - - // We want to delete the keywords we just added if the user wants the range - // out of the mapfile, otherwise they will replace any keywords not in the - // mapfile - if (ui.GetString("DEFAULTRANGE") == "MAP") { - camGrp.deleteKeyword("MinimumLatitude"); - camGrp.deleteKeyword("MaximumLatitude"); - camGrp.deleteKeyword("MinimumLongitude"); - camGrp.deleteKeyword("MaximumLongitude"); - } - - // Otherwise, remove the keywords from the map file so the camera keywords - // will be propogated correctly - else { - while (userGrp.hasKeyword("MinimumLatitude")) { - userGrp.deleteKeyword("MinimumLatitude"); - } - while (userGrp.hasKeyword("MinimumLongitude")) { - userGrp.deleteKeyword("MinimumLongitude"); - } - while (userGrp.hasKeyword("MaximumLatitude")) { - userGrp.deleteKeyword("MaximumLatitude"); - } - while (userGrp.hasKeyword("MaximumLongitude")) { - userGrp.deleteKeyword("MaximumLongitude"); - } - } - - // If the user decided to enter a ground range then override - if (ui.WasEntered("MINLON")) { - userGrp.addKeyword(PvlKeyword("MinimumLongitude", - toString(ui.GetDouble("MINLON"))), Pvl::Replace); - } - - if (ui.WasEntered("MAXLON")) { - userGrp.addKeyword(PvlKeyword("MaximumLongitude", - toString(ui.GetDouble("MAXLON"))), Pvl::Replace); - } - - if (ui.WasEntered("MINLAT")) { - userGrp.addKeyword(PvlKeyword("MinimumLatitude", - toString(ui.GetDouble("MINLAT"))), Pvl::Replace); - } - - if (ui.WasEntered("MAXLAT")) { - userGrp.addKeyword(PvlKeyword("MaximumLatitude", - toString(ui.GetDouble("MAXLAT"))), Pvl::Replace); - } - - // If they want the res. from the mapfile, delete it from the camera so - // nothing gets overriden - if (ui.GetString("PIXRES") == "MAP") { - camGrp.deleteKeyword("PixelResolution"); - } - // Otherwise, delete any resolution keywords from the mapfile so the camera - // info is propogated over - else if (ui.GetString("PIXRES") == "CAMERA") { - if (userGrp.hasKeyword("Scale")) { - userGrp.deleteKeyword("Scale"); - } - if (userGrp.hasKeyword("PixelResolution")) { - userGrp.deleteKeyword("PixelResolution"); - } - } - - // Copy any defaults that are not in the user map from the camera map file - for (int k = 0; k < camGrp.keywords(); k++) { - if (!userGrp.hasKeyword(camGrp[k].name())) { - userGrp += camGrp[k]; - } - } - - // If the user decided to enter a resolution then override - if (ui.GetString("PIXRES") == "MPP") { - userGrp.addKeyword(PvlKeyword("PixelResolution", - toString(ui.GetDouble("RESOLUTION"))), - Pvl::Replace); - if (userGrp.hasKeyword("Scale")) { - userGrp.deleteKeyword("Scale"); - } - } - else if (ui.GetString("PIXRES") == "PPD") { - userGrp.addKeyword(PvlKeyword("Scale", - toString(ui.GetDouble("RESOLUTION"))), - Pvl::Replace); - if (userGrp.hasKeyword("PixelResolution")) { - userGrp.deleteKeyword("PixelResolution"); - } - } - - // See if the user want us to handle the longitude seam - if (ui.GetString("DEFAULTRANGE") == "CAMERA" || ui.GetString("DEFAULTRANGE") == "MINIMIZE") { - - // Open the last cube and use its camera - CubeAttributeInput atts0( list.back() ); - Cube icube; - if(atts0.bands().size() != 0) { - vector lame = atts0.bands(); - icube.setVirtualBands(lame); - } - icube.open( list.back().toString() ); - g_incam = icube.camera(); - - if (g_incam->IntersectsLongitudeDomain(userMap)) { - if (ui.GetString("LONSEAM") == "AUTO") { - if ((int) userGrp["LongitudeDomain"] == 360) { - userGrp.addKeyword(PvlKeyword("LongitudeDomain", toString(180)), - Pvl::Replace); - if (g_incam->IntersectsLongitudeDomain(userMap)) { - // Its looks like a global image so switch back to the - // users preference - userGrp.addKeyword(PvlKeyword("LongitudeDomain", toString(360)), - Pvl::Replace); - } - } - else { - userGrp.addKeyword(PvlKeyword("LongitudeDomain", toString(360)), - Pvl::Replace); - if (g_incam->IntersectsLongitudeDomain(userMap)) { - // Its looks like a global image so switch back to the - // users preference - userGrp.addKeyword(PvlKeyword("LongitudeDomain", toString(180)), - Pvl::Replace); - } - } - // Make the target info match the new longitude domain - double minlat, maxlat, minlon, maxlon; - g_incam->GroundRange(minlat, maxlat, minlon, maxlon, userMap); - if (!ui.WasEntered("MINLAT")) { - userGrp.addKeyword(PvlKeyword("MinimumLatitude", toString(minlat)), Pvl::Replace); - } - if (!ui.WasEntered("MAXLAT")) { - userGrp.addKeyword(PvlKeyword("MaximumLatitude", toString(maxlat)), Pvl::Replace); - } - if (!ui.WasEntered("MINLON")) { - userGrp.addKeyword(PvlKeyword("MinimumLongitude", toString(minlon)), Pvl::Replace); - } - if (!ui.WasEntered("MAXLON")) { - userGrp.addKeyword(PvlKeyword("MaximumLongitude", toString(maxlon)), Pvl::Replace); - } - } - - else if (ui.GetString("LONSEAM") == "ERROR") { - QString msg = "The image [" + ui.GetCubeName("FROM") + "] crosses the " + - "longitude seam"; - throw IException(IException::User, msg, _FILEINFO_); - } - } - - // The camera will be deleted when the Cube is deleted so NULL g_incam - g_incam = NULL; - } - - - Pvl pvl; - pvl.addGroup(userGrp); - - - // If there is only one input cube, we need to attach an AlphaCube to the outputs. - if (list.size() == 1) { - Cube parent(list[0].toString()); - if (!parent.hasGroup("AlphaCube")) { - PvlGroup alpha("AlphaCube"); - alpha += PvlKeyword("AlphaSamples", toString(parent.sampleCount())); - alpha += PvlKeyword("AlphaLines", toString(parent.lineCount())); - alpha += PvlKeyword("AlphaStartingSample", toString(0.5)); - alpha += PvlKeyword("AlphaStartingLine", toString(0.5)); - alpha += PvlKeyword("AlphaEndingSample", toString(parent.sampleCount() + 0.5)); - alpha += PvlKeyword("AlphaEndingLine", toString(parent.lineCount() + 0.5)); - alpha += PvlKeyword("BetaSamples", toString(parent.sampleCount())); - alpha += PvlKeyword("BetaLines", toString(parent.lineCount())); - pvl.addGroup(alpha); - } - } - - if ( ui.WasEntered("TO") ) { - g_processGroundPolygons.SetStatCubes("TO", pvl, bands); - } - - if ( ui.WasEntered("TOVECT") ) { - g_vectorOut = 1; - outvect = ui.GetFileName("TOVECT"); - } - - bool useCenter = true; - if (ui.GetString("METHOD") == "CENTER") { - useCenter = true; - } - else if (ui.GetString("METHOD") == " WHOLEPIXEL") { - useCenter = false; - } - - g_processGroundPolygons.SetIntersectAlgorithm(useCenter); - - - for (int f = 0; f < list.size(); f++) { - - Cube cube(list[f].toString(), "r"); - // Loop through the input cube and get the all pixels values for all bands - ProcessByBrick processBrick; - processBrick.Progress()->SetText("Working on file: " + list[f].toString()); - processBrick.SetBrickSize(1, 1, bands); - // Recall list[f] is a FileName, which stores the attributes - CubeAttributeInput atts0(list[f]); - Cube *icube = processBrick.SetInputCube(list[f].toString(), atts0, 0); - g_incam = icube->camera(); - - if ( ui.WasEntered("TO") ) { - processBrick.StartProcess(rasterizePixel); - processBrick.EndProcess(); - } - if ( ui.WasEntered("TOVECT") ) { - - ofstream fout_vrt; - - QString outFileNameVRT = FileName( outvect.toLatin1().data() ).removeExtension().addExtension("vrt").expanded(); - QString layer_name = FileName( outvect.toLatin1().data() ).baseName(); - QString csv_fname = FileName( outvect.toLatin1().data() ).name(); - - fout_vrt.open( outFileNameVRT.toLatin1().data() ); - - fout_vrt << "" << endl; - fout_vrt << " " << endl; - fout_vrt << " " << csv_fname.toLatin1().data() << "" << endl; - fout_vrt << " wkbPolygon" << endl; - fout_vrt << " "<< ogc_SRS.toLatin1().data() << "" << endl; - fout_vrt << " "<< endl; - fout_vrt << " "<< endl; - fout_vrt << " " << endl; - fout_vrt << " " << endl; - fout_vrt << " " << endl; - fout_vrt << "" << endl; - - fout_vrt.close(); - - - - // write the header - fout_csv.open( outvect.toLatin1().data() ); - fout_csv << "sampleno" << "," << "lineno" << "," << "pixelvalue" << "," << "geom" << endl; - fout_csv.close(); - // open in append mode - fout_csv.open( outvect.toLatin1().data(), std::ios_base::app ); - - processBrick.StartProcess(vectorizePixel); - processBrick.EndProcess(); - fout_csv.close(); - } // IF TOVECT - - } - - if ( ui.WasEntered("TO") ) { - // When there is only one input cube, we want to propagate IsisCube labels to output cubes - if (list.size() == 1) { - // g_incam->SetImage(csamples,clines); - // Note that polygons and original labels are not propagated - g_processGroundPolygons.PropagateLabels(list[0].toString()); - // Tell Process which tables we want to propagate - QList tablesToPropagate; - tablesToPropagate << "InstrumentPointing" << "InstrumentPosition" << "BodyRotation" - << "SunPosition"; - g_processGroundPolygons.PropagateTables(list[0].toString(), tablesToPropagate); - } - } - g_processGroundPolygons.EndProcess(); - - // WARNING: rasterizePixel() method alters the current state of the camera. - // If any code is added after this point, you must call setImage to return - // to original camera state before rasterization. - -} - - -/** - * Helper function to print out mapfile to session log - */ -void PrintMap() { UserInterface &ui = Application::GetUserInterface(); - - // Get mapping group from map file - Pvl userMap; - userMap.read(ui.GetFileName("MAP")); - PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); - - //Write map file out to the log - Isis::Application::GuiLog(userGrp); -} - - -/** - * This method uses the ProcessGroundPolygons object to rasterize each - * pixel in the given buffer. - * - * @param in Input ProcessByBrick buffer. - */ -void rasterizePixel(Isis::Buffer &in) { - - std::vectorlat, lon; - std::vectordns; - - for (int i = 0; i < in.size(); i++) { - dns.push_back(in[i]); - } - - int l = in.Line(); - int s = in.Sample(); - - // TODO: This needs to be done for each band for band dependant instruments - // Note: This can slow this down a lot - - // Get the IFOVs in lat/lon space - PixelFOV fov; - QList< QList< QPointF > > fovVertices = fov.latLonVertices(*g_incam, l, s, g_numIFOVs); - - // loop through each ifov list - for (int ifov = 0; ifov < fovVertices.size(); ifov++) { - // we need at least 3 vertices for a polygon - if (fovVertices[ifov].size() > 3) { - // Get lat/lon for each vertex of the ifov - for (int point = 0; point < fovVertices[ifov].size(); point++) { - lat.push_back(fovVertices[ifov][point].x()); - lon.push_back(fovVertices[ifov][point].y()); - } - // rasterize this ifov and clear vectors for next ifov - g_processGroundPolygons.Rasterize(lat, lon, dns); - lat.clear(); - lon.clear(); - } - } + pixel2map(ui); } -/** - * This method uses the ProcessGroundPolygons object to vectorize each - * pixel in the given buffer. - * - * @param in Input ProcessByBrick buffer. - */ -void vectorizePixel(Isis::Buffer &in) { - std::vectorlat, lon; - std::vectordns; - geos::geom::Geometry* GndPixel; - - - // Setup the WKT writer - geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); - - - for (int i = 0; i < in.size(); i++) { - dns.push_back(in[i]); - } - - int l = in.Line(); - int s = in.Sample(); - - // DO: This needs to be done for each band for band dependent instruments - // Note: This can slow this down a lot - - // Get the IFOVs in lat/lon space - PixelFOV fov; - QList< QList< QPointF > > fovVertices = fov.latLonVertices(*g_incam, l, s, g_numIFOVs); - - - // loop through each ifov list - for (int ifov = 0; ifov < fovVertices.size(); ifov++) { - // we need at least 3 vertices for a polygon - if (fovVertices[ifov].size() > 3) { - // Get lat/lon for each vertex of the ifov - for (int point = 0; point < fovVertices[ifov].size(); point++) { - lat.push_back(fovVertices[ifov][point].x()); - lon.push_back(fovVertices[ifov][point].y()); - } - // rasterize this ifov and clear vectors for next ifov - // add Vectorize method - GndPixel = g_processGroundPolygons.Vectorize(lat, lon, dns); - //cout << dns[0] << endl; - if ( dns[0] != Isis::Null ) - { fout_csv << s << "," << l << "," << dns[0] << ",\"" << wkt->write(GndPixel) << "\"" << endl;} - - lat.clear(); - lon.clear(); - } - } -} diff --git a/isis/src/base/apps/pixel2map/pixel2map.h b/isis/src/base/apps/pixel2map/pixel2map.h index 9e616cf2ae..82d5860ccd 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.h +++ b/isis/src/base/apps/pixel2map/pixel2map.h @@ -1,8 +1,67 @@ #ifndef pixel2map_h #define pixel2map_h +#include +#include +#include +#include + +#include "Camera.h" +#include "Cube.h" +#include "CubeAttribute.h" +#include "FileList.h" +#include "IException.h" +#include "PixelFOV.h" +#include "ProcessByBrick.h" +#include "ProcessGroundPolygons.h" +#include "ProcessRubberSheet.h" +#include "ProjectionFactory.h" +#include "Pvl.h" + +#include "PvlGroup.h" +#include "Target.h" + #include "Transform.h" +#include "geos/geom/Geometry.h" +#include "geos/io/WKTWriter.h" + + +void PrintMap(); +void rasterizePixel(Isis::Buffer &in); +void vectorizePixel(Isis::Buffer &in); + +map GuiHelpers() { + map helper; + helper ["PrintMap"] = (void *) PrintMap; + return helper; +} + + + + +// Global variables +ProcessGroundPolygons g_processGroundPolygons; +Camera *g_incam; +int g_numIFOVs = 0; +int g_vectorOut = 0; // to be set bool in future + +int csamples; +int clines; + +QString vectOut; +QString outvect; + +ofstream fout_csv; +QString ogc_SRS; + + +namespace Isis { + extern void pixel2map(UserInterface &ui); + extern void cam2map(Cube *icube, Pvl &userMap); + + + /** * @author 2008-02-13 Stacy Alley * @@ -26,4 +85,6 @@ class pixel2map : public Isis::Transform { }; +} // namespace Isis + #endif diff --git a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp index 34fad07ed3..d031f151cc 100644 --- a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp +++ b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp @@ -9,7 +9,6 @@ find files of those names at the top level of this repository. **/ #include #include "geos/geom/CoordinateSequence.h" -#include "geos/geom/CoordinateArraySequence.h" #include "geos/geom/LineString.h" #include "geos/io/WKTWriter.h" @@ -54,14 +53,14 @@ namespace Isis { if (crosses) { // Make a polygon from the lat/lon vectors and split it on 360 - geos::geom::CoordinateArraySequence *pts = new geos::geom::CoordinateArraySequence(); + geos::geom::CoordinateSequence pts; for (unsigned int i = 0; i < lat.size(); i++) { - pts->add(geos::geom::Coordinate(lon[i], lat[i])); + pts.add(geos::geom::Coordinate(lon[i], lat[i])); } - pts->add(geos::geom::Coordinate(lon[0], lat[0])); + pts.add(geos::geom::Coordinate(lon[0], lat[0])); geos::geom::Polygon *crossingPoly = Isis::globalFactory->createPolygon( - globalFactory->createLinearRing(pts), NULL); + globalFactory->createLinearRing(pts)).release(); geos::geom::MultiPolygon *splitPoly = NULL; try { @@ -139,14 +138,14 @@ geos::geom::Geometry* ProcessGroundPolygons::Vectorize(std::vector &lat, if (crosses) { // Make a polygon from the lat/lon vectors and split it on 360 - geos::geom::CoordinateArraySequence *pts = new geos::geom::CoordinateArraySequence(); + geos::geom::CoordinateSequence pts; for (unsigned int i = 0; i < lat.size(); i++) { - pts->add(geos::geom::Coordinate(lon[i], lat[i])); + pts.add(geos::geom::Coordinate(lon[i], lat[i])); } - pts->add(geos::geom::Coordinate(lon[0], lat[0])); + pts.add(geos::geom::Coordinate(lon[0], lat[0])); geos::geom::Polygon *crossingPoly = Isis::globalFactory->createPolygon( - globalFactory->createLinearRing(pts), NULL); + globalFactory->createLinearRing(pts)).release(); geos::geom::MultiPolygon *splitPoly = NULL; try { @@ -190,14 +189,14 @@ geos::geom::Geometry* ProcessGroundPolygons::Vectorize(std::vector &lat, else { // if does not crosses // Make a polygon from the lat/lon vectors and split it on 360 - geos::geom::CoordinateArraySequence *pts = new geos::geom::CoordinateArraySequence(); + geos::geom::CoordinateSequence pts; for (unsigned int i = 0; i < lat.size(); i++) { - pts->add(geos::geom::Coordinate(lon[i], lat[i])); + pts.add(geos::geom::Coordinate(lon[i], lat[i])); } - pts->add(geos::geom::Coordinate(lon[0], lat[0])); + pts.add(geos::geom::Coordinate(lon[0], lat[0])); geos::geom::Polygon *crossingPoly = Isis::globalFactory->createPolygon( - globalFactory->createLinearRing(pts), NULL); + globalFactory->createLinearRing(pts)).release(); return crossingPoly; //ProcessPolygons::Rasterize(p_samples, p_lines, values); From 0c4b24345ec380b0c9cc30e4cbd656fb0f210c3a Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Wed, 21 Aug 2024 18:13:37 -0700 Subject: [PATCH 07/21] removed call to UserInterface in new cpp code --- isis/src/base/apps/pixel2map/pixel2map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp index 7c2df7655d..b9e5db789f 100644 --- a/isis/src/base/apps/pixel2map/pixel2map.cpp +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -10,7 +10,7 @@ namespace Isis { g_incam = NULL; // Get the map projection file provided by the user - UserInterface &ui = Application::GetUserInterface(); + // UserInterface &ui = Application::GetUserInterface(); Pvl userMap; userMap.read(ui.GetFileName("MAP")); PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); From 466b73d936a15846b413b2eb3a41fd1e366d5678 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Thu, 22 Aug 2024 00:35:21 -0700 Subject: [PATCH 08/21] refactored started working --- isis/src/base/apps/pixel2map/main.cpp | 3 +- isis/src/base/apps/pixel2map/pixel2map.cpp | 58 +++++++++++++++++----- isis/src/base/apps/pixel2map/pixel2map.h | 36 ++++++++------ 3 files changed, 69 insertions(+), 28 deletions(-) diff --git a/isis/src/base/apps/pixel2map/main.cpp b/isis/src/base/apps/pixel2map/main.cpp index 4c11cfa49e..ad3fc39f9e 100755 --- a/isis/src/base/apps/pixel2map/main.cpp +++ b/isis/src/base/apps/pixel2map/main.cpp @@ -1,7 +1,7 @@ #include "Isis.h" #include "pixel2map.h" - +#include "Pvl.h" #include "UserInterface.h" using namespace std; @@ -9,6 +9,7 @@ using namespace Isis; void IsisMain() { UserInterface &ui = Application::GetUserInterface(); + Pvl appLog; pixel2map(ui); } diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp index b9e5db789f..606ed9b8ac 100644 --- a/isis/src/base/apps/pixel2map/pixel2map.cpp +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -2,17 +2,45 @@ #include "pixel2map.h" +#include "Process.h" +#include "Pvl.h" + using namespace std; +using namespace Isis; namespace Isis { - - g_incam = NULL; + static void rasterizePixel(Isis::Buffer &in); + static void vectorizePixel(Isis::Buffer &in); + + // Global variables + Cube *incube; + + // This is the FIRST required function ///////////////////////////////////////////////// + //void pixel2map(UserInterface &ui){ + // // Open the input cube + // //Cube *incube; + // //CubeAttributeInput inAtt = ui.GetInputAttribute("FROM"); + // Cube *inCube = new Cube( ui.GetCubeName("FROM"), "r"); + // + // // Now we got the Cube, we call the SECOND function + // pixel2map(inCube, ui); + //} + + // This is the SECOND required function //////////////////////////////////////////////// + //void pixel2map(Cube *inCube, UserInterface &ui){ + void pixel2map(UserInterface &ui){ + + //Camera *g_incam; + //Camera g_incam; + //Pvl userMap; + // Get the map projection file provided by the user // UserInterface &ui = Application::GetUserInterface(); - Pvl userMap; - userMap.read(ui.GetFileName("MAP")); + + //Pvl userMap.read(ui.GetFileName("MAP")); + Pvl userMap(ui.GetFileName("MAP")); PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); FileList list; @@ -87,7 +115,7 @@ namespace Isis { } // Get the mapping group - Pvl camMap; + Isis::Pvl camMap; g_incam->BasicMapping(camMap); camGrp = camMap.findGroup("Mapping"); @@ -386,23 +414,26 @@ namespace Isis { // WARNING: rasterizePixel() method alters the current state of the camera. // If any code is added after this point, you must call setImage to return // to original camera state before rasterization. - + } /** * Helper function to print out mapfile to session log */ - void PrintMap() { - UserInterface &ui = Application::GetUserInterface(); + void PrintMap(UserInterface &ui) { + //removed in the refactoring process + //UserInterface &ui = Application::GetUserInterface(); // Get mapping group from map file - Pvl userMap; - userMap.read(ui.GetFileName("MAP")); + //Pvl userMap; + //userMap.read(ui.GetFileName("MAP")); + Pvl userMap(ui.GetFileName("MAP")); PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); //Write map file out to the log - Isis::Application::GuiLog(userGrp); + // + //Isis::Application::GuiLog(userGrp); } @@ -499,8 +530,11 @@ namespace Isis { lat.clear(); lon.clear(); } - } // main + } // main + + + } // pixel2map void } // namespace Isis diff --git a/isis/src/base/apps/pixel2map/pixel2map.h b/isis/src/base/apps/pixel2map/pixel2map.h index 82d5860ccd..dbf3bb3e4e 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.h +++ b/isis/src/base/apps/pixel2map/pixel2map.h @@ -26,23 +26,24 @@ #include "geos/geom/Geometry.h" #include "geos/io/WKTWriter.h" +#include "UserInterface.h" void PrintMap(); -void rasterizePixel(Isis::Buffer &in); -void vectorizePixel(Isis::Buffer &in); +//void rasterizePixel(Isis::Buffer &in); +//void vectorizePixel(Isis::Buffer &in); -map GuiHelpers() { - map helper; - helper ["PrintMap"] = (void *) PrintMap; - return helper; -} +//std::map GuiHelpers() { +// map helper; +// helper ["PrintMap"] = (void *) PrintMap; +// return helper; +//} // Global variables -ProcessGroundPolygons g_processGroundPolygons; -Camera *g_incam; +Isis::ProcessGroundPolygons g_processGroundPolygons; +Isis::Camera *g_incam; int g_numIFOVs = 0; int g_vectorOut = 0; // to be set bool in future @@ -52,13 +53,18 @@ int clines; QString vectOut; QString outvect; -ofstream fout_csv; +std::ofstream fout_csv; QString ogc_SRS; namespace Isis { - extern void pixel2map(UserInterface &ui); - extern void cam2map(Cube *icube, Pvl &userMap); + extern void pixel2map(UserInterface &ui); + extern void pixel2map(Cube* incube, UserInterface &ui); + //extern void pixel2map(UserInterface &ui); + //extern void pixel2map(UserInterface &ui, Pvl *log=nullptr); + //extern void pixel2map(Cube *incube, Pvl &userMap); + + @@ -68,19 +74,19 @@ namespace Isis { * @internal * @history 2013-07-30 Stuart C. Sides & Tracie Sucharski Renamed from vim2map */ -class pixel2map : public Isis::Transform { +class pixel2mapForward : public Isis::Transform { private: Isis::Camera *p_incam; Isis::Projection *p_outmap; public: // constructor - pixel2map(const int inputSamples, const int inputLines, Isis::Camera *incam, + pixel2mapForward(const int inputSamples, const int inputLines, Isis::Camera *incam, const int outputSamples, const int outputLines, Isis::Projection *outmap, bool trim); // destructor - ~pixel2map() {}; + ~pixel2mapForward() {}; }; From 3a04081d75f2cda5e86b202e670a2789a74bf5ce Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Thu, 22 Aug 2024 01:25:55 -0700 Subject: [PATCH 09/21] First functional test working --- isis/src/base/apps/pixel2map/pixel2map.cpp | 3 ++- isis/tests/FunctionalTestsPixel2map.cpp | 17 ++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp index 606ed9b8ac..2cb73ee5c4 100644 --- a/isis/src/base/apps/pixel2map/pixel2map.cpp +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -523,7 +523,8 @@ namespace Isis { // rasterize this ifov and clear vectors for next ifov // add Vectorize method GndPixel = g_processGroundPolygons.Vectorize(lat, lon, dns); - //cout << dns[0] << endl; + // cout << dns[0] << endl; + // Generate only non null pixel if ( dns[0] != Isis::Null ) { fout_csv << s << "," << l << "," << dns[0] << ",\"" << wkt->write(GndPixel) << "\"" << endl;} diff --git a/isis/tests/FunctionalTestsPixel2map.cpp b/isis/tests/FunctionalTestsPixel2map.cpp index 43770beab7..2eb5c1977a 100644 --- a/isis/tests/FunctionalTestsPixel2map.cpp +++ b/isis/tests/FunctionalTestsPixel2map.cpp @@ -28,18 +28,17 @@ TEST_F(DefaultCube, FunctionalTestPixel2mapVector) { UserInterface options(PIXEL2MAP_XML, args); - //try { - // pixel2map(options); - //} - //catch (IException &e) { - // FAIL() << "Unable to open image: " << e.what() << std::endl; - //} - - // TEST 1: Check we have both csv and vrt file + try { + pixel2map(options); + } + catch (IException &e) { + FAIL() << "Unable to open image: " << e.what() << std::endl; + } + + // TEST 1: Check we have both csv and vrt output files FileName csvFileOut(tempDir.path() + "/vect.csv"); EXPECT_TRUE(csvFileOut.fileExists()); - FileName vrtFileOut(tempDir.path() + "/vect.vrt"); EXPECT_TRUE(vrtFileOut.fileExists()); From 75b3d0eb80832c638c9d985a9378482a725d160c Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Thu, 22 Aug 2024 01:54:02 -0700 Subject: [PATCH 10/21] Removed unused headers --- isis/src/base/apps/pixel2map/main.cpp | 2 +- isis/src/base/apps/pixel2map/pixel2map.cpp | 3 +-- isis/src/base/apps/pixel2map/pixel2map.h | 12 +++++------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/isis/src/base/apps/pixel2map/main.cpp b/isis/src/base/apps/pixel2map/main.cpp index ad3fc39f9e..f0a9ac6b83 100755 --- a/isis/src/base/apps/pixel2map/main.cpp +++ b/isis/src/base/apps/pixel2map/main.cpp @@ -1,7 +1,7 @@ #include "Isis.h" #include "pixel2map.h" -#include "Pvl.h" + #include "UserInterface.h" using namespace std; diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp index 2cb73ee5c4..5193b0c63f 100644 --- a/isis/src/base/apps/pixel2map/pixel2map.cpp +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -3,7 +3,6 @@ #include "pixel2map.h" #include "Process.h" -#include "Pvl.h" using namespace std; using namespace Isis; @@ -29,7 +28,7 @@ namespace Isis { // This is the SECOND required function //////////////////////////////////////////////// //void pixel2map(Cube *inCube, UserInterface &ui){ - void pixel2map(UserInterface &ui){ + void pixel2map(UserInterface &ui){ //Camera *g_incam; //Camera g_incam; diff --git a/isis/src/base/apps/pixel2map/pixel2map.h b/isis/src/base/apps/pixel2map/pixel2map.h index dbf3bb3e4e..b711b637a0 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.h +++ b/isis/src/base/apps/pixel2map/pixel2map.h @@ -8,17 +8,14 @@ #include "Camera.h" #include "Cube.h" -#include "CubeAttribute.h" #include "FileList.h" -#include "IException.h" #include "PixelFOV.h" #include "ProcessByBrick.h" #include "ProcessGroundPolygons.h" -#include "ProcessRubberSheet.h" -#include "ProjectionFactory.h" +//#include "ProcessRubberSheet.h" +//#include "ProjectionFactory.h" #include "Pvl.h" - -#include "PvlGroup.h" +//#include "PvlGroup.h" #include "Target.h" #include "Transform.h" @@ -64,7 +61,8 @@ namespace Isis { //extern void pixel2map(UserInterface &ui, Pvl *log=nullptr); //extern void pixel2map(Cube *incube, Pvl &userMap); - + //static void rasterizePixel(Isis::Buffer &in); + //static void vectorizePixel(Isis::Buffer &in); From 063ccd64f8931d5f9385c644ae850e140469434d Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Thu, 22 Aug 2024 11:56:03 -0700 Subject: [PATCH 11/21] code reviewed with Kelvin --- isis/src/base/apps/pixel2map/main.cpp | 35 +++++++++++++++- isis/src/base/apps/pixel2map/pixel2map.cpp | 48 +++++++++------------- isis/src/base/apps/pixel2map/pixel2map.h | 32 ++++----------- isis/src/base/apps/pixel2map/pixel2map.xml | 11 ++--- isis/tests/FunctionalTestsPixel2map.cpp | 37 ++++++++++++++--- 5 files changed, 101 insertions(+), 62 deletions(-) diff --git a/isis/src/base/apps/pixel2map/main.cpp b/isis/src/base/apps/pixel2map/main.cpp index f0a9ac6b83..ef3e5a1765 100755 --- a/isis/src/base/apps/pixel2map/main.cpp +++ b/isis/src/base/apps/pixel2map/main.cpp @@ -1,5 +1,8 @@ +#define GUIHELPERS #include "Isis.h" +#include "Application.h" + #include "pixel2map.h" #include "UserInterface.h" @@ -7,13 +10,43 @@ using namespace std; using namespace Isis; +void PrintMap(); + +// Check for docs for GUI helpers -> KEEP and move it to pixel2map.cpp + std::map GuiHelpers() { + map helper; + helper ["PrintMap"] = (void *) PrintMap; + return helper; +} + + void IsisMain() { UserInterface &ui = Application::GetUserInterface(); Pvl appLog; - pixel2map(ui); + pixel2map(ui, &appLog); + + if( ui.WasEntered("TO") && ui.IsInteractive() ) { + Application::GuiLog(appLog); + } + } +/** + * Helper function to print out mapfile to session log + */ +void PrintMap() { +//removed in the refactoring process +UserInterface &ui = Application::GetUserInterface(); + + // Get mapping group from map file + Pvl userMap(ui.GetFileName("MAP")); + PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); + + //Write map file out to the log +// + Isis::Application::GuiLog(userGrp); +} // PrintMap diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp index 5193b0c63f..e8d12ee2a7 100644 --- a/isis/src/base/apps/pixel2map/pixel2map.cpp +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -13,7 +13,20 @@ namespace Isis { static void vectorizePixel(Isis::Buffer &in); // Global variables - Cube *incube; + static Cube *incube; + static Isis::ProcessGroundPolygons g_processGroundPolygons; + static Isis::Camera *g_incam; + static int g_numIFOVs = 0; + static int g_vectorOut = 0; // to be set bool in future + + static int csamples; + static int clines; + + static QString vectOut; + static QString outvect; + + static std::ofstream fout_csv; + static QString ogc_SRS; // This is the FIRST required function ///////////////////////////////////////////////// //void pixel2map(UserInterface &ui){ @@ -28,7 +41,7 @@ namespace Isis { // This is the SECOND required function //////////////////////////////////////////////// //void pixel2map(Cube *inCube, UserInterface &ui){ - void pixel2map(UserInterface &ui){ + void pixel2map(UserInterface &ui, Pvl *appLog){ //Camera *g_incam; //Camera g_incam; @@ -414,26 +427,9 @@ namespace Isis { // If any code is added after this point, you must call setImage to return // to original camera state before rasterization. - } + } // void pixel2map - /** - * Helper function to print out mapfile to session log - */ - void PrintMap(UserInterface &ui) { - //removed in the refactoring process - //UserInterface &ui = Application::GetUserInterface(); - - // Get mapping group from map file - //Pvl userMap; - //userMap.read(ui.GetFileName("MAP")); - Pvl userMap(ui.GetFileName("MAP")); - PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); - - //Write map file out to the log - // - //Isis::Application::GuiLog(userGrp); - } /** @@ -476,7 +472,7 @@ namespace Isis { lon.clear(); } } - } + } // rasterizePixel /** * This method uses the ProcessGroundPolygons object to vectorize each @@ -489,12 +485,10 @@ namespace Isis { std::vectorlat, lon; std::vectordns; geos::geom::Geometry* GndPixel; - // Setup the WKT writer geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); - for (int i = 0; i < in.size(); i++) { dns.push_back(in[i]); } @@ -531,10 +525,8 @@ namespace Isis { lon.clear(); } - } // main - - - - } // pixel2map void + } + + } // vectorizePixel } // namespace Isis diff --git a/isis/src/base/apps/pixel2map/pixel2map.h b/isis/src/base/apps/pixel2map/pixel2map.h index b711b637a0..350fceb548 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.h +++ b/isis/src/base/apps/pixel2map/pixel2map.h @@ -25,10 +25,10 @@ #include "UserInterface.h" -void PrintMap(); -//void rasterizePixel(Isis::Buffer &in); -//void vectorizePixel(Isis::Buffer &in); +//void PrintMap(); + +// Check for docs for GUI helpers -> KEEP and move it to pixel2map.cpp //std::map GuiHelpers() { // map helper; // helper ["PrintMap"] = (void *) PrintMap; @@ -38,27 +38,10 @@ void PrintMap(); -// Global variables -Isis::ProcessGroundPolygons g_processGroundPolygons; -Isis::Camera *g_incam; -int g_numIFOVs = 0; -int g_vectorOut = 0; // to be set bool in future - -int csamples; -int clines; - -QString vectOut; -QString outvect; - -std::ofstream fout_csv; -QString ogc_SRS; - - namespace Isis { - extern void pixel2map(UserInterface &ui); - extern void pixel2map(Cube* incube, UserInterface &ui); - //extern void pixel2map(UserInterface &ui); - //extern void pixel2map(UserInterface &ui, Pvl *log=nullptr); + + //extern void pixel2map(Cube* incube, UserInterface &ui); + extern void pixel2map(UserInterface &ui, Pvl *log=nullptr); //extern void pixel2map(Cube *incube, Pvl &userMap); //static void rasterizePixel(Isis::Buffer &in); @@ -72,6 +55,8 @@ namespace Isis { * @internal * @history 2013-07-30 Stuart C. Sides & Tracie Sucharski Renamed from vim2map */ + + /** class pixel2mapForward : public Isis::Transform { private: Isis::Camera *p_incam; @@ -88,6 +73,7 @@ class pixel2mapForward : public Isis::Transform { }; +**/ } // namespace Isis diff --git a/isis/src/base/apps/pixel2map/pixel2map.xml b/isis/src/base/apps/pixel2map/pixel2map.xml index e87a8f4e7a..2f6a6bea86 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.xml +++ b/isis/src/base/apps/pixel2map/pixel2map.xml @@ -323,8 +323,8 @@ Updated documentation and added examples. Fixes #4537. - - Added Vector output + + Added Vector output @@ -450,14 +450,15 @@ output Null - Geospatial VRT Vector File + Geospatial CSV/BVRT Vector File - The output file will be a VRT File and a comma-delimited file. This file format - can easily be imported into Open Gis Consortium (OGC) compatible Geospatial tools. + The output file is a comma-delimited file and a VRT sidecar file with geospatial metadata. The coordinate are spherical, unprojected. This file is interoperable with Open Gis Consortium (OGC) compatible Geospatial tools. TO + MAP + FROMLIST *.csv diff --git a/isis/tests/FunctionalTestsPixel2map.cpp b/isis/tests/FunctionalTestsPixel2map.cpp index 2eb5c1977a..c267209b30 100644 --- a/isis/tests/FunctionalTestsPixel2map.cpp +++ b/isis/tests/FunctionalTestsPixel2map.cpp @@ -9,6 +9,9 @@ #include "PvlGroup.h" #include "TestUtilities.h" #include "XmlToPvlTranslationManager.h" +#include "CSVReader.h" +#include "LineManager.h" + #include "UserInterface.h" #include "pixel2map.h" @@ -21,8 +24,15 @@ static QString PIXEL2MAP_XML = FileName("$ISISROOT/bin/xml/pixel2map.xml").expan TEST_F(DefaultCube, FunctionalTestPixel2mapVector) { - QFile csvFile(tempDir.path() + "/vect.csv"); - QFile vrtFile(tempDir.path() + "/vect.vrt"); + + + //QString csvFileName = tempDir.path() + "/vect.csv"; + //QString vrtFileName = tempDir.path() + "/vect.vrt"; + QString csvFileName = "P2Mvect.csv"; + QString vrtFileName = "P2Mvect.vrt"; + + QFile csvFile( csvFileName ); + QFile vrtFile( vrtFileName ); //QString outCubeFileName = tempDir.path() + "/outTemp.cub"; QVector args = {"tovect="+csvFile.fileName(), "from="+ testCube->fileName()}; @@ -35,11 +45,28 @@ TEST_F(DefaultCube, FunctionalTestPixel2mapVector) { FAIL() << "Unable to open image: " << e.what() << std::endl; } - // TEST 1: Check we have both csv and vrt output files + // TEST 1a: Check we have both csv and vrt output files - FileName csvFileOut(tempDir.path() + "/vect.csv"); + FileName csvFileOut( csvFileName ); EXPECT_TRUE(csvFileOut.fileExists()); - FileName vrtFileOut(tempDir.path() + "/vect.vrt"); + FileName vrtFileOut( vrtFileName ); EXPECT_TRUE(vrtFileOut.fileExists()); + // TEST 1b: Check the output csv file header + + CSVReader::CSVAxis csvLine; + CSVReader csvout = CSVReader( csvFileName , false, 0, ','); + + csvLine = csvout.getRow(0); + + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[0], "sampleno"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[1], "lineno"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[2], "pixelvalue"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[3], "geom"); + + std::cout << "Number of rows in the CSV: " << csvout.size() << '\n'; + //std::cout << testCube.sampleCount() << '\n'; + + EXPECT_EQ(testCube->sampleCount()*testCube->lineCount(), csvout.rows()-1); + } From 36e80d1af24f09b59cf0707fbff3430069ab1adb Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Thu, 22 Aug 2024 17:52:22 -0700 Subject: [PATCH 12/21] fixed Functional Test - started UnitTest --- isis/src/base/apps/pixel2map/pixel2map.cpp | 45 +++++++++++++++++----- isis/tests/CameraFixtures.cpp | 4 +- isis/tests/FunctionalTestsPixel2map.cpp | 34 +++++++++++----- 3 files changed, 62 insertions(+), 21 deletions(-) diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp index e8d12ee2a7..6facde78c7 100644 --- a/isis/src/base/apps/pixel2map/pixel2map.cpp +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -369,9 +369,11 @@ namespace Isis { processBrick.EndProcess(); } if ( ui.WasEntered("TOVECT") ) { - + ofstream fout_vrt; + cout << "==========Pixel Type: " << PixelTypeName(cube.pixelType()) << " code:" << cube.pixelType() << endl; + QString outFileNameVRT = FileName( outvect.toLatin1().data() ).removeExtension().addExtension("vrt").expanded(); QString layer_name = FileName( outvect.toLatin1().data() ).baseName(); QString csv_fname = FileName( outvect.toLatin1().data() ).name(); @@ -398,9 +400,9 @@ namespace Isis { fout_csv.open( outvect.toLatin1().data() ); fout_csv << "sampleno" << "," << "lineno" << "," << "pixelvalue" << "," << "geom" << endl; fout_csv.close(); - // open in append mode + // re-open in append mode fout_csv.open( outvect.toLatin1().data(), std::ios_base::app ); - + //fout_csv << std::setprecision(7); // see isis2ascii processBrick.StartProcess(vectorizePixel); processBrick.EndProcess(); fout_csv.close(); @@ -489,9 +491,18 @@ namespace Isis { // Setup the WKT writer geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); + //cout << "dns Size: " << in.size() << endl; + + // With one band at input, size will be 1 for (int i = 0; i < in.size(); i++) { - dns.push_back(in[i]); - } + // adds the element at the end of the vector + if(IsNullPixel(in[i])){ + dns.push_back( 999.999 ); + } + else { + dns.push_back(in[i]); + } + } int l = in.Line(); int s = in.Sample(); @@ -516,16 +527,30 @@ namespace Isis { // rasterize this ifov and clear vectors for next ifov // add Vectorize method GndPixel = g_processGroundPolygons.Vectorize(lat, lon, dns); - // cout << dns[0] << endl; + + // Using back() function to retrieve the last element + //float pixelvalue = dns.back(); + + //QString myvalue = printf ("%4.2f ", dns[0]); + //QString myvalue = QString("%4.2f").arg(dns[0]); + QString v = QString::number(dns[0]); + // Generate only non null pixel - if ( dns[0] != Isis::Null ) - { fout_csv << s << "," << l << "," << dns[0] << ",\"" << wkt->write(GndPixel) << "\"" << endl;} - + if ( dns[0] != Isis::Null ) { + fout_csv << s << "," << l << "," << dns[0] << ",\"" << wkt->write(GndPixel) << "\"" << endl; + } + + //fout_csv << s << "," << l << "," << v << ",\"" << wkt->write(GndPixel) << "\"" << endl; + lat.clear(); lon.clear(); + + } - } + } + + } // vectorizePixel } // namespace Isis diff --git a/isis/tests/CameraFixtures.cpp b/isis/tests/CameraFixtures.cpp index 716c40add3..60b9785ccc 100644 --- a/isis/tests/CameraFixtures.cpp +++ b/isis/tests/CameraFixtures.cpp @@ -185,7 +185,7 @@ namespace Isis { projCubeLabel >> projLabel; testCube = new Cube(); - testCube->fromIsd(tempDir.path() + "/default.cub", label, isd, "rw"); + testCube->fromIsd("tempDir.path() + default.cub", label, isd, "rw"); LineManager line(*testCube); int pixelValue = 1; @@ -988,4 +988,4 @@ namespace Isis { testCube.reset(); } -} \ No newline at end of file +} diff --git a/isis/tests/FunctionalTestsPixel2map.cpp b/isis/tests/FunctionalTestsPixel2map.cpp index c267209b30..cbb6978e57 100644 --- a/isis/tests/FunctionalTestsPixel2map.cpp +++ b/isis/tests/FunctionalTestsPixel2map.cpp @@ -11,6 +11,7 @@ #include "XmlToPvlTranslationManager.h" #include "CSVReader.h" #include "LineManager.h" +#include "Histogram.h" #include "UserInterface.h" @@ -22,19 +23,25 @@ using namespace Isis; static QString PIXEL2MAP_XML = FileName("$ISISROOT/bin/xml/pixel2map.xml").expanded(); - -TEST_F(DefaultCube, FunctionalTestPixel2mapVector) { - +// DefaultCube +// MroCtxCube +TEST_F(MroCtxCube, FunctionalTestPixel2mapVector) { + + // DefaultCube only + //resizeCube(5,5,1); - //QString csvFileName = tempDir.path() + "/vect.csv"; - //QString vrtFileName = tempDir.path() + "/vect.vrt"; - QString csvFileName = "P2Mvect.csv"; - QString vrtFileName = "P2Mvect.vrt"; + QString csvFileName = tempDir.path() + "/vect.csv"; + QString vrtFileName = tempDir.path() + "/vect.vrt"; + //QString csvFileName = "/Users/alf/gitwrk/ISIS3dev-b/build/DefaultCube.csv"; + //QString vrtFileName = "/Users/alf/gitwrk/ISIS3dev-b/build/DefaultCube.vrt"; QFile csvFile( csvFileName ); QFile vrtFile( vrtFileName ); //QString outCubeFileName = tempDir.path() + "/outTemp.cub"; - QVector args = {"tovect="+csvFile.fileName(), "from="+ testCube->fileName()}; + + QVector args = {"TOVECT="+csvFile.fileName(), "FROM="+ testCube->fileName() }; + + //QVector args = {"tovect="+csvFile.fileName(), "from=/Users/alf/gitwrk/ISIS3dev-b/isis/tests/data/mroCtxImage/ctxTestImage.cub"}; UserInterface options(PIXEL2MAP_XML, args); @@ -45,6 +52,13 @@ TEST_F(DefaultCube, FunctionalTestPixel2mapVector) { FAIL() << "Unable to open image: " << e.what() << std::endl; } + // pre-TEST: Check that we have no null values in the cube + std::unique_ptr hist (testCube->histogram()); + + EXPECT_EQ(hist->ValidPixels(), testCube->sampleCount()*testCube->lineCount()); + EXPECT_EQ(hist->NullPixels(), 0); + + // TEST 1a: Check we have both csv and vrt output files FileName csvFileOut( csvFileName ); @@ -64,9 +78,11 @@ TEST_F(DefaultCube, FunctionalTestPixel2mapVector) { EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[2], "pixelvalue"); EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[3], "geom"); - std::cout << "Number of rows in the CSV: " << csvout.size() << '\n'; + //std::cout << "Number of rows in the CSV: " << csvout.size() << '\n'; //std::cout << testCube.sampleCount() << '\n'; + // The number of lines must be equal to the number of pixels EXPECT_EQ(testCube->sampleCount()*testCube->lineCount(), csvout.rows()-1); + } From 733d6916d2757d011f34cd5991651f158dc91f72 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Fri, 23 Aug 2024 10:19:49 -0700 Subject: [PATCH 13/21] added the unit test cpp file in the tests folder --- isis/tests/UnitTestProcessGroundPolygons.cpp | 63 ++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 isis/tests/UnitTestProcessGroundPolygons.cpp diff --git a/isis/tests/UnitTestProcessGroundPolygons.cpp b/isis/tests/UnitTestProcessGroundPolygons.cpp new file mode 100644 index 0000000000..e16eaf5eb0 --- /dev/null +++ b/isis/tests/UnitTestProcessGroundPolygons.cpp @@ -0,0 +1,63 @@ +#include "ImagePolygon.h" +#include "LineManager.h" +#include "PolygonTools.h" +#include "Preference.h" +#include "ProgramLauncher.h" +#include "Pvl.h" +#include "geos/geom/Point.h" +#include "geos/geom/MultiPolygon.h" +#include "geos/geom/CoordinateSequence.h" + +#include + +#include "CameraFixtures.h" +#include "TempFixtures.h" + +#include "ProcessGroundPolygons.h" + +using namespace Isis; + +TEST_F(DefaultCube, UnitTestVectorize) { + + /* + ImagePolygon poly; + try { + poly.Create(*testCube); + } + catch(IException &e) { + QString msg = "Cannot create polygon for [" + testCube->fileName() + "]"; + throw IException(IException::Programmer, msg, _FILEINFO_); + } + ASSERT_EQ(4517, poly.numVertices()); + + + geos::geom::Geometry* boundary = poly.Polys()->getEnvelope().release(); + geos::geom::Point* centroid = poly.Polys()->getCentroid().release(); + */ + + Isis::ProcessGroundPolygons g_processGroundPolygons; + geos::geom::Geometry* groundpixel; + //geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); + + std::vector lons = {255.645377, 256.146301, 256.146301, 255.645377}; + std::vector lats = {9.928429, 9.928429, 10.434929, 10.434929}; + std::vector dns = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10}; + + groundpixel = g_processGroundPolygons.Vectorize(lats, lons, dns); + + // Check that the geometry is valid + EXPECT_EQ( groundpixel->isValid(), 1 ); + EXPECT_EQ( groundpixel->getNumPoints(), ); + + //geos::geom::CoordinateSequence coordArray = *(boundary->getCoordinates().release()); + + //for (size_t i = 0; i < coordArray.getSize(); i++) { + // EXPECT_NEAR(lons[i], coordArray.getAt(i).x, 1e-6); + // EXPECT_NEAR(lats[i], coordArray.getAt(i).y, 1e-6); + //} + + //EXPECT_NEAR(255.895201, centroid->getX(), 1e-6); + //EXPECT_NEAR(10.182391, centroid->getY(), 1e-6); + + +} \ No newline at end of file From 1b241a90e8683c4656c2dbae0c455a19a989a9e1 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Fri, 23 Aug 2024 13:55:41 -0700 Subject: [PATCH 14/21] added new test, fixed code in case of 360 crossing --- .zenodo.json | 5 +++ AUTHORS.rst | 2 +- isis/src/base/apps/pixel2map/pixel2map.cpp | 2 +- .../ProcessGroundPolygons.cpp | 20 ++++----- .../ProcessGroundPolygons.h | 4 +- isis/tests/UnitTestProcessGroundPolygons.cpp | 43 ++++++++++++++++--- 6 files changed, 55 insertions(+), 21 deletions(-) diff --git a/.zenodo.json b/.zenodo.json index bb5af05e1c..f4e0f64212 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -166,6 +166,11 @@ "affiliation": "United States Geological Survey, Astro Geology Science Center", "name": "Fergason, Robin" }, + { + "affiliation": "Italian National Institute for Astrophysics (INAF), Isituto di Astrofisica e Planetologia Spaziali (IAPS)", + "name": "Frigeri, Alessandro", + "orcid": "0000-0002-9140-3977" + }, { "name": "Gaddis, Lisa" }, diff --git a/AUTHORS.rst b/AUTHORS.rst index d564245b80..e3330cd117 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -176,4 +176,4 @@ Integrated Software for Imagers and Spectrometers Contributors ----- This list was generated from the .zenodo.json file by running the -isis/scripts/zenodo_to_authors.py Python program. \ No newline at end of file +isis/scripts/zenodo_to_authors.py Python program. diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp index 6facde78c7..f0ecfcc191 100644 --- a/isis/src/base/apps/pixel2map/pixel2map.cpp +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -526,7 +526,7 @@ namespace Isis { } // rasterize this ifov and clear vectors for next ifov // add Vectorize method - GndPixel = g_processGroundPolygons.Vectorize(lat, lon, dns); + GndPixel = g_processGroundPolygons.Vectorize(lat, lon); // Using back() function to retrieve the last element //float pixelvalue = dns.back(); diff --git a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp index d031f151cc..ff2cb01716 100644 --- a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp +++ b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp @@ -109,20 +109,21 @@ namespace Isis { /** * This method gets called from the application with the lat/lon - * vertices of a polygon along with a vector of values. + * vertices of a polygon. * - * it returns a geos::geom::Geometry* WKT representation of the + * it returns a geos::geom::Geometry* representation of the * geometry * * @param lat * @param lon - * @param values + * */ geos::geom::Geometry* ProcessGroundPolygons::Vectorize(std::vector &lat, - std::vector &lon, - std::vector &values) + std::vector &lon) + //std::vector &values) { + // Decide if we need to split the poly on the 360 boundry // Yes, we can do this better. The lat and lon vectors should be passed in as polygons, but @@ -157,7 +158,6 @@ geos::geom::Geometry* ProcessGroundPolygons::Vectorize(std::vector &lat, // See leading comment } - delete crossingPoly; if (splitPoly != NULL) { @@ -178,12 +178,8 @@ geos::geom::Geometry* ProcessGroundPolygons::Vectorize(std::vector &lat, tlat.push_back(llcoords->getAt(cord).y); } - - Convert(tlat, tlon); - //ProcessPolygons::Rasterize(p_samples, p_lines, values); } return splitPoly; - delete splitPoly; } } else { // if does not crosses @@ -195,10 +191,10 @@ geos::geom::Geometry* ProcessGroundPolygons::Vectorize(std::vector &lat, } pts.add(geos::geom::Coordinate(lon[0], lat[0])); - geos::geom::Polygon *crossingPoly = Isis::globalFactory->createPolygon( + geos::geom::Polygon *singlePoly = Isis::globalFactory->createPolygon( globalFactory->createLinearRing(pts)).release(); - return crossingPoly; + return singlePoly; //ProcessPolygons::Rasterize(p_samples, p_lines, values); } diff --git a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h index 085c0e9327..44ef4adf3d 100644 --- a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h +++ b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.h @@ -75,8 +75,8 @@ namespace Isis { int &band, double &value); geos::geom::Geometry* Vectorize (std::vector &lat, - std::vector &lon, - std::vector &values); + std::vector &lon); + //std::vector &values); void EndProcess(); void Finalize(); diff --git a/isis/tests/UnitTestProcessGroundPolygons.cpp b/isis/tests/UnitTestProcessGroundPolygons.cpp index e16eaf5eb0..58b237485f 100644 --- a/isis/tests/UnitTestProcessGroundPolygons.cpp +++ b/isis/tests/UnitTestProcessGroundPolygons.cpp @@ -17,7 +17,8 @@ using namespace Isis; -TEST_F(DefaultCube, UnitTestVectorize) { +// Default test to check integrity of the geometry +TEST( UnitTestVectorize, Default ) { /* ImagePolygon poly; @@ -41,13 +42,17 @@ TEST_F(DefaultCube, UnitTestVectorize) { std::vector lons = {255.645377, 256.146301, 256.146301, 255.645377}; std::vector lats = {9.928429, 9.928429, 10.434929, 10.434929}; - std::vector dns = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10}; + //std::vector dns = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10}; - groundpixel = g_processGroundPolygons.Vectorize(lats, lons, dns); + groundpixel = g_processGroundPolygons.Vectorize(lats, lons); // Check that the geometry is valid EXPECT_EQ( groundpixel->isValid(), 1 ); - EXPECT_EQ( groundpixel->getNumPoints(), ); + EXPECT_EQ( groundpixel->isPolygonal(), 1 ); + EXPECT_EQ( groundpixel->getGeometryType(), "Polygon"); + EXPECT_EQ( groundpixel->getNumGeometries(), 1); + EXPECT_EQ( groundpixel->getNumPoints(), lons.size() + 1 ); + //geos::geom::CoordinateSequence coordArray = *(boundary->getCoordinates().release()); @@ -60,4 +65,32 @@ TEST_F(DefaultCube, UnitTestVectorize) { //EXPECT_NEAR(10.182391, centroid->getY(), 1e-6); -} \ No newline at end of file +}; + +TEST( UnitTestVectorize, Crosses360 ) { + + Isis::ProcessGroundPolygons g_processGroundPolygons; + geos::geom::Geometry* groundpixel; + //geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); + + + + std::vector lons = {359.0, 1.0, 1.0, 359.0, 359.0}; + std::vector lats = { 0.0, 0.0, 1.0, 1.0, 0.0}; + + + /* + std::vector lons = {350, 351, 351, 350}; + std::vector lats = {0 , 0, 1, 1}; + */ + + groundpixel = g_processGroundPolygons.Vectorize(lats, lons); + + // Check that the geometry is valid + EXPECT_EQ( groundpixel->isValid(), 1 ); + EXPECT_EQ( groundpixel->isPolygonal(), 1 ); + EXPECT_EQ( groundpixel->getGeometryType(), "MultiPolygon"); + EXPECT_EQ( groundpixel->getNumGeometries(), 2); + + +}; \ No newline at end of file From 6de8572d3ae9b126ba3b7cef046dac382830f07d Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Fri, 23 Aug 2024 15:43:00 -0700 Subject: [PATCH 15/21] cleanup for PR --- isis/src/base/apps/pixel2map/pixel2map.cpp | 85 +++---------------- .../ProcessGroundPolygons.cpp | 1 - isis/tests/FunctionalTestsPixel2map.cpp | 28 ++---- isis/tests/UnitTestProcessGroundPolygons.cpp | 47 +--------- 4 files changed, 25 insertions(+), 136 deletions(-) diff --git a/isis/src/base/apps/pixel2map/pixel2map.cpp b/isis/src/base/apps/pixel2map/pixel2map.cpp index f0ecfcc191..70e0b4dc19 100644 --- a/isis/src/base/apps/pixel2map/pixel2map.cpp +++ b/isis/src/base/apps/pixel2map/pixel2map.cpp @@ -13,11 +13,10 @@ namespace Isis { static void vectorizePixel(Isis::Buffer &in); // Global variables - static Cube *incube; static Isis::ProcessGroundPolygons g_processGroundPolygons; static Isis::Camera *g_incam; static int g_numIFOVs = 0; - static int g_vectorOut = 0; // to be set bool in future + static int g_vectorOut = 0; static int csamples; static int clines; @@ -27,31 +26,9 @@ namespace Isis { static std::ofstream fout_csv; static QString ogc_SRS; - - // This is the FIRST required function ///////////////////////////////////////////////// - //void pixel2map(UserInterface &ui){ - // // Open the input cube - // //Cube *incube; - // //CubeAttributeInput inAtt = ui.GetInputAttribute("FROM"); - // Cube *inCube = new Cube( ui.GetCubeName("FROM"), "r"); - // - // // Now we got the Cube, we call the SECOND function - // pixel2map(inCube, ui); - //} - - // This is the SECOND required function //////////////////////////////////////////////// - //void pixel2map(Cube *inCube, UserInterface &ui){ + void pixel2map(UserInterface &ui, Pvl *appLog){ - //Camera *g_incam; - //Camera g_incam; - //Pvl userMap; - - - // Get the map projection file provided by the user - // UserInterface &ui = Application::GetUserInterface(); - - //Pvl userMap.read(ui.GetFileName("MAP")); Pvl userMap(ui.GetFileName("MAP")); PvlGroup &userGrp = userMap.findGroup("Mapping", Pvl::Traverse); @@ -69,7 +46,6 @@ namespace Isis { } } - if (ui.GetString("FOVRANGE") == "INSTANTANEOUS") { g_numIFOVs = 1; } @@ -85,8 +61,6 @@ namespace Isis { PvlGroup camGrp; QString lastBandString; - - // Get the combined lat/lon range for all input cubes int bands = 1; for (int i = 0; i < list.size(); i++) { @@ -105,10 +79,9 @@ namespace Isis { csamples = g_incam->Samples(); clines = g_incam->Lines(); - + // Preparing the OGC IAU code for the vector data being generated Spice spi(icube); ogc_SRS = "IAU:" + Isis::toString(spi.target()->naifBodyCode()) + "00"; - //cout << ogc_SRS << endl; // Make sure it is not the sky if (g_incam->target()->isSky()) { @@ -310,11 +283,9 @@ namespace Isis { g_incam = NULL; } - Pvl pvl; pvl.addGroup(userGrp); - // If there is only one input cube, we need to attach an AlphaCube to the outputs. if (list.size() == 1) { Cube parent(list[0].toString()); @@ -371,9 +342,7 @@ namespace Isis { if ( ui.WasEntered("TOVECT") ) { ofstream fout_vrt; - - cout << "==========Pixel Type: " << PixelTypeName(cube.pixelType()) << " code:" << cube.pixelType() << endl; - + QString outFileNameVRT = FileName( outvect.toLatin1().data() ).removeExtension().addExtension("vrt").expanded(); QString layer_name = FileName( outvect.toLatin1().data() ).baseName(); QString csv_fname = FileName( outvect.toLatin1().data() ).name(); @@ -393,9 +362,7 @@ namespace Isis { fout_vrt << "" << endl; fout_vrt.close(); - - - + // write the header fout_csv.open( outvect.toLatin1().data() ); fout_csv << "sampleno" << "," << "lineno" << "," << "pixelvalue" << "," << "geom" << endl; @@ -406,6 +373,7 @@ namespace Isis { processBrick.StartProcess(vectorizePixel); processBrick.EndProcess(); fout_csv.close(); + } // IF TOVECT } @@ -413,7 +381,6 @@ namespace Isis { if ( ui.WasEntered("TO") ) { // When there is only one input cube, we want to propagate IsisCube labels to output cubes if (list.size() == 1) { - // g_incam->SetImage(csamples,clines); // Note that polygons and original labels are not propagated g_processGroundPolygons.PropagateLabels(list[0].toString()); // Tell Process which tables we want to propagate @@ -431,9 +398,6 @@ namespace Isis { } // void pixel2map - - - /** * This method uses the ProcessGroundPolygons object to rasterize each * pixel in the given buffer. @@ -490,26 +454,16 @@ namespace Isis { // Setup the WKT writer geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); - - //cout << "dns Size: " << in.size() << endl; // With one band at input, size will be 1 for (int i = 0; i < in.size(); i++) { // adds the element at the end of the vector - if(IsNullPixel(in[i])){ - dns.push_back( 999.999 ); - } - else { - dns.push_back(in[i]); - } - } + dns.push_back(in[i]); + } int l = in.Line(); int s = in.Sample(); - // DO: This needs to be done for each band for band dependent instruments - // Note: This can slow this down a lot - // Get the IFOVs in lat/lon space PixelFOV fov; QList< QList< QPointF > > fovVertices = fov.latLonVertices(*g_incam, l, s, g_numIFOVs); @@ -524,33 +478,22 @@ namespace Isis { lat.push_back(fovVertices[ifov][point].x()); lon.push_back(fovVertices[ifov][point].y()); } - // rasterize this ifov and clear vectors for next ifov - // add Vectorize method + + // vectorize this ifov and clear coordinate vectors for next ifov GndPixel = g_processGroundPolygons.Vectorize(lat, lon); - // Using back() function to retrieve the last element - //float pixelvalue = dns.back(); - - //QString myvalue = printf ("%4.2f ", dns[0]); - //QString myvalue = QString("%4.2f").arg(dns[0]); QString v = QString::number(dns[0]); - // Generate only non null pixel + // Generate vectors of only non null pixel if ( dns[0] != Isis::Null ) { fout_csv << s << "," << l << "," << dns[0] << ",\"" << wkt->write(GndPixel) << "\"" << endl; } - - //fout_csv << s << "," << l << "," << v << ",\"" << wkt->write(GndPixel) << "\"" << endl; - + lat.clear(); - lon.clear(); - - + lon.clear(); } - } - - + } } // vectorizePixel } // namespace Isis diff --git a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp index ff2cb01716..60c03752ec 100644 --- a/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp +++ b/isis/src/base/objs/ProcessGroundPolygons/ProcessGroundPolygons.cpp @@ -195,7 +195,6 @@ geos::geom::Geometry* ProcessGroundPolygons::Vectorize(std::vector &lat, globalFactory->createLinearRing(pts)).release(); return singlePoly; - //ProcessPolygons::Rasterize(p_samples, p_lines, values); } } diff --git a/isis/tests/FunctionalTestsPixel2map.cpp b/isis/tests/FunctionalTestsPixel2map.cpp index cbb6978e57..1862fffed0 100644 --- a/isis/tests/FunctionalTestsPixel2map.cpp +++ b/isis/tests/FunctionalTestsPixel2map.cpp @@ -23,26 +23,16 @@ using namespace Isis; static QString PIXEL2MAP_XML = FileName("$ISISROOT/bin/xml/pixel2map.xml").expanded(); -// DefaultCube -// MroCtxCube TEST_F(MroCtxCube, FunctionalTestPixel2mapVector) { - - // DefaultCube only - //resizeCube(5,5,1); - + QString csvFileName = tempDir.path() + "/vect.csv"; QString vrtFileName = tempDir.path() + "/vect.vrt"; - //QString csvFileName = "/Users/alf/gitwrk/ISIS3dev-b/build/DefaultCube.csv"; - //QString vrtFileName = "/Users/alf/gitwrk/ISIS3dev-b/build/DefaultCube.vrt"; QFile csvFile( csvFileName ); QFile vrtFile( vrtFileName ); - //QString outCubeFileName = tempDir.path() + "/outTemp.cub"; QVector args = {"TOVECT="+csvFile.fileName(), "FROM="+ testCube->fileName() }; - //QVector args = {"tovect="+csvFile.fileName(), "from=/Users/alf/gitwrk/ISIS3dev-b/isis/tests/data/mroCtxImage/ctxTestImage.cub"}; - UserInterface options(PIXEL2MAP_XML, args); try { @@ -52,7 +42,7 @@ TEST_F(MroCtxCube, FunctionalTestPixel2mapVector) { FAIL() << "Unable to open image: " << e.what() << std::endl; } - // pre-TEST: Check that we have no null values in the cube + // pre-TEST: Check that we have no null values in the test cube std::unique_ptr hist (testCube->histogram()); EXPECT_EQ(hist->ValidPixels(), testCube->sampleCount()*testCube->lineCount()); @@ -60,14 +50,12 @@ TEST_F(MroCtxCube, FunctionalTestPixel2mapVector) { // TEST 1a: Check we have both csv and vrt output files - - FileName csvFileOut( csvFileName ); + FileName csvFileOut( csvFileName ); EXPECT_TRUE(csvFileOut.fileExists()); FileName vrtFileOut( vrtFileName ); EXPECT_TRUE(vrtFileOut.fileExists()); - // TEST 1b: Check the output csv file header - + // TEST 1b: Check the output csv file header CSVReader::CSVAxis csvLine; CSVReader csvout = CSVReader( csvFileName , false, 0, ','); @@ -78,11 +66,11 @@ TEST_F(MroCtxCube, FunctionalTestPixel2mapVector) { EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[2], "pixelvalue"); EXPECT_PRED_FORMAT2(AssertQStringsEqual, csvLine[3], "geom"); - //std::cout << "Number of rows in the CSV: " << csvout.size() << '\n'; - //std::cout << testCube.sampleCount() << '\n'; - // The number of lines must be equal to the number of pixels EXPECT_EQ(testCube->sampleCount()*testCube->lineCount(), csvout.rows()-1); - } + + + + diff --git a/isis/tests/UnitTestProcessGroundPolygons.cpp b/isis/tests/UnitTestProcessGroundPolygons.cpp index 58b237485f..c4672b4405 100644 --- a/isis/tests/UnitTestProcessGroundPolygons.cpp +++ b/isis/tests/UnitTestProcessGroundPolygons.cpp @@ -19,30 +19,12 @@ using namespace Isis; // Default test to check integrity of the geometry TEST( UnitTestVectorize, Default ) { - - /* - ImagePolygon poly; - try { - poly.Create(*testCube); - } - catch(IException &e) { - QString msg = "Cannot create polygon for [" + testCube->fileName() + "]"; - throw IException(IException::Programmer, msg, _FILEINFO_); - } - ASSERT_EQ(4517, poly.numVertices()); - - - geos::geom::Geometry* boundary = poly.Polys()->getEnvelope().release(); - geos::geom::Point* centroid = poly.Polys()->getCentroid().release(); - */ - + Isis::ProcessGroundPolygons g_processGroundPolygons; geos::geom::Geometry* groundpixel; - //geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); std::vector lons = {255.645377, 256.146301, 256.146301, 255.645377}; std::vector lats = {9.928429, 9.928429, 10.434929, 10.434929}; - //std::vector dns = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10}; groundpixel = g_processGroundPolygons.Vectorize(lats, lons); @@ -52,45 +34,22 @@ TEST( UnitTestVectorize, Default ) { EXPECT_EQ( groundpixel->getGeometryType(), "Polygon"); EXPECT_EQ( groundpixel->getNumGeometries(), 1); EXPECT_EQ( groundpixel->getNumPoints(), lons.size() + 1 ); - - - //geos::geom::CoordinateSequence coordArray = *(boundary->getCoordinates().release()); - - //for (size_t i = 0; i < coordArray.getSize(); i++) { - // EXPECT_NEAR(lons[i], coordArray.getAt(i).x, 1e-6); - // EXPECT_NEAR(lats[i], coordArray.getAt(i).y, 1e-6); - //} - - //EXPECT_NEAR(255.895201, centroid->getX(), 1e-6); - //EXPECT_NEAR(10.182391, centroid->getY(), 1e-6); - - + }; TEST( UnitTestVectorize, Crosses360 ) { Isis::ProcessGroundPolygons g_processGroundPolygons; geos::geom::Geometry* groundpixel; - //geos::io::WKTWriter *wkt = new geos::io::WKTWriter(); - - std::vector lons = {359.0, 1.0, 1.0, 359.0, 359.0}; std::vector lats = { 0.0, 0.0, 1.0, 1.0, 0.0}; - - /* - std::vector lons = {350, 351, 351, 350}; - std::vector lats = {0 , 0, 1, 1}; - */ - groundpixel = g_processGroundPolygons.Vectorize(lats, lons); // Check that the geometry is valid EXPECT_EQ( groundpixel->isValid(), 1 ); EXPECT_EQ( groundpixel->isPolygonal(), 1 ); EXPECT_EQ( groundpixel->getGeometryType(), "MultiPolygon"); - EXPECT_EQ( groundpixel->getNumGeometries(), 2); - - + EXPECT_EQ( groundpixel->getNumGeometries(), 2); }; \ No newline at end of file From 2664263ac20b13729939798978de3e14fdf1e039 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Mon, 26 Aug 2024 16:08:00 -0700 Subject: [PATCH 16/21] updated CHANGELOG and docs --- CHANGELOG.md | 12 ++++++++++++ isis/src/base/apps/pixel2map/pixel2map.xml | 4 ++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aba827254e..517bf88f8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,18 @@ release. ## [Unreleased] +### Added +- Added TOVECT output parameter which generate a geospatial CSV file with a VRT metadata sidecar file [#5571](https://github.com/DOI-USGS/ISIS3/issues/5571) +- Added Vectorize to ProcessGroundPolygon library +- Added gtest files for the app and unit test + +## Changed +- Refactored the pixel2map app +- Updated pixel2map documentation + +## Fixed + + ## [8.3.0] - 2024-08-16 ### Added diff --git a/isis/src/base/apps/pixel2map/pixel2map.xml b/isis/src/base/apps/pixel2map/pixel2map.xml index 2f6a6bea86..bbefbb8efa 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.xml +++ b/isis/src/base/apps/pixel2map/pixel2map.xml @@ -448,12 +448,12 @@ filename output - Null + output.csv Geospatial CSV/BVRT Vector File - The output file is a comma-delimited file and a VRT sidecar file with geospatial metadata. The coordinate are spherical, unprojected. This file is interoperable with Open Gis Consortium (OGC) compatible Geospatial tools. + The output file is a comma-delimited file (.csv). An XML VRT sidecar file with geospatial metadata will be generated automatically. The vector pixel will include the values of the first band of the input cube. The coordinate are spherical, unprojected. This file is interoperable with Open Gis Consortium (OGC) compatible geospatial tools and desktop GIS. TO From b91366fe42fb6b756a2c109978467c6475f6d743 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Mon, 26 Aug 2024 16:19:54 -0700 Subject: [PATCH 17/21] updated institution info --- .zenodo.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.zenodo.json b/.zenodo.json index f4e0f64212..9838a65b98 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -167,7 +167,7 @@ "name": "Fergason, Robin" }, { - "affiliation": "Italian National Institute for Astrophysics (INAF), Isituto di Astrofisica e Planetologia Spaziali (IAPS)", + "affiliation": "Italian National Institute for Astrophysics (INAF), Istituto di Astrofisica e Planetologia Spaziali (IAPS), Rome, Italy", "name": "Frigeri, Alessandro", "orcid": "0000-0002-9140-3977" }, From c94c91935ee2db5b75275f370c1ae700a3b55185 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Fri, 30 Aug 2024 11:15:38 -0700 Subject: [PATCH 18/21] removed commented-out lines in header --- isis/src/base/apps/pixel2map/pixel2map.h | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/isis/src/base/apps/pixel2map/pixel2map.h b/isis/src/base/apps/pixel2map/pixel2map.h index 350fceb548..8287172ed9 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.h +++ b/isis/src/base/apps/pixel2map/pixel2map.h @@ -12,10 +12,7 @@ #include "PixelFOV.h" #include "ProcessByBrick.h" #include "ProcessGroundPolygons.h" -//#include "ProcessRubberSheet.h" -//#include "ProjectionFactory.h" #include "Pvl.h" -//#include "PvlGroup.h" #include "Target.h" #include "Transform.h" @@ -25,29 +22,10 @@ #include "UserInterface.h" -//void PrintMap(); -// Check for docs for GUI helpers -> KEEP and move it to pixel2map.cpp -//std::map GuiHelpers() { -// map helper; -// helper ["PrintMap"] = (void *) PrintMap; -// return helper; -//} - - - - -namespace Isis { - - //extern void pixel2map(Cube* incube, UserInterface &ui); - extern void pixel2map(UserInterface &ui, Pvl *log=nullptr); - //extern void pixel2map(Cube *incube, Pvl &userMap); +extern void pixel2map(UserInterface &ui, Pvl *log=nullptr); - //static void rasterizePixel(Isis::Buffer &in); - //static void vectorizePixel(Isis::Buffer &in); - - /** * @author 2008-02-13 Stacy Alley From b5d4727b7d602e8122641669117efb31d2861c82 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Thu, 5 Sep 2024 11:53:44 +0200 Subject: [PATCH 19/21] removed README.md --- isis/src/base/apps/pixel2map/README.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 isis/src/base/apps/pixel2map/README.md diff --git a/isis/src/base/apps/pixel2map/README.md b/isis/src/base/apps/pixel2map/README.md deleted file mode 100644 index 79c3c83163..0000000000 --- a/isis/src/base/apps/pixel2map/README.md +++ /dev/null @@ -1 +0,0 @@ -pixel2map as of July 2023 From aebfea53207410d508b67aac3976606114a586d7 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Wed, 11 Sep 2024 12:25:06 +0200 Subject: [PATCH 20/21] pixel2map definition re-inserted into Isis namespace (which was deleted during code cleanup) --- isis/src/base/apps/pixel2map/pixel2map.h | 32 +++--------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/isis/src/base/apps/pixel2map/pixel2map.h b/isis/src/base/apps/pixel2map/pixel2map.h index 8287172ed9..93e15cc75e 100755 --- a/isis/src/base/apps/pixel2map/pixel2map.h +++ b/isis/src/base/apps/pixel2map/pixel2map.h @@ -23,36 +23,10 @@ #include "UserInterface.h" - +namespace Isis { + extern void pixel2map(UserInterface &ui, Pvl *log=nullptr); - - -/** - * @author 2008-02-13 Stacy Alley - * - * @internal - * @history 2013-07-30 Stuart C. Sides & Tracie Sucharski Renamed from vim2map - */ - - /** -class pixel2mapForward : public Isis::Transform { - private: - Isis::Camera *p_incam; - Isis::Projection *p_outmap; - - public: - // constructor - pixel2mapForward(const int inputSamples, const int inputLines, Isis::Camera *incam, - const int outputSamples, const int outputLines, Isis::Projection *outmap, - bool trim); - - // destructor - ~pixel2mapForward() {}; - - -}; -**/ -} // namespace Isis +} #endif From 4417d062c1bb0dea61c62c411196a31689ed5871 Mon Sep 17 00:00:00 2001 From: Alessandro Frigeri Date: Thu, 3 Oct 2024 16:40:54 +0200 Subject: [PATCH 21/21] change on testCube path reverted --- isis/tests/CameraFixtures.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isis/tests/CameraFixtures.cpp b/isis/tests/CameraFixtures.cpp index 60b9785ccc..eb8fa8c827 100644 --- a/isis/tests/CameraFixtures.cpp +++ b/isis/tests/CameraFixtures.cpp @@ -185,7 +185,7 @@ namespace Isis { projCubeLabel >> projLabel; testCube = new Cube(); - testCube->fromIsd("tempDir.path() + default.cub", label, isd, "rw"); + testCube->fromIsd(tempDir.path() + "/default.cub", label, isd, "rw"); LineManager line(*testCube); int pixelValue = 1;