Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CompoundCurve: Add validateConstruction method #1164

Merged
merged 1 commit into from
Sep 24, 2024

Conversation

dbaston
Copy link
Member

@dbaston dbaston commented Sep 23, 2024

Resolves #1103

@dbaston dbaston merged commit bf2257a into libgeos:main Sep 24, 2024
28 checks passed
@dr-jts
Copy link
Contributor

dr-jts commented Sep 24, 2024

Would this make sense to add to Geometry.isValid()? And possibly to IsValidOp.

Comment on lines +318 to +319
const CoordinateXY& end = curves[i-1]->getCoordinatesRO()->back<CoordinateXY>();
const CoordinateXY& start = curves[i]->getCoordinatesRO()->front<CoordinateXY>();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I may miss something, but it is not obvious to me that you can't insert an empty curve in a CompoundCurve, in which case back() and front() are returning something invalid. At least if using directly the CompoundCurve::CompoundCurve(std::vector<std::unique_ptr>&& p_curves, const GeometryFactory& gf) constructor. That might be hard/impossible to trigger through WKT. But maybe through WKB ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, this is possible and would crash. Of course it couldn't be so easy.

@dbaston
Copy link
Member Author

dbaston commented Sep 24, 2024

Would this make sense to add to Geometry.isValid()? And possibly to IsValidOp.

I was aiming to handle it consistently with how we handle linear rings, where we simply disallow the construction of a ring with a single point, or a ring that doesn't close.

void
LinearRing::validateConstruction()
{
// Empty ring is valid
if(points->isEmpty()) {
return;
}
if(!LineString::isClosed()) {
throw util::IllegalArgumentException(
"Points of LinearRing do not form a closed linestring"
);
}
if(points->getSize() < MINIMUM_VALID_SIZE) {
std::ostringstream os;
os << "Invalid number of points in LinearRing found "
<< points->getSize() << " - must be 0 or >= " << MINIMUM_VALID_SIZE;
throw util::IllegalArgumentException(os.str());
}
}

@dr-jts
Copy link
Contributor

dr-jts commented Sep 24, 2024

Would this make sense to add to Geometry.isValid()? And possibly to IsValidOp.

I was aiming to handle it consistently with how we handle linear rings, where we simply disallow the construction of a ring with a single point, or a ring that doesn't close.

So would this mean that a WKT or WKB serialization of an invalid compound curve could not be read? Sometimes users like to be able to read a structurally invalid geometry, so the library can be used to test validity and possible allow repair.

I wonder how PostGIS handles this?

@pramsey
Copy link
Member

pramsey commented Sep 24, 2024

Probably the same as LinearRing, which is (wait for it) to disallow non-closed WKT but allow non-closed WKB.

select 'CompoundCurve((0 0, 0 1, 1 1), (1 2, 1 0, 0 0))'::geometry; 
ERROR:  incontinuous compound curve

The point of being liberal in the binary is to allow dump/restore to work, even when highly invalid geometries have found their way into a table.

@rouault
Copy link
Contributor

rouault commented Sep 24, 2024

So would this mean that a WKT or WKB serialization of an invalid compound curve could not be read? Sometimes users like to be able to read a structurally invalid geometry, so the library can be used to test validity and possible allow repair

I was wondering about that too. I've checked that GDAL allows for an extremely tiny gap of 1e-14, which probably is never met in practice.

# 1e-13 difference: rejected:
>>> g = ogr.CreateGeometryFromWkt('CompoundCurve((0 0,1 1),(1 1.0000000000001,3 3))')
ERROR 1: Non contiguous curves
ERROR 6: OGR Error: General Error

# 1e-14 difference: tolerated
>>> g = ogr.CreateGeometryFromWkt('CompoundCurve((0 0,1 1),(1 1.00000000000001,3 3))')
>>> print(g)
COMPOUNDCURVE ((0 0,1 1),(1 1,3 3))

What happens in practice though is when ingesting GML curves, and in particular when the compound curve chaining straight lines with circular portions where the circular portions are not defined as a CircularString, but as a ArcByCenterPoint, where you need to recompute the start and ending points from the center point and the start and end angles, which easily leads to precision issues. But I've ended up compensating for that in the GML import logic itself, because the gap is generally much larger than 1e-14.

@dbaston
Copy link
Member Author

dbaston commented Sep 24, 2024

So would this mean that a WKT or WKB serialization of an invalid compound curve could not be read?

Correct, GEOS does not allow the construction of linear rings that are not closed, linear rings that have fewer than 3 points, or linestrings with a single point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CompoundCurve construction should ensure sections are continuous
4 participants