diff --git a/isis/src/base/objs/GisGeometry/GisGeometry.cpp b/isis/src/base/objs/GisGeometry/GisGeometry.cpp index ab1e870e6b..b64ec8b7e5 100644 --- a/isis/src/base/objs/GisGeometry/GisGeometry.cpp +++ b/isis/src/base/objs/GisGeometry/GisGeometry.cpp @@ -207,15 +207,25 @@ namespace Isis { * * First determines if it contains a geometry and then validates with the * GEOS toolkit. - * - * @return bool True if valid, false if invalid or non-existant - */ + * + * @return bool True if valid, false if invalid or non-existant + * + * @history 2018-07-29 Kris Becker - If the geometry is invalid, it throws an + * exception. Catch all exceptions an return proper + * status + */ bool GisGeometry::isValid() const { if (!isDefined()) { return (false); } - - return (1 == GEOSisValid(this->m_geom)); + + int valid(0); + try { + valid = GEOSisValid(this->m_geom); + } catch (...) { + valid = 0; + } + return (1 == valid); } @@ -601,9 +611,35 @@ namespace Isis { double ratio = inCommon->area() / this->area(); return (ratio); } + - - /** +/** + * @brief Compute a buffer around an existing geometry + * + * Add a buffer around a geometry with the defined enlargement factor. It is + * common to use this as buffer(0) to fix geometries with self-intersections. + * These cases are often identified by calling isValid() and getting a false + * value returned. + * + * @author 2018-07-29 Kris Becker + * + * @param width With to enlarge or shrink polygon + * @param quadsegs Numnber of segments to define a circle on corners + * + * @return GisGeometry* Pointer to new GisGeometry with buffer applied + */ + GisGeometry *GisGeometry::buffer(const double width,const int quadsegs) const { + // If there is no geometry, return a null geometry + if ( !isDefined()) { + return (new GisGeometry()); + } + + // Create the buffer around the geom + GEOSGeometry *geom = GEOSBuffer(m_geom, width, quadsegs); + return (new GisGeometry(geom)); + } + + /** * @brief Computes the envelope or bounding box of this geometry * * This method computes the envelope or bounding box of the geometry in this diff --git a/isis/src/base/objs/GisGeometry/GisGeometry.h b/isis/src/base/objs/GisGeometry/GisGeometry.h index f8cad42e59..935db9bf8e 100644 --- a/isis/src/base/objs/GisGeometry/GisGeometry.h +++ b/isis/src/base/objs/GisGeometry/GisGeometry.h @@ -46,6 +46,11 @@ namespace Isis { * ISIS. Fixes #2398. * @history 2016-03-04 Kris Becker - Completed the documentation and implmented the equals() * method. + * @history 2018-07-29 Kris Becker - Added buffer() method; isValid() was + * throwing an exception if the geometry was invalid + * (e.g., self-intersecting geometry), which is now + * trapped and a false condition is properly returned. + * */ class GisGeometry { @@ -99,6 +104,7 @@ namespace Isis { double intersectRatio(const GisGeometry &geom) const; + GisGeometry *buffer(const double width=0.0, const int quadsegs=16) const; GisGeometry *envelope( ) const; GisGeometry *convexHull( ) const; GisGeometry *simplify(const double &tolerance) const; diff --git a/isis/src/base/objs/Strategy/Strategy.cpp b/isis/src/base/objs/Strategy/Strategy.cpp index f262ef1986..f5e8174f2e 100644 --- a/isis/src/base/objs/Strategy/Strategy.cpp +++ b/isis/src/base/objs/Strategy/Strategy.cpp @@ -725,7 +725,18 @@ namespace Isis { // Got a geometry. if ( !geom.isEmpty() ) { - + + // Get decision keys + bool repairGeom = toBool(keys.get("RepairInvalidGeometry", "true")); + QString geomAction = keys.get("InvalidGeometryAction", "disable").toLower(); + if ( !QString("disable error continue").contains(geomAction) ) { + if ( isDebug() ) { + cout << " Invalid value for InvalidGeometryAction (" << geomAction + << ") - set to disable!\n"; + } + geomAction = "disable"; + } + // Process arguments Allows creation specialized geometry as well if ( keys.exists("GisGeometryArgs") ) { QStringList args = keys.allValues("GisGeometryArgs"); @@ -743,7 +754,65 @@ namespace Isis { if ( !geom.isEmpty() ) { QScopedPointer geosgeom(new GisGeometry(geom, GisGeometry::type(gisType))); - if ( geosgeom.isNull() || !geosgeom->isValid() ) return (false); + if ( geosgeom.isNull() ) { + if ( isDebug() ) { + cout << resource->name() << " geometry failed to construct\n"; + } + if ("continue" == geomAction) return (false); + if ( "disable" == geomAction ) { + resource->discard(); + return ( false ); + } + + // Throw an error + QString mess = resource->name() + " failed to construct geometry!"; + throw IException(IException::Programmer, mess, _FILEINFO_); + } + + // Check validity and take appropriate action + if ( !geosgeom->isValid() ) { + + QString geomError = geosgeom->isValidReason(); + if ( isDebug() ) { + cout << " Geometry error: " << geomError << "\n"; + } + + // Attempt repair if requested + if ( repairGeom ) { + if (isDebug()) { + cout << " " << resource->name() << " geometry is invalid..." + << "attempting buffer(0) to fix it!\n"; + } + geosgeom.reset( geosgeom->buffer(0) ); + if ( isDebug() ) { + if (geosgeom.isNull() || !geosgeom->isValid() ) { + cout << " Geomtry could not be repaired!\n"; + } + else { + cout << " Geometry was successfully repaired!\n"; + } + } + } + + // Now check state and take final action regarding a failed + // geometry + + if (geosgeom.isNull() || !geosgeom->isValid() ) { + if ( isDebug() ) { + cout << " All efforts to convert geometry failed!\n"; + } + if ("continue" == geomAction) return (false); + if ( "disable" == geomAction ) { + resource->discard(); + return ( false ); + } + + // Throw an error + QString mess = resource->name() + " failed to construct geomtry - Error: " + + geomError; + throw IException(IException::Programmer, mess, _FILEINFO_); + } + } npointsOrg = npoints = geosgeom->points(); QString gisTolerance = translateKeywordArgs("GisSimplifyTolerance", diff --git a/isis/src/base/objs/Strategy/Strategy.h b/isis/src/base/objs/Strategy/Strategy.h index 5e3e813999..1980dcc6b9 100644 --- a/isis/src/base/objs/Strategy/Strategy.h +++ b/isis/src/base/objs/Strategy/Strategy.h @@ -15,6 +15,7 @@ find files of those names at the top level of this repository. **/ #include // SharedResource and ResourceList typedefs +#include "GisGeometry.h" #include "Resource.h" #include "PvlObject.h" @@ -80,6 +81,12 @@ namespace Isis { * replacements in reverse order fixes this issue. * @history 2016-03-07 Tyler Wilson - Corrected documentation, and created a * unit test to test most of this classe's methods. + * @history 2018-07-29 Kris Becker - Fixed errors in importGeometry() where an + * exception was being thrown when checking for valid + * Geometry. It now checks for this case and runs + * buffer(0) to attempt to fix the geometry. This is + * typically a self-intersection error that can be + * repaired with a buffer(0) operator. */ class Strategy {