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

Validity Handling #275

Merged
merged 27 commits into from
Jan 31, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b647059
Added tests that should fail because of issue #218, fixed floating po…
keithdoggett Oct 30, 2020
4da6790
Improve geos multipolygon creation performance (#251)
Quiwin Apr 10, 2021
af7e100
Added Segment#segment_intersection to get points from intersections, …
keithdoggett Jun 30, 2021
59466e9
Move SweeplineIntersector to its own file. Remove Queue, replace obse…
keithdoggett Jul 1, 2021
291f85c
Change delete_if to delete on observed_segments
keithdoggett Jul 6, 2021
92f085f
Add PlanarGraph Implementation
keithdoggett Jul 7, 2021
152d79c
Change HalfEdge#each to cycle, simplify some methods, raise on invali…
keithdoggett Jul 15, 2021
49592e9
Add tests for points and empty linestrings on a geometry graph
keithdoggett Jul 15, 2021
91cd3ec
Change HalfEdge#cycle to and_connected, remove TODOS
keithdoggett Jul 19, 2021
e54e976
Change structure to Cartesian::PlanarGraph, Cartesian::PlanarGraph::H…
keithdoggett Jul 19, 2021
44b965f
Fix indentation
keithdoggett Jul 19, 2021
50c7302
Change HalfEdge#and_connected to return and enumerator instead of set…
keithdoggett Jul 24, 2021
c979c1d
Add ImplHelper::ValidOp module to provide a uniform interface for val…
keithdoggett Aug 3, 2021
bb6ca22
Minor fixes to ValidOp, move Validity testing instance variables to c…
keithdoggett Aug 19, 2021
c2e93eb
Split ValidOp into ValidOp and ValidOpHelpers
keithdoggett Sep 20, 2021
7833e63
Use module_function instead of extend self
keithdoggett Sep 22, 2021
16f61f6
Implement #crosses? and #intersects? between spherical line strings a…
keithdoggett Sep 22, 2021
d36cdf3
Appease Rubocop
keithdoggett Oct 5, 2021
9c30b7c
Make duplicate ring test report as self intersection to match GEOS 3.10
keithdoggett Jan 12, 2022
6e19eab
use ubuntugis-unstable packages
keithdoggett Jan 12, 2022
2827250
Add validity check per method and validity API (#276)
BuonOmo Jan 13, 2022
23d64d2
rebase adjustements
BuonOmo Jan 13, 2022
41228d5
Add geometry validity doc
BuonOmo Jan 14, 2022
c098786
Remove or add more details to TODOs
keithdoggett Jan 15, 2022
05d39d2
Add note about UNCHECKED_METHODS in Geometry-Validity
keithdoggett Jan 15, 2022
fccbf67
Fix make_valid and operator methods
BuonOmo Jan 19, 2022
22dd912
Check validity of geometries in arguments of checked methods
keithdoggett Jan 24, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ jobs:
- jruby
os:
- ubuntu
- windows
# Windows users, feel free to open a PR :)
# - windows
- macos
exclude:
- os: windows # See issue #242, windows support would be welcome.
Expand All @@ -32,16 +33,20 @@ jobs:
- uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
bundler-cache: true
bundler-cache: false
- name: Install Geos (Linux)
if: matrix.os == 'ubuntu'
run: sudo apt-get install libgeos-dev -y
run: |
sudo apt-add-repository ppa:ubuntugis/ubuntugis-unstable
sudo apt-get install libgeos-dev -y
- name: Install Geos (Mac)
if: matrix.os == 'macos'
run: brew install geos
- name: Install Geos (Windows)
if: matrix.os == 'windows'
run: exit 1 # FIXME
run: exit 1
- name: Bundle Install
run: bundle install
- name: Test
run: bundle exec rake
RuboCop:
Expand Down
1 change: 1 addition & 0 deletions .yardopts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
--markup rdoc
--output-dir ./yardoc
lib/**/*.rb
ext/**/*.{c,h}
-
doc/*.md
2 changes: 2 additions & 0 deletions History.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
### Current


* Change `ProjectedLinearRing#is_simple?` method to be uniform across geos versions #228
* Improve large MultiPolygon creation performance (Quiwin) #251
* Major changes to validity handling (see doc/Geometry-Validity.md) #275
* Fix CAPI equality (`==`) comparison on macos by using `GEOSEqualsExact_r` #270

### 2.3.1 / 2021-11-30
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ Here's the current list of available topics:
- [Installing GEOS](https://github.com/rgeo/rgeo/blob/master/doc/Installing-GEOS.md)
- [Factory Compatibility](https://github.com/rgeo/rgeo/blob/master/doc/Factory-Compatibility.md)
- [Which factory should I use?](https://github.com/rgeo/rgeo/blob/master/doc/Which-factory-should-I-use.md)
- [Geometry validity handling](https://github.com/rgeo/rgeo/blob/master/doc/Geometry-Validity.md)
- [Examples](https://github.com/rgeo/rgeo/blob/master/doc/Examples.md)
- [Who uses `rgeo`?](https://github.com/rgeo/rgeo/blob/master/doc/Gallery.md)

Expand Down
77 changes: 32 additions & 45 deletions doc/Examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ This guide shows examples of different operations that can be performed with RGe

## Creating a Factory

The examples below will show different methods for creating a factory with certain properties.
The examples below will show different methods for creating a factory with certain properties.

_Note that these are not exhaustive and you should refer to the docs for a complete list of options._

Expand All @@ -87,7 +87,7 @@ Create a 2D Cartesian factory using a GEOS integration, if available, otherwise
```ruby
factory = RGeo::Cartesian.factory
p factory
#=> #<RGeo::Geos::CAPIFactory srid=0 bufres=1 flags=8>
#=> #<RGeo::Geos::CAPIFactory srid=0 bufres=1 flags=8>
```

### Ruby Cartesian Factory
Expand All @@ -97,7 +97,7 @@ Create a 2D Cartesian factory using a Ruby implementation.
```ruby
factory = RGeo::Cartesian.simple_factory
p factory
#=> #<RGeo::Cartesian::Factory @has_z=false, @has_m=false, @proj4=nil, @coord_sys=nil, @srid=0, @lenient_assertions=false, @buffer_resolution=1>
#=> #<RGeo::Cartesian::Factory @has_z=false, @has_m=false, @proj4=nil, @coord_sys=nil, @srid=0, @buffer_resolution=1>
```

### Spherical Factory
Expand Down Expand Up @@ -164,7 +164,7 @@ p factory

simple_factory = RGeo::Cartesian.simple_factory(has_z_coordinate: true, has_m_coordinate: true)
p simple_factory
#=> #<RGeo::Cartesian::Factory @has_z=true, @has_m=true, @proj4=nil, @coord_sys=nil, @srid=0, @lenient_assertions=false, @buffer_resolution=1>
#=> #<RGeo::Cartesian::Factory @has_z=true, @has_m=true, @proj4=nil, @coord_sys=nil, @srid=0, @buffer_resolution=1>
```

### Specify an SRID
Expand All @@ -179,19 +179,6 @@ p factory
#=> #<RGeo::Geos::CAPIFactory:0x2ad702f454bc srid=3857 bufres=1 flags=8>
```

### Factory that Allows Invalid Geometries

By default, most factories will not allow the creation of invalid geometries and will raise an `RGeo::Error::InvalidGeometry` exception. This can be set with the `:uses_lenient_assertions` parameter.

```ruby
factory = RGeo::Geographic.spherical_factory(uses_lenient_assertions: true)
p factory
#=> #<RGeo::Geographic::Factory:0x000055ae05d98150 @impl_prefix="Spherical", @point_class=RGeo::Geographic::SphericalPointImpl, @line_string_class=RGeo::Geographic::SphericalLineStringImpl, @linear_ring_class=RGeo::Geographic::SphericalLinearRingImpl, @line_class=RGeo::Geographic::SphericalLineImpl, @polygon_class=RGeo::Geographic::SphericalPolygonImpl, @geometry_collection_class=RGeo::Geographic::SphericalGeometryCollectionImpl, @multi_point_class=RGeo::Geographic::SphericalMultiPointImpl, @multi_line_string_class=RGeo::Geographic::SphericalMultiLineStringImpl, @multi_polygon_class=RGeo::Geographic::SphericalMultiPolygonImpl, @support_z=false, @support_m=false, @srid=4055, @proj4=nil>

p factory.property(:uses_lenient_assertions)
#=> true
```

## Points

The zero-dimensional object which all geometries are built on. Points accept floating-point numbers as arguments for x,y(,z,m).
Expand Down Expand Up @@ -257,7 +244,7 @@ pt2 = factory.point(2, 0)
pt3 = factory.point(2, 2)
linestring = factory.line_string([pt1, pt2, pt3])
p linestring
# => #<RGeo::Geos::CAPILineStringImpl "LINESTRING (0.0 0.0, 2.0 0.0, 2.0 2.0)">
# => #<RGeo::Geos::CAPILineStringImpl "LINESTRING (0.0 0.0, 2.0 0.0, 2.0 2.0)">
```


Expand All @@ -271,7 +258,7 @@ This creates the same LineString as above.
factory = RGeo::Cartesian.factory
linestring2 = factory.parse_wkt("LINESTRING (0 0, 2 0, 2 2)")
p linestring2
# => #<RGeo::Geos::CAPILineStringImpl "LINESTRING (0.0 0.0, 2.0 0.0, 2.0 2.0)">
# => #<RGeo::Geos::CAPILineStringImpl "LINESTRING (0.0 0.0, 2.0 0.0, 2.0 2.0)">
# p linestring == linestring2
# => true
```
Expand All @@ -296,14 +283,14 @@ linestring = factory.parse_wkt("LINESTRING (0 0, 2 0, 2 2)")
p linestring.boundary
# => #<RGeo::Geos::CAPIMultiPointImpl "MULTIPOINT ((0.0 0.0), (2.0 2.0))">
```
![Basic LineString](assets/linestring_boundary.png)
![Basic LineString](https://github.com/rgeo/rgeo/raw/master/doc/assets/linestring_boundary.png)

## LinearRings

A LinearRing is a LineString that is both closed and simple. Closed means that the `start_point` and `end_point` are equivalent. Simple means that there are no self-intersections. The first example is a valid LinearRing and the second is an invalid LinearRing.

![Valid LinearRing](assets/linearring_valid.png)
![Invalid LinearRing](assets/linearring_invalid.png)
![Valid LinearRing](https://github.com/rgeo/rgeo/raw/master/doc/assets/linearring_valid.png)
![Invalid LinearRing](https://github.com/rgeo/rgeo/raw/master/doc/assets/linearring_invalid.png)

_Note: Some factories may prevent the creation of invalid LinearRings and raise an `RGeo::Error::InvalidGeometry exception._

Expand All @@ -317,7 +304,7 @@ pt3 = factory.point(4, 4)
pt4 = factory.point(2, 6)
linearring = factory.linear_ring([pt1, pt2, pt3, pt4, pt1])
p linearring
# => #<RGeo::Geos::CAPILinearRingImpl "LINESTRING (2.0 2.0, 4.0 2.0, 4.0 4.0, 2.0 6.0, 2.0 2.0)">
# => #<RGeo::Geos::CAPILinearRingImpl "LINESTRING (2.0 2.0, 4.0 2.0, 4.0 4.0, 2.0 6.0, 2.0 2.0)">
p linearring.closed?
#=> true
p linearring.simple?
Expand Down Expand Up @@ -364,18 +351,18 @@ A Polygon is a geometry composed of an outer ring and, optionally, multiple inte

The following are all examples of valid Polygons.

![Valid Polygon1](assets/polygon_valid1.png)
![Valid Polygon2](assets/polygon_valid2.png)
![Valid Polygon3](assets/polygon_valid3.png)
![Valid Polygon4](assets/polygon_valid4.png)
![Valid Polygon1](https://github.com/rgeo/rgeo/raw/master/doc/assets/polygon_valid1.png)
![Valid Polygon2](https://github.com/rgeo/rgeo/raw/master/doc/assets/polygon_valid2.png)
![Valid Polygon3](https://github.com/rgeo/rgeo/raw/master/doc/assets/polygon_valid3.png)
![Valid Polygon4](https://github.com/rgeo/rgeo/raw/master/doc/assets/polygon_valid4.png)

_Note in the last figure that the two interior rings share point G._

The following are examples of invalid Polygons.

![Invalid Polygon1](assets/polygon_invalid1.png)
![Invalid Polygon2](assets/polygon_invalid2.png)
![Invalid Polygon3](assets/polygon_invalid3.png)
![Invalid Polygon1](https://github.com/rgeo/rgeo/raw/master/doc/assets/polygon_invalid1.png)
![Invalid Polygon2](https://github.com/rgeo/rgeo/raw/master/doc/assets/polygon_invalid2.png)
![Invalid Polygon3](https://github.com/rgeo/rgeo/raw/master/doc/assets/polygon_invalid3.png)

### Creating a Polygon with RGeo Features

Expand Down Expand Up @@ -554,12 +541,12 @@ A MultiLineString is closed if all of its elements are closed.

The following is an example of a simple MultiLineString.

![Simple MultiLineString1](assets/multilinestring_valid1.png)
![Simple MultiLineString1](https://github.com/rgeo/rgeo/raw/master/doc/assets/multilinestring_valid1.png)

The following are examples of non-simple MultiLineStrings.

![Non-Simple MultiLineString1](assets/multilinestring_invalid1.png)
![Non-Simple MultiLineString2](assets/multilinestring_invalid2.png)
![Non-Simple MultiLineString1](https://github.com/rgeo/rgeo/raw/master/doc/assets/multilinestring_invalid1.png)
![Non-Simple MultiLineString2](https://github.com/rgeo/rgeo/raw/master/doc/assets/multilinestring_invalid2.png)

### Create a MultiLineString with RGeo Features

Expand Down Expand Up @@ -602,15 +589,15 @@ A MultiPolygon is a collection of Polygons. A MultiPolygon is simple if all Poly

The following are examples of simple MultiPolygons.

![Simple MultiPolygon1](assets/multipolygon_valid1.png)
![Simple MultiPolygon2](assets/multipolygon_valid2.png)
![Simple MultiPolygon3](assets/multipolygon_valid3.png)
![Simple MultiPolygon1](https://github.com/rgeo/rgeo/raw/master/doc/assets/multipolygon_valid1.png)
![Simple MultiPolygon2](https://github.com/rgeo/rgeo/raw/master/doc/assets/multipolygon_valid2.png)
![Simple MultiPolygon3](https://github.com/rgeo/rgeo/raw/master/doc/assets/multipolygon_valid3.png)

The following are examples of non-simple MultiPolygons.

![Non-simple MultiPolygon1](assets/multipolygon_invalid1.png)
![Non-simple MultiPolygon2](assets/multipolygon_invalid2.png)
![Non-simple MultiPolygon3](assets/multipolygon_invalid3.png)
![Non-simple MultiPolygon1](https://github.com/rgeo/rgeo/raw/master/doc/assets/multipolygon_invalid1.png)
![Non-simple MultiPolygon2](https://github.com/rgeo/rgeo/raw/master/doc/assets/multipolygon_invalid2.png)
![Non-simple MultiPolygon3](https://github.com/rgeo/rgeo/raw/master/doc/assets/multipolygon_invalid3.png)

### Creating a MultiPolygon with RGeo Features

Expand Down Expand Up @@ -647,7 +634,7 @@ p multipolygon

This creates the following MultiPolygon.

![MultiPolygon Example](assets/multipolygon_example.png)
![MultiPolygon Example](https://github.com/rgeo/rgeo/raw/master/doc/assets/multipolygon_example.png)

### Creating a MultiPolygon with WKT

Expand Down Expand Up @@ -731,7 +718,7 @@ Get the WKT representation of a geometry.
```ruby
factory = RGeo::Cartesian.factory
p factory.point(1, 1).as_text
# => "POINT (1.0 1.0)"
# => "POINT (1.0 1.0)"
```

### as_binary
Expand All @@ -741,7 +728,7 @@ Get the WKB representation of a geometry.
```ruby
factory = RGeo::Cartesian.factory
p factory.point(1, 1).as_binary
# => "\x00\x00\x00\x00\x01?\xF0\x00\x00\x00\x00\x00\x00?\xF0\x00\x00\x00\x00\x00\x00"
# => "\x00\x00\x00\x00\x01?\xF0\x00\x00\x00\x00\x00\x00?\xF0\x00\x00\x00\x00\x00\x00"
```

## Predicates and Relationships
Expand Down Expand Up @@ -1048,7 +1035,7 @@ square2 = factory.parse_wkt("POLYGON ((1 0, 1 2, 3 2, 3 0, 1 0))")
intersection = square1.intersection(square2)

p intersection
# => #<RGeo::Geos::CAPIPolygonImpl "POLYGON ((1.0 2.0, 2.0 2.0, 2.0 0.0, 1.0 0.0, 1.0 2.0))">
# => #<RGeo::Geos::CAPIPolygonImpl "POLYGON ((1.0 2.0, 2.0 2.0, 2.0 0.0, 1.0 0.0, 1.0 2.0))">
```

### Union
Expand Down Expand Up @@ -1079,7 +1066,7 @@ squares = factory.collection([square1, square2])
union = squares.unary_union

p union
# => #<RGeo::Geos::CAPIPolygonImpl "POLYGON ((0.0 0.0, 0.0 2.0, 1.0 2.0, 2.0 2.0, 3.0 2.0, 3.0 0.0, 2.0 0.0, 1.0 0.0, 0.0 0.0))">
# => #<RGeo::Geos::CAPIPolygonImpl "POLYGON ((0.0 0.0, 0.0 2.0, 1.0 2.0, 2.0 2.0, 3.0 2.0, 3.0 0.0, 2.0 0.0, 1.0 0.0, 0.0 0.0))">
```

### Difference
Expand All @@ -1094,7 +1081,7 @@ square2 = factory.parse_wkt("POLYGON ((1 0, 1 2, 3 2, 3 0, 1 0))")
diff = square1.difference(square2)

p diff
# => #<RGeo::Geos::CAPIPolygonImpl "POLYGON ((0.0 0.0, 0.0 2.0, 1.0 2.0, 1.0 0.0, 0.0 0.0))">
# => #<RGeo::Geos::CAPIPolygonImpl "POLYGON ((0.0 0.0, 0.0 2.0, 1.0 2.0, 1.0 0.0, 0.0 0.0))">
```

### SymDifference
Expand Down
18 changes: 10 additions & 8 deletions doc/Factory-Compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ _Note: This list is not exhaustive of all the methods defined by each factory. T
| `LineString#disjoint?(MultiLineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#disjoint?(MultiPolygon)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#intersects?(Point)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#intersects?(LineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | |
| `LineString#intersects?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | |
| `LineString#intersects?(LineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | |
| `LineString#intersects?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | |
| `LineString#intersects?(Polygon)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#intersects?(Collection)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#intersects?(MultiPoint)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
Expand All @@ -175,8 +175,8 @@ _Note: This list is not exhaustive of all the methods defined by each factory. T
| `LineString#touches?(MultiLineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#touches?(MultiPolygon)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#crosses?(Point)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#crosses?(LineString)` | ✅ | ✅ | ✅ | ✅ | | ✅ | |
| `LineString#crosses?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | | ✅ | |
| `LineString#crosses?(LineString)` | ✅ | ✅ | ✅ | ✅ | | ✅ | |
| `LineString#crosses?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | | ✅ | |
| `LineString#crosses?(Polygon)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#crosses?(Collection)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LineString#crosses?(MultiPoint)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
Expand Down Expand Up @@ -251,8 +251,8 @@ _Note: This list is not exhaustive of all the methods defined by each factory. T
| `LinearRing#disjoint?(MultiLineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#disjoint?(MultiPolygon)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#intersects?(Point)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#intersects?(LineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | |
| `LinearRing#intersects?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | |
| `LinearRing#intersects?(LineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | |
| `LinearRing#intersects?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | |
| `LinearRing#intersects?(Polygon)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#intersects?(Collection)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#intersects?(MultiPoint)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
Expand All @@ -267,8 +267,8 @@ _Note: This list is not exhaustive of all the methods defined by each factory. T
| `LinearRing#touches?(MultiLineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#touches?(MultiPolygon)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#crosses?(Point)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#crosses?(LineString)` | ✅ | ✅ | ✅ | ✅ | | ✅ | |
| `LinearRing#crosses?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | | ✅ | |
| `LinearRing#crosses?(LineString)` | ✅ | ✅ | ✅ | ✅ | | ✅ | |
| `LinearRing#crosses?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | | ✅ | |
| `LinearRing#crosses?(Polygon)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#crosses?(Collection)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `LinearRing#crosses?(MultiPoint)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
Expand Down Expand Up @@ -318,6 +318,7 @@ _Note: This list is not exhaustive of all the methods defined by each factory. T
| `Polygon#boundary` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `Polygon#convex_hull` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `Polygon#buffer` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `Polygon#area` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `Polygon#equals?(Point)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `Polygon#equals?(LineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `Polygon#equals?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
Expand Down Expand Up @@ -686,6 +687,7 @@ _Note: This list is not exhaustive of all the methods defined by each factory. T
| `MultiPolygon#boundary` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| `MultiPolygon#convex_hull` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `MultiPolygon#buffer` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `MultiPolygon#area` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `MultiPolygon#equals?(Point)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `MultiPolygon#equals?(LineString)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
| `MultiPolygon#equals?(LinearRing)` | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
Expand Down