jts
jts copied to clipboard
Buffer operation does not preserve dimension and measures of CoordinateSequence
Computing the buffer of a Point
that has a CoordinateSequence
with a dimension of 2 will result in a Polygon
that has an exterior ring with a dimension of 3.
Here is a unit test as extension to BufferTest
/**
* Tests if a buffer operation does not change the dimension and measures value of the underlying sequences
*/
public void testBufferDoesNotChangeDimensionOrMeasures() {
checkNotChangeDimensionOrMeasures("POINT (0 0)");
checkNotChangeDimensionOrMeasures("POINT (0 0 0)");
checkNotChangeDimensionOrMeasures("POINT Z (0 0 0)");
checkNotChangeDimensionOrMeasures("POINT M (0 0 0)");
checkNotChangeDimensionOrMeasures("POINT ZM (0 0 0 0)");
}
private void checkNotChangeDimensionOrMeasures(String wkt)
{
Geometry geom = read(wkt);
DimensionAndMeasuresFilter filter = new DimensionAndMeasuresFilter();
geom.apply(filter);
int dimension = filter.getDimension();
int measures = filter.getMeasures();
Geometry geom0 = geom.buffer(0);
filter = new DimensionAndMeasuresFilter();
geom0.apply(filter);
int dimension0 = filter.getDimension();
int measures0 = filter.getMeasures();
assertEquals("(" + wkt + ").buffer(0) changes dimension", dimension, dimension0);
assertEquals("(" + wkt + ").buffer(0) changes measures", measures, measures0);
Geometry geom1 = geom.buffer(1);
filter = new DimensionAndMeasuresFilter();
geom1.apply(filter);
int dimension1 = filter.getDimension();
int measures1 = filter.getMeasures();
assertEquals("(" + wkt + ").buffer(1) changes dimension", dimension, dimension1);
assertEquals("(" + wkt + ").buffer(1) changes measures", measures, measures1);
}
private class DimensionAndMeasuresFilter implements GeometryComponentFilter {
private int dimension = 2;
private int measures;
public int getDimension() { return dimension; }
public int getMeasures() { return measures; }
public void filter(Geometry g) {
if (g instanceof Point) {
Point pt = (Point)g;
if (pt.getCoordinateSequence().getDimension() > dimension)
dimension = pt.getCoordinateSequence().getDimension();
if (pt.getCoordinateSequence().getMeasures() > measures)
measures = pt.getCoordinateSequence().getMeasures();
}
else if (g instanceof LineString) {
LineString ls = (LineString)g;
if (ls.getCoordinateSequence().getDimension() > dimension)
dimension = ls.getCoordinateSequence().getDimension();
if (ls.getCoordinateSequence().getMeasures() > measures)
measures = ls.getCoordinateSequence().getMeasures();
}
}
}
``
Yes, a lot of the constructive operations are loose in their handling of coordinate dimension. It would be good to identify an easy-to-use code pattern to fix this, and roll it out across the codebase.
I suggest to create oberloads for Coordinate.create()
that take x- and y-ordinate values directly and use that instead of new Coordinate(double, double)
:
in Coordinate:
public Coordinate create(double x, double y) {
Coordinate result = create();
result.x = x;
result.y = y;
return result;
}
Additionally we need to replace the use of the copy constructor new Coordinate(Coordinate)
with the Coordinate.copy()
function.