Skip to content

Commit

Permalink
OGRGeoJSONWriteLayer::ICreateFeature(): simplify using OGRGeometry::r…
Browse files Browse the repository at this point in the history
…oundCoordinates() and SetPrecision()
  • Loading branch information
rouault committed Mar 6, 2024
1 parent 1a66295 commit 2975e06
Showing 1 changed file with 13 additions and 42 deletions.
55 changes: 13 additions & 42 deletions ogr/ogrsf_frmts/geojson/ogrgeojsonwritelayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,42 +243,32 @@ OGRErr OGRGeoJSONWriteLayer::ICreateFeature(OGRFeature *poFeature)

// Special processing to detect and repair invalid geometries due to
// coordinate precision.
// Normally drivers shouldn't do that as similar code is triggered by
// setting the OGR_APPLY_GEOM_SET_PRECISION=YES configuration option by
// the generic OGRLayer::CreateFeature() code path. But this code predates
// its introduction and RFC99, and can be useful in RFC7946 mode due to
// coordinate reprojection.
OGRGeometry *poOrigGeom = poFeature->GetGeometryRef();
if (OGRGeometryFactory::haveGEOS() &&
oWriteOptions_.nXYCoordPrecision >= 0 && poOrigGeom &&
wkbFlatten(poOrigGeom->getGeometryType()) != wkbPoint &&
IsValid(poOrigGeom))
{
struct CoordinateRoundingVisitor : public OGRDefaultGeometryVisitor
{
const double dfFactor_;
const double dfInvFactor_;

explicit CoordinateRoundingVisitor(int nCoordPrecision)
: dfFactor_(std::pow(10.0, double(nCoordPrecision))),
dfInvFactor_(std::pow(10.0, double(-nCoordPrecision)))
{
}

using OGRDefaultGeometryVisitor::visit;
void visit(OGRPoint *p) override
{
p->setX(std::round(p->getX() * dfFactor_) * dfInvFactor_);
p->setY(std::round(p->getY() * dfFactor_) * dfInvFactor_);
}
};

CoordinateRoundingVisitor oVisitor(oWriteOptions_.nXYCoordPrecision);
const double dfXYResolution =
std::pow(10.0, double(-oWriteOptions_.nXYCoordPrecision));
auto poNewGeom = poFeature == poFeatureToWrite
? poOrigGeom->clone()
: poFeatureToWrite->GetGeometryRef();
bool bDeleteNewGeom = (poFeature == poFeatureToWrite);
poNewGeom->accept(&oVisitor);
OGRGeomCoordinatePrecision sPrecision;
sPrecision.dfXYResolution = dfXYResolution;
poNewGeom->roundCoordinates(sPrecision);
if (!IsValid(poNewGeom))
{
CPLDebug("GeoJSON", "Running MakeValid() to correct an invalid "
CPLDebug("GeoJSON", "Running SetPrecision() to correct an invalid "
"geometry due to reduced precision output");
auto poValidGeom = poNewGeom->MakeValid();
auto poValidGeom =
poOrigGeom->SetPrecision(dfXYResolution, /* nFlags = */ 0);
if (poValidGeom)
{
if (poFeature == poFeatureToWrite)
Expand All @@ -288,25 +278,6 @@ OGRErr OGRGeoJSONWriteLayer::ICreateFeature(OGRFeature *poFeature)
poFeatureToWrite->SetFID(poFeature->GetFID());
}

// It may happen that after MakeValid(), and rounding again,
// we end up with an invalid result. Run MakeValid() again...
poValidGeom->accept(&oVisitor);
if (!IsValid(poValidGeom))
{
auto poValidGeom2 = poValidGeom->MakeValid();
if (poValidGeom2)
{
delete poValidGeom;
poValidGeom = poValidGeom2;
if (!IsValid(poValidGeom))
{
// hopefully should not happen
CPLDebug("GeoJSON",
"... still not valid! Giving up");
}
}
}

poFeatureToWrite->SetGeometryDirectly(poValidGeom);
}
}
Expand Down

0 comments on commit 2975e06

Please sign in to comment.