diff --git a/modules/core/src/main/java/org/locationtech/jts/geom/impl/PackedCoordinateSequence.java b/modules/core/src/main/java/org/locationtech/jts/geom/impl/PackedCoordinateSequence.java index 4486734d63..dbd4a40bee 100644 --- a/modules/core/src/main/java/org/locationtech/jts/geom/impl/PackedCoordinateSequence.java +++ b/modules/core/src/main/java/org/locationtech/jts/geom/impl/PackedCoordinateSequence.java @@ -420,6 +420,185 @@ public Envelope expandEnvelope(Envelope env) } } + public static class Double2 extends PackedCoordinateSequence { + private static final long serialVersionUID = 5777450686367912720L; + + double[] xy; + double[] z; + double[] m; + + /** + * Builds a new packed coordinate sequence + * + * @param coords an array of double values that contains the ordinate values of the sequence + * @param dimension the total number of ordinates that make up a {@link Coordinate} in this sequence. + * @param measures the number of measure-ordinates each {@link Coordinate} in this sequence has. + */ + public Double2(double[] xy, double[] z, double[] m) { + super(z != null ? 3 : 2, m != null ? 1 : 0); + this.xy = xy; + this.z = z; + this.m = m; + } + + /** + * Builds a new packed coordinate sequence out of a coordinate array + * + * @param coordinates an array of {@link Coordinate}s + * @param dimension the total number of ordinates that make up a {@link Coordinate} in this sequence. + */ + public Double2(Coordinate[] coordinates, int dimension) { + this( coordinates, dimension, Math.max(0,dimension-3)); + } + /** + * Builds a new packed coordinate sequence out of a coordinate array + * + * @param coordinates an array of {@link Coordinate}s + * @param dimension the total number of ordinates that make up a {@link Coordinate} in this sequence. + * @param measures the number of measure-ordinates each {@link Coordinate} in this sequence has. + */ + public Double2(Coordinate[] coordinates, int dimension, int measures) { + super(dimension,measures); + if (coordinates == null) + coordinates = new Coordinate[0]; + + xy = new double[coordinates.length]; + for (int i = 0; i < coordinates.length; i++) { + xy[i * 2] = coordinates[i].x; + xy[i * 2 + 1] = coordinates[i].y; + if (dimension == 3) + z[i] = coordinates[i].getOrdinate(2); + if (measures == 1) + m[i] = coordinates[i].getOrdinate(3); + } + } + /** + * Builds a new packed coordinate sequence out of a coordinate array + * + * @param coordinates an array of {@link Coordinate}s + */ + public Double2(Coordinate[] coordinates) { + this(coordinates, 3, 0); + } + + /** + * Builds a new empty packed coordinate sequence of a given size and dimension + * + * @param size the number of coordinates in this sequence + * @param dimension the total number of ordinates that make up a {@link Coordinate} in this sequence. + * @param measures the number of measure-ordinates each {@link Coordinate} in this sequence has. + */ + public Double2(int size, int dimension, int measures) { + super(dimension,measures); + xy = new double[size * 2]; + if (dimension == 3) + z = new double[size]; + if (measures == 1) + m = new double[size]; + } + + /** + * @see PackedCoordinateSequence#getCoordinate(int) + */ + public Coordinate getCoordinateInternal(int i) { + double x = xy[i * 2]; + double y = xy[i * 2 + 1]; + if( dimension == 2 && measures == 0 ) { + return new CoordinateXY(x,y); + } + else if (dimension == 3 && measures == 0) { + double z = this.z[i]; + return new Coordinate(x,y,z); + } + else if (dimension == 3 && measures == 1) { + double m = this.m[i]; + return new CoordinateXYM(x,y,m); + } + else if (dimension == 4) { + double z = this.z[i]; + double m = this.m[i]; + return new CoordinateXYZM(x,y,z,m); + } + return new Coordinate(x, y); + } + + /** + * Gets the underlying array containing the coordinate values. + * + * @return the array of coordinate values + */ + public double[] getRawXYCoordinates() + { + return xy; + } + + /** + * @see CoordinateSequence#size() + */ + public int size() { + return xy.length / 2; + } + + /** + * @see java.lang.Object#clone() + * @see PackedCoordinateSequence#clone() + * @deprecated + */ + public Object clone() { + return copy(); + } + + /** + * @see PackedCoordinateSequence#size() + */ + public Double2 copy() { + double[] cloneXy = Arrays.copyOf(xy, xy.length); + double[] cloneZ = z != null ? Arrays.copyOf(z, z.length) : null; + double[] cloneM = m != null ? Arrays.copyOf(m, m.length) : null; + return new Double2(cloneXy, cloneZ, cloneM); + } + + /** + * @see PackedCoordinateSequence#getOrdinate(int, int) + * Beware, for performance reasons the ordinate index is not checked, if + * it's over dimensions you may not get an exception but a meaningless + * value. + */ + public double getOrdinate(int index, int ordinate) { + if (ordinate <= 1) + return xy[index * 2 + ordinate]; + if (ordinate == 2) + return z[index]; + if (ordinate == 3) + return m[index]; + throw new RuntimeException("Ordinate must be <= 3"); + } + + /** + * @see PackedCoordinateSequence#setOrdinate(int, int, double) + */ + public void setOrdinate(int index, int ordinate, double value) { + coordRef = null; + if (ordinate <= 1) + xy[index * 2 + ordinate] = value; + if (ordinate == 2) + z[index] = value; + if (ordinate == 3) + m[index] = value; + } + + /** + * @see CoordinateSequence#expandEnvelope(Envelope) + */ + public Envelope expandEnvelope(Envelope env) + { + for (int i = 0; i < xy.length; i += 2 ) { + env.expandToInclude(xy[i], xy[i + 1]); + } + return env; + } + } + /** * Packed coordinate sequence implementation based on floats */ diff --git a/modules/core/src/main/java/org/locationtech/jts/geom/impl/PackedCoordinateSequenceFactory.java b/modules/core/src/main/java/org/locationtech/jts/geom/impl/PackedCoordinateSequenceFactory.java index 35ed9e333a..70863ccb75 100644 --- a/modules/core/src/main/java/org/locationtech/jts/geom/impl/PackedCoordinateSequenceFactory.java +++ b/modules/core/src/main/java/org/locationtech/jts/geom/impl/PackedCoordinateSequenceFactory.java @@ -39,6 +39,11 @@ public class PackedCoordinateSequenceFactory implements */ public static final int FLOAT = 1; + /** + * Type code for dim/measure separated arrays of type double. + */ + public static final int DOUBLE2 = 1; + /** * A factory using array type {@link #DOUBLE} */ @@ -51,6 +56,12 @@ public class PackedCoordinateSequenceFactory implements public static final PackedCoordinateSequenceFactory FLOAT_FACTORY = new PackedCoordinateSequenceFactory(FLOAT); + /** + * A factory using array type {@link #DOUBLE2} + */ + public static final PackedCoordinateSequenceFactory DOUBLE2_FACTORY = + new PackedCoordinateSequenceFactory(DOUBLE2); + private static final int DEFAULT_MEASURES = 0; private static final int DEFAULT_DIMENSION = 3; @@ -100,8 +111,10 @@ public CoordinateSequence create(Coordinate[] coordinates) { } if (type == DOUBLE) { return new PackedCoordinateSequence.Double(coordinates, dimension, measures); - } else { + } else if (type == FLOAT) { return new PackedCoordinateSequence.Float(coordinates, dimension, measures); + } else { + return new PackedCoordinateSequence.Double2(coordinates, dimension, measures); } } @@ -113,8 +126,10 @@ public CoordinateSequence create(CoordinateSequence coordSeq) { int measures = coordSeq.getMeasures(); if (type == DOUBLE) { return new PackedCoordinateSequence.Double(coordSeq.toCoordinateArray(), dimension, measures); - } else { + } else if (type == FLOAT) { return new PackedCoordinateSequence.Float(coordSeq.toCoordinateArray(), dimension, measures); + } else { + return new PackedCoordinateSequence.Double2(coordSeq.toCoordinateArray(), dimension, measures); } } @@ -148,6 +163,11 @@ public CoordinateSequence create(double[] packedCoordinates, int dimension, int return new PackedCoordinateSequence.Float(packedCoordinates, dimension, measures); } } + + public CoordinateSequence create(double[] xy, double[] z, double[] m) { + return new PackedCoordinateSequence.Double2(xy, z, m); + } + /** * Creates a packed coordinate sequence of type {@link #FLOAT} * from the provided array. @@ -184,9 +204,12 @@ public CoordinateSequence create(int size, int dimension) { if (type == DOUBLE) { return new PackedCoordinateSequence.Double( size, dimension, Math.max(DEFAULT_MEASURES, dimension-3)); - } else { + } else if (type == FLOAT) { return new PackedCoordinateSequence.Float( size, dimension, Math.max(DEFAULT_MEASURES, dimension-3)); + } else { + return new PackedCoordinateSequence.Double2( + size, dimension, Math.max(DEFAULT_MEASURES, dimension-3)); } } @@ -196,8 +219,10 @@ public CoordinateSequence create(int size, int dimension) { public CoordinateSequence create(int size, int dimension, int measures) { if (type == DOUBLE) { return new PackedCoordinateSequence.Double(size, dimension, measures); - } else { + } else if (type == FLOAT) { return new PackedCoordinateSequence.Float(size, dimension, measures); + } else { + return new PackedCoordinateSequence.Double2(size, dimension, measures); } } } diff --git a/modules/core/src/test/java/org/locationtech/jts/geom/impl/PackedCoordinateSequenceTest.java b/modules/core/src/test/java/org/locationtech/jts/geom/impl/PackedCoordinateSequenceTest.java index b2df619017..836f224d58 100644 --- a/modules/core/src/test/java/org/locationtech/jts/geom/impl/PackedCoordinateSequenceTest.java +++ b/modules/core/src/test/java/org/locationtech/jts/geom/impl/PackedCoordinateSequenceTest.java @@ -51,6 +51,10 @@ public void testDouble() { public void testFloat() { checkAll( PackedCoordinateSequenceFactory.FLOAT_FACTORY) ; } + + public void testDouble2() { + checkAll( PackedCoordinateSequenceFactory.DOUBLE2_FACTORY) ; + } public void checkAll(CoordinateSequenceFactory factory) {