PolygonHandler uses wrong ordinate index for CoordinateXYM.class

Description

The ShapefileFeatureReader throws the following exception when iterating features from a shapefile:

java.lang.IllegalArgumentException: Invalid ordinate index: 3 at org.locationtech.jts.geom.CoordinateXYM.setOrdinate(CoordinateXYM.java:146) at org.locationtech.jts.geom.impl.CoordinateArraySequence.setOrdinate(CoordinateArraySequence.java:305) at org.geotools.data.shapefile.shp.PolygonHandler.readCoordinates(PolygonHandler.java:311) at org.geotools.data.shapefile.shp.PolygonHandler.read(PolygonHandler.java:142) at org.geotools.data.shapefile.shp.ShapefileReader$Record.shape(ShapefileReader.java:113) at org.geotools.data.shapefile.ShapefileFeatureReader.getGeometry(ShapefileFeatureReader.java:238) at org.geotools.data.shapefile.ShapefileFeatureReader.hasNext(ShapefileFeatureReader.java:181)

Some parameters from the operation in question:

flatFeature: false dimensions: 2 numParts: 1 numPoints: 1099 shapeType = PolygonM

When the PolygonHandler of Geotools is going to read the coordinates, it invokes the following setOrdinate() method:

if (shapeType == ShapeType.POLYGONM || shapeType == ShapeType.POLYGONZ) { // Handle M dbuffer.position(dbuffer.position() + 2); dbuffer.get(ordinates, 0, numPoints); for (int t = 0; t < numPoints; t++) { cs.setOrdinate(t, CoordinateSequence.M, ordinates[t]); } }

Where CoordinateSequence.M has an int value of '3'.

But when the CoordinateXYM.class is handling this setOrdinate, it doesn't accept any value higher than 2:

@Override public void setOrdinate(int ordinateIndex, double value) { switch (ordinateIndex) { case X: x = value; break; case Y: y = value; break; case M: m = value; break; default: throw new IllegalArgumentException("Invalid ordinate index: " + ordinateIndex); } }

We can see the definition of M inside the CoordinateXYM.class

/** * Standard ordinate index value for M in XYM sequences. * * <p>This constant assumes XYM coordinate sequence definition. Check this assumption using * {@link #getDimension()} and {@link #getMeasures()} before use. */ public static final int M = 2;

Instead Geotool uses M from CoordinateSequence class, which is only intended for XYZM coordinate definitions:

/** * Standard ordinate index value for, where M is 3. * * <p>This constant assumes XYZM coordinate sequence definition, please check this assumption * using {@link #getDimension()} and {@link #getMeasures()} before use. */ int M = 3;

Environment

Windows 10, Linux (CentOS &RedHat)
Java 8 & Java 11

  • JTS: 1.17.1

  • Geotools: 24.0

is duplicated by

Activity

Eivind Rønnevik 
May 12, 2021 at 1:03 PM

Sure, I will provide a shapefile as an example on that 6740 ticket. But I don' think I’m entitled to reopen the ticket itself? It states “You don’t have permission to transition this issue” when I click the “Closed” button.

Ian Turton 
May 12, 2021 at 12:17 PM

I would repopen - https://osgeo-org.atlassian.net/browse/GEOT-6740 with an example of your failing Shapefile

Eivind Rønnevik 
May 12, 2021 at 10:00 AM

I see this issue has been closed and marked as fixed.

However I tested today with latest and greatest gt-shapefile-25.0, and the problem still occurs for me.

I hit the same problem as before;

Exception in thread "main" java.lang.IllegalArgumentException: Invalid ordinate index: 3 at org.locationtech.jts.geom.CoordinateXYM.setOrdinate(CoordinateXYM.java:156) at org.locationtech.jts.geom.impl.CoordinateArraySequence.setOrdinate(CoordinateArraySequence.java:305) at org.geotools.data.shapefile.shp.PolygonHandler.readCoordinates(PolygonHandler.java:311) at org.geotools.data.shapefile.shp.PolygonHandler.read(PolygonHandler.java:139) at org.geotools.data.shapefile.shp.ShapefileReader$Record.shape(ShapefileReader.java:114) at org.geotools.data.shapefile.ShapefileFeatureReader.getGeometry(ShapefileFeatureReader.java:238) at org.geotools.data.shapefile.ShapefileFeatureReader.hasNext(ShapefileFeatureReader.java:181)


And when debugging the PolygonHandler.class where cs.setOrdinate() is called (line 311 in the source file, but line 8 below in the snippet)

boolean isArcZWithM = dbuffer.hasRemaining() && shapeType == ShapeType.POLYGONZ; if (isArcZWithM || shapeType == ShapeType.POLYGONM) { // Handle M dbuffer.position(dbuffer.position() + 2); dbuffer.get(ordinates, 0, numPoints); for (int t = 0; t < numPoints; t++) { cs.setOrdinate(t, CoordinateSequence.M, ordinates[t]); } }


It still makes use of

CoordinateSequence.M

which has an int value of 3.

And in the JTS library (running with latest 18.1 version) they only accept 0, 1 or 2 as parameters for the ordinateIndex, if not they will throw the IllegalArgumentException that I hit.

I was unsure whether I should create a new Jira or if this one should be reopened, so I wanted to ask upfront. Please advice on what to do.

Kind Regards,
Eivind

Ian Turton 
November 28, 2020 at 5:44 PM

Former user 
November 25, 2020 at 11:31 AM

Fixed

Details

Assignee

Reporter

Affects versions

Priority

Created November 25, 2020 at 7:46 AM
Updated May 12, 2021 at 1:03 PM
Resolved November 28, 2020 at 5:44 PM