Skip to content

Add Geometry.getCoordinateDimension - #1220

Open
mdedetrich wants to merge 1 commit into
locationtech:masterfrom
mdedetrich:add-geometry-getCoordinateDimension
Open

Add Geometry.getCoordinateDimension#1220
mdedetrich wants to merge 1 commit into
locationtech:masterfrom
mdedetrich:add-geometry-getCoordinateDimension

Conversation

@mdedetrich

Copy link
Copy Markdown

Resolves: #654

Tests have also been added to make sure that it works as expected.

Signed-off-by: Matthew de Detrich <mdedetrich@gmail.com>

@grootstebozewolf grootstebozewolf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Request changes. The method is the right answer to #654getDimension() is topological, and WKB needs the coordinate count — but the API shape and the empty contract both freeze the wrong thing. Dan already pointed at the port: GEOS Geometry::getCoordinateDimension() is an instance method that trusts the sequence, including on empty.

Blockers

  • This should be g.getCoordinateDimension(), not Geometry.getCoordinateDimension(g). Implement it on the four types GEOS does. Do not add another 50-line instanceof switch to Geometry.java.
  • Do not force empty sequences to 2. WKTReader already stores dimension on POINT Z EMPTY; GEOS reports 3 / 3 / 4. Trust seq.getDimension(). Document that factory-built empties may report 3 (CoordinateArrays.dimension([]) defaults to 3). Add POINT Z EMPTY expecting 3.

Nits: dead shell != null; test file needs a license header; tests are Packed-only; XYZ vs XYM both being 3 matches GEOS and does not fully drive WKBWriter.setOutputOrdinates.

Comment on lines +1753 to +1781
if (g instanceof Point) {
return coordinateSequenceDimension(((Point) g).getCoordinateSequence());
}
if (g instanceof LineString) {
return coordinateSequenceDimension(((LineString) g).getCoordinateSequence());
}
if (g instanceof Polygon) {
Polygon poly = (Polygon) g;
int dimension = 2;
LinearRing shell = poly.getExteriorRing();
if (shell != null) {
dimension = coordinateSequenceDimension(shell.getCoordinateSequence());
}
for (int i = 0; i < poly.getNumInteriorRing(); i++) {
dimension = Math.max(dimension, coordinateSequenceDimension(poly.getInteriorRingN(i).getCoordinateSequence()));
}
return dimension;
}
if (g instanceof GeometryCollection) {
GeometryCollection gc = (GeometryCollection) g;
int dimension = 2;
for (int i = 0; i < gc.getNumGeometries(); i++) {
dimension = Math.max(dimension, getCoordinateDimension(gc.getGeometryN(i)));
}
return dimension;
}
return 2;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should be g.getCoordinateDimension(), not Geometry.getCoordinateDimension(g).

getDimension() is already an instance method. GEOS — the port Dan pointed at on #654 — is virtual uint8_t getCoordinateDimension() const on Point / SimpleCurve / Surface / GeometryCollection. A static instanceof chain will not override for a later type and teaches the wrong call site. Put an instance method next to getDimension() and implement it on those four types.

A CoordinateSequenceFilter looks more “JTS,” but Point.apply / LineString.apply return without visiting a size-0 sequence, so a filter cannot see empty-sequence metadata. Direct getCoordinateSequence() (what you have, what GEOS has) is the right access — just not as a type switch on Geometry.

Comment on lines +1783 to +1785
return seq.size() > 0 ? seq.getDimension() : 2;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do not force empty sequences to 2.

WKTReader.createCoordinateSequenceEmpty already builds csFactory.create(0, toDimension(flags), measures). POINT Z EMPTY therefore already has a 0-size sequence of dimension 3. This helper throws that away. GEOS pins the same cases at 3 / 3 / 4 (WKBReaderTest).

The size check is papering over a different footgun: GeometryFactory.createPoint() uses create(new Coordinate[]{}), and CoordinateArrays.dimension([]) is 3 (“unknown, assume default”). Packed’s default is also 3. Trust the sequence anyway. Document that factory-built empties may report 3. Add POINT Z EMPTY / LINESTRING Z EMPTY expecting 3.

Comment on lines +1763 to +1766
if (shell != null) {
dimension = coordinateSequenceDimension(shell.getCoordinateSequence());
}
for (int i = 0; i < poly.getNumInteriorRing(); i++) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

shell != null is dead: Polygon replaces a null shell with createLinearRing().

Comment on lines +57 to +59
public void testEmptyPoint() {
checkDimension("POINT EMPTY", 2);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

POINT EMPTY only locks the untagged case. Add POINT Z EMPTY / LINESTRING Z EMPTY expecting 3 (GEOS / the WKTReader empty sequence). Also run one case on the default CoordinateArraySequence factory — these tests are Packed-only, which hides the factory empty-default-3 footgun.

New test file also needs the license header CONTRIBUTING asks for.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

XY / XYZ / XYM / XYZM, mixed collections taking the max, and “3 means Z or M” all match GEOS. LinearRing falls through LineString, Multi* through GeometryCollection. The strict WKT reader is the correct fixture. That is enough for the original #654 2-vs-3 examples.

This getter does not distinguish XYZ from XYM (both 3). That matches GEOS. Callers who need the ordinate set still have to look at hasZ / hasM on the sequence — fine for #654; do not claim it fully drives WKBWriter.setOutputOrdinates.

Empty MultiLineString / MultiPolygon from WKT already drop the Z flag in WKTReader (createMultiLineString() with no flags). Pre-existing; this method cannot invent a dimension those objects do not store.

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.

Question: Is there a way to determine geometry dimension?

2 participants