locationtech / jts

The JTS Topology Suite is a Java library for creating and manipulating vector geometry.
Other
1.91k stars 437 forks source link

Writing and reading WKB loses M dimension #733

Open kaiwinter opened 3 years ago

kaiwinter commented 3 years ago

When using WKBWriter to write a Geometry which has XYM coordinates and afterwards using WKBReader for reading the result. The Geometry has XYZ coordinates instead of XYM coordinates.

Here is small example:

    String wkt = "MULTILINESTRING M((1 1 1, 2 2 2))";
    WKTReader wktReader = new WKTReader();
    Geometry geometryBefore = wktReader.read(wkt);

    WKBWriter wkbWriter = new WKBWriter(3);
    byte[] write = wkbWriter.write(geometryBefore);

    WKBReader wkbReader = new WKBReader();
    Geometry geometryAfter = wkbReader.read(write);

    System.out.println(Arrays.asList(geometryBefore.getCoordinates()));
    System.out.println(Arrays.asList(geometryAfter.getCoordinates()));

When running this you get the following output:

[(1.0, 1.0 m=1.0), (2.0, 2.0 m=2.0)]
[(1.0, 1.0, 1.0), (2.0, 2.0, 2.0)]

The geometryBefore has XYM coordinates. The geometryAfter has XYZ coordinates. In WKBReader.readGeometry are two variables evaluated hasZ and hasM. In the above example hasZ is true and hasM is false. I think this is because WKBWriter.writeGeometryType always writes 0x80000000 regardless of the coordinate type. Debugging WKBReader.readGeometry makes me think 0x40000000 should be used for M coordinates in WKBWriter.writeGeometryType.

What do you think? Can this be improved or did I just misunderstood how this should work.

jnh5y commented 3 years ago

I think you've identified a bug here. Any interest in working on it?

The Contributing guide has some info about that here: https://github.com/locationtech/jts/blob/master/CONTRIBUTING.md

kaiwinter commented 3 years ago

Yes sure. Currently I'm using a workaround with a GeometryFactory but I would love to get rid of it as it most probably impacts performance.

When thinking of a fix my first thought was to do an instanceof check of the result of g.getCoordinate() in writeGeometry. But that would be pretty ugly. Is there a better way to get the subtype of the Coordinate (whether it is CoordinateXYM)?

When looking at the WKTWriter there is the method setOutputOrdinates() . I was using this method to correctly write XYM coordinates as text, so I think this pattern may be applied to the WTBWriter as well. Do you have other ideas?