PolygonHandler uses wrong ordinate index for CoordinateXYM.class
Description
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
@Ian Turton 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
@Ian Turton 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
Former user November 25, 2020 at 11:31 AM
https://osgeo-org.atlassian.net/browse/GEOT-6740 may be ralated
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;