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

Add ImplHelper::ValidOp Module to Provide Uniform Validity Checks #271

Merged
merged 7 commits into from Oct 5, 2021

Conversation

keithdoggett
Copy link
Member

@keithdoggett keithdoggett commented Aug 3, 2021

Summary

Implements ImplHelper::ValidOp which provides implementations of the valid? and invalid_reason methods based on simple geometric predicates.

Change summary:

  • Implement ImplHelper::ValidOp
  • Override ValidOp for cartesian polygons and use the GeometryGraph to implement the checks.
  • Add test/common/validity_test to ensure uniform validity across all implementation types.
  • Replace validate_geometry with prepare_geometry and move any relevant validations to the constructor.
    • These relevant validations are things like a LinearRing having enough points that GEOS will raise for so we have to also.
    • prepare_geometry will do the handy things that validate_geometry did like closing rings and ensuring points are in a projection area.

Other Information

Tests are currently failing because of the spherical factory

There are still some open issues that need to be figured out before we can merge. The most pressing of which is the spherical implementation.

TODOS:

  • Implement geometric predicates in the spherical factory so that polygons can be validated (currently they cannot be).
  • Make sure we like the structure of how classes can override their own checks from ValidOp. It seems a little clunky in cartesian polygons right now because a lot of the code is copied.
  • Replace more of the overridden cartesian ValidOp methods with graph implementations. Once we've determined that the overriding structure makes sense I'll add more.
  • Determine what to do with factory options like uses_lenient_multipolygon_assertions and uses_lenient_assertions (this may be part of @BuonOmo's validity PR that provides safe and unsafe versions of methods).
  • Determine if all cartesian geometries should implement graph and re-implement some predicates with it (could be done later).

…idity checking of geometries.

The ValidOp module provides methods based on simple geometric predicates to determine validity for a geometry and can be used as a fallback or overridden.
The module can be overriden fully (in the case of Cartesian polygons) or just by implementing #invalid_reason (FFI and CAPI factories).

Removes #validate_geometry from all classes and replaces them with #prepare_geometry. Any required validations were moved to the constructors.

Adds the ValidityTest module to test/common to ensure that all classes of geometries validate in the same way.
Copy link
Member

@BuonOmo BuonOmo left a comment

Choose a reason for hiding this comment

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

I think the way ValidOp is included is fine. As discussed in one of my comments, we can just override leaf methods (i.e. the one that does the final check) to have something more accurate per implementation when needed.

If some method is not a leaf and we need to override a part of it, we still can change the parent method, to make sure we always have a minimal overriding part.

Also, that has been a lot of work you've done on that validity stuff, thank you very much! It is a pleasure reading all of it 🙂

Comment on lines 130 to 131
return ImplHelper::TopologyErrors::UNCLOSED_RING unless exterior_ring.is_closed?
return ImplHelper::TopologyErrors::UNCLOSED_RING unless interior_rings.all?(&:is_closed?)
Copy link
Member

Choose a reason for hiding this comment

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

When i see the is_closed usage there, I feel like we'll have some trouble rebase with the master branch if we wait too much

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah once it gets merged I can go back and change it.

lib/rgeo/impl_helper/valid_op.rb Outdated Show resolved Hide resolved
lib/rgeo/impl_helper/valid_op.rb Outdated Show resolved Hide resolved
lib/rgeo/impl_helper/valid_op.rb Outdated Show resolved Hide resolved
Comment on lines +53 to +54
# TODO: should we replace with graph.incident_edges.length == segments.length
# since graph isn't used elsewhere yet it might be more overhead.
Copy link
Member

Choose a reason for hiding this comment

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

Not 100% sure I get your point there ^^

Copy link
Member Author

Choose a reason for hiding this comment

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

The same simplicity check (self-intersection) can be performed by creating the GeometryGraph of the LineString and doing the described comparison. But doing the check with graph will be slower since it has to perform an intersection check and then link all of the nodes whereas the current implementation only does an intersection check.

And since graph is not used elsewhere in any LineString method I figured the additional overhead is not necessary, but I could change it if we think it's better to do so.

lib/rgeo/cartesian/feature_methods.rb Outdated Show resolved Hide resolved
lib/rgeo/geos/ffi_feature_methods.rb Outdated Show resolved Hide resolved
lib/rgeo/impl_helper/basic_line_string_methods.rb Outdated Show resolved Hide resolved
lib/rgeo/impl_helper/valid_op.rb Show resolved Hide resolved
test/common/validity_tests.rb Outdated Show resolved Hide resolved
@BuonOmo BuonOmo assigned keithdoggett and unassigned BuonOmo Aug 6, 2021
@BuonOmo BuonOmo mentioned this pull request Aug 30, 2021
12 tasks
BuonOmo and others added 4 commits September 20, 2021 10:49
ValidOp is to be included in feature classes and has the invalid_reason and valid? methods, as well as feature type specific methods that walk through the validity flow for each
geometry type.

ValidOpHelpers is a collection of functions where an object is passed to them. These perform the specific checks and return the invalid reason if applicable.

Also added overrides for both modules for cartesian functions.
…nd fix tests, ValidOp so the spherical factory passes validity checks
@BuonOmo
Copy link
Member

BuonOmo commented Oct 3, 2021

Determine what to do with factory options like uses_lenient_multipolygon_assertions and uses_lenient_assertions (this may be part of @BuonOmo's validity PR that provides safe and unsafe versions of methods).

I'll definitely do that bit.

In fact I think we're ready to merge, since what is left is either optimisation, or spherical support. By merging we'll be able to split that job in many and have me and contributors help you :)


private

# TODO: replace with better algorithm
Copy link
Member

Choose a reason for hiding this comment

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

This should be translated into an issue I think :)

Copy link
Member Author

Choose a reason for hiding this comment

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

@keithdoggett keithdoggett merged commit ed8b898 into validity-handling Oct 5, 2021
@keithdoggett keithdoggett deleted the uniform-validity branch October 5, 2021 01:52
@keithdoggett keithdoggett mentioned this pull request Oct 5, 2021
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.

None yet

2 participants