Skip to content

Commit 47703d3

Browse files
committed
support for explicit Z M coordinates values in WKT
1 parent 8b25a72 commit 47703d3

File tree

3 files changed

+84
-35
lines changed

3 files changed

+84
-35
lines changed

libs/geo/src/main/java/org/elasticsearch/geometry/Geometry.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ default boolean hasZ() {
2424
return false;
2525
}
2626

27+
default boolean hasM() {
28+
return false;
29+
}
30+
2731
default boolean hasAlt() {
2832
return hasZ();
2933
}

libs/geo/src/main/java/org/elasticsearch/geometry/Point.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,31 +12,42 @@
1212
import org.elasticsearch.geometry.utils.WellKnownText;
1313

1414
/**
15-
* Represents a Point on the earth's surface in decimal degrees and optional altitude in meters.
15+
* Represents a Point on the earth's surface with optional Z (altitude) and M (measure).
1616
*/
1717
public class Point implements Geometry {
1818
public static final Point EMPTY = new Point();
1919

2020
private final double y;
2121
private final double x;
2222
private final double z;
23+
private final double m;
2324
private final boolean empty;
2425

2526
private Point() {
2627
y = 0;
2728
x = 0;
2829
z = Double.NaN;
30+
m = Double.NaN;
2931
empty = true;
3032
}
3133

3234
public Point(double x, double y) {
33-
this(x, y, Double.NaN);
35+
this(x, y, Double.NaN, Double.NaN);
3436
}
3537

3638
public Point(double x, double y, double z) {
3739
this.y = y;
3840
this.x = x;
3941
this.z = z;
42+
this.m = Double.NaN;
43+
this.empty = false;
44+
}
45+
46+
public Point(double x, double y, double z, double m) {
47+
this.y = y;
48+
this.x = x;
49+
this.z = z;
50+
this.m = m;
4051
this.empty = false;
4152
}
4253

@@ -57,6 +68,8 @@ public double getZ() {
5768
return z;
5869
}
5970

71+
public double getM() { return m; }
72+
6073
public double getLat() {
6174
return y;
6275
}
@@ -78,7 +91,8 @@ public boolean equals(Object o) {
7891
if (point.empty != empty) return false;
7992
if (Double.compare(point.y, y) != 0) return false;
8093
if (Double.compare(point.x, x) != 0) return false;
81-
return Double.compare(point.z, z) == 0;
94+
if (Double.compare(point.z, z) != 0) return false;
95+
return Double.compare(point.m, m) == 0;
8296
}
8397

8498
@Override
@@ -91,6 +105,8 @@ public int hashCode() {
91105
result = 31 * result + (int) (temp ^ (temp >>> 32));
92106
temp = Double.doubleToLongBits(z);
93107
result = 31 * result + (int) (temp ^ (temp >>> 32));
108+
temp = Double.doubleToLongBits(m);
109+
result = 31 * result + (int) (temp ^ (temp >>> 32));
94110
return result;
95111
}
96112

@@ -109,6 +125,11 @@ public boolean hasZ() {
109125
return Double.isNaN(z) == false;
110126
}
111127

128+
@Override
129+
public boolean hasM() {
130+
return Double.isNaN(m) == false;
131+
}
132+
112133
@Override
113134
public String toString() {
114135
return WellKnownText.toWKT(this);

libs/geo/src/main/java/org/elasticsearch/geometry/utils/WellKnownText.java

Lines changed: 56 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -231,18 +231,30 @@ private static void parseGeometry(ByteBuffer byteBuffer, StringBuilder sb) {
231231
byteBuffer.order(byteBuffer.get() == 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
232232
final int type = byteBuffer.getInt();
233233
switch (type) {
234-
case 1 -> parsePoint(byteBuffer, false, sb);
235-
case 1001 -> parsePoint(byteBuffer, true, sb);
236-
case 2 -> parseLine(byteBuffer, false, sb);
237-
case 1002 -> parseLine(byteBuffer, true, sb);
238-
case 3 -> parsePolygon(byteBuffer, false, sb);
239-
case 1003 -> parsePolygon(byteBuffer, true, sb);
240-
case 4 -> parseMultiPoint(byteBuffer, false, sb);
241-
case 1004 -> parseMultiPoint(byteBuffer, true, sb);
242-
case 5 -> parseMultiLine(byteBuffer, false, sb);
243-
case 1005 -> parseMultiLine(byteBuffer, true, sb);
244-
case 6 -> parseMultiPolygon(byteBuffer, false, sb);
245-
case 1006 -> parseMultiPolygon(byteBuffer, true, sb);
234+
case 1 -> parsePoint(byteBuffer, false, false, sb);
235+
case 1001 -> parsePoint(byteBuffer, true, false, sb);
236+
case 2001 -> parsePoint(byteBuffer, false, true, sb);
237+
case 3001 -> parsePoint(byteBuffer, true, true, sb);
238+
case 2 -> parseLine(byteBuffer, false, false, sb);
239+
case 1002 -> parseLine(byteBuffer, true, false, sb);
240+
case 2002 -> parseLine(byteBuffer, false, true, sb);
241+
case 3002 -> parseLine(byteBuffer, true, true, sb);
242+
case 3 -> parsePolygon(byteBuffer, false, false, sb);
243+
case 1003 -> parsePolygon(byteBuffer, true, false, sb);
244+
case 2003 -> parsePolygon(byteBuffer, false, true, sb);
245+
case 3003 -> parsePolygon(byteBuffer, true, true, sb);
246+
case 4 -> parseMultiPoint(byteBuffer, false, false, sb);
247+
case 1004 -> parseMultiPoint(byteBuffer, true, false, sb);
248+
case 2004 -> parseMultiPoint(byteBuffer, false, true, sb);
249+
case 3004 -> parseMultiPoint(byteBuffer, true, true, sb);
250+
case 5 -> parseMultiLine(byteBuffer, false, false, sb);
251+
case 1005 -> parseMultiLine(byteBuffer, true, false, sb);
252+
case 2005 -> parseMultiLine(byteBuffer, false, true, sb);
253+
case 3005 -> parseMultiLine(byteBuffer, true, true, sb);
254+
case 6 -> parseMultiPolygon(byteBuffer, false, false, sb);
255+
case 1006 -> parseMultiPolygon(byteBuffer, true, false, sb);
256+
case 2006 -> parseMultiPolygon(byteBuffer, false, true, sb);
257+
case 3006 -> parseMultiPolygon(byteBuffer, true, true, sb);
246258
case 7, 1007 -> parseGeometryCollection(byteBuffer, sb);
247259
case 17 -> parseCircle(byteBuffer, false, sb);
248260
case 1017 -> parseCircle(byteBuffer, true, sb);
@@ -253,21 +265,33 @@ private static void parseGeometry(ByteBuffer byteBuffer, StringBuilder sb) {
253265
;
254266
}
255267

256-
private static void writeCoordinate(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb) {
268+
private static void writeCoordinate(ByteBuffer byteBuffer, boolean hasZ, boolean hasM, StringBuilder sb) {
257269
sb.append(byteBuffer.getDouble()).append(SPACE).append(byteBuffer.getDouble());
258270
if (hasZ) {
259271
sb.append(SPACE).append(byteBuffer.getDouble());
260272
}
273+
if (hasM) {
274+
sb.append(SPACE).append(byteBuffer.getDouble());
275+
}
261276
}
262277

263-
private static void parsePoint(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb) {
264-
sb.append("POINT").append(SPACE);
265-
sb.append(LPAREN);
266-
writeCoordinate(byteBuffer, hasZ, sb);
278+
private static void parsePoint(ByteBuffer byteBuffer, boolean hasZ, boolean hasM, StringBuilder sb) {
279+
sb.append("POINT");
280+
281+
if (hasZ && hasM) {
282+
sb.append(" ZM");
283+
} else if (hasZ) {
284+
sb.append(" Z");
285+
} else if (hasM) {
286+
sb.append(" M");
287+
}
288+
289+
sb.append(SPACE).append(LPAREN);
290+
writeCoordinate(byteBuffer, hasZ, hasM, sb);
267291
sb.append(RPAREN);
268292
}
269293

270-
private static void parseMultiPoint(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb) {
294+
private static void parseMultiPoint(ByteBuffer byteBuffer, boolean hasZ, boolean hasM,StringBuilder sb) {
271295
sb.append("MULTIPOINT").append(SPACE);
272296
final int numPoints = byteBuffer.getInt();
273297
if (numPoints == 0) {
@@ -278,7 +302,7 @@ private static void parseMultiPoint(ByteBuffer byteBuffer, boolean hasZ, StringB
278302
for (int i = 0; i < numPoints; i++) {
279303
byteBuffer.order(byteBuffer.get() == 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
280304
byteBuffer.getInt();
281-
writeCoordinate(byteBuffer, hasZ, sb);
305+
writeCoordinate(byteBuffer, hasZ, hasM, sb);
282306
if (i != numPoints - 1) {
283307
sb.append(COMMA);
284308
sb.append(SPACE);
@@ -287,12 +311,12 @@ private static void parseMultiPoint(ByteBuffer byteBuffer, boolean hasZ, StringB
287311
sb.append(RPAREN);
288312
}
289313

290-
private static void parseLine(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb) {
314+
private static void parseLine(ByteBuffer byteBuffer, boolean hasZ, boolean hasM, StringBuilder sb) {
291315
sb.append("LINESTRING").append(SPACE);
292-
parseLineString(byteBuffer, hasZ, sb);
316+
parseLineString(byteBuffer, hasZ, hasM, sb);
293317
}
294318

295-
private static void parseMultiLine(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb) {
319+
private static void parseMultiLine(ByteBuffer byteBuffer, boolean hasZ, boolean hasM, StringBuilder sb) {
296320
sb.append("MULTILINESTRING").append(SPACE);
297321
final int numLines = byteBuffer.getInt();
298322
if (numLines == 0) {
@@ -303,36 +327,36 @@ private static void parseMultiLine(ByteBuffer byteBuffer, boolean hasZ, StringBu
303327
for (int i = 0; i < numLines; i++) {
304328
byteBuffer.order(byteBuffer.get() == 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
305329
byteBuffer.getInt();
306-
parseLineString(byteBuffer, hasZ, sb);
330+
parseLineString(byteBuffer, hasZ, hasM, sb);
307331
if (i != numLines - 1) {
308332
sb.append(COMMA);
309333
}
310334
}
311335
sb.append(RPAREN);
312336
}
313337

314-
private static void parsePolygon(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb) {
338+
private static void parsePolygon(ByteBuffer byteBuffer, boolean hasZ, boolean hasM, StringBuilder sb) {
315339
sb.append("POLYGON").append(SPACE);
316-
parseRings(byteBuffer, hasZ, sb, byteBuffer.getInt());
340+
parseRings(byteBuffer, hasZ, hasM, sb, byteBuffer.getInt());
317341

318342
}
319343

320-
private static void parseRings(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb, int numRings) {
344+
private static void parseRings(ByteBuffer byteBuffer, boolean hasZ, boolean hasM, StringBuilder sb, int numRings) {
321345
if (numRings == 0) {
322346
sb.append(EMPTY);
323347
return;
324348
}
325349
sb.append(LPAREN);
326-
parseLineString(byteBuffer, hasZ, sb);
350+
parseLineString(byteBuffer, hasZ, hasM, sb);
327351
for (int i = 1; i < numRings; i++) {
328352
sb.append(COMMA);
329353
sb.append(SPACE);
330-
parseLineString(byteBuffer, hasZ, sb);
354+
parseLineString(byteBuffer, hasZ, hasM, sb);
331355
}
332356
sb.append(RPAREN);
333357
}
334358

335-
private static void parseMultiPolygon(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb) {
359+
private static void parseMultiPolygon(ByteBuffer byteBuffer, boolean hasZ, boolean hasM, StringBuilder sb) {
336360
sb.append("MULTIPOLYGON").append(SPACE);
337361
final int numPolygons = byteBuffer.getInt();
338362
if (numPolygons == 0) {
@@ -343,23 +367,23 @@ private static void parseMultiPolygon(ByteBuffer byteBuffer, boolean hasZ, Strin
343367
for (int i = 0; i < numPolygons; i++) {
344368
byteBuffer.order(byteBuffer.get() == 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
345369
byteBuffer.getInt();
346-
parseRings(byteBuffer, hasZ, sb, byteBuffer.getInt());
370+
parseRings(byteBuffer, hasZ, hasM, sb, byteBuffer.getInt());
347371
if (i != numPolygons - 1) {
348372
sb.append(COMMA);
349373
}
350374
}
351375
sb.append(RPAREN);
352376
}
353377

354-
private static void parseLineString(ByteBuffer byteBuffer, boolean hasZ, StringBuilder sb) {
378+
private static void parseLineString(ByteBuffer byteBuffer, boolean hasZ, boolean hasM, StringBuilder sb) {
355379
final int length = byteBuffer.getInt();
356380
if (length == 0) {
357381
sb.append(EMPTY);
358382
return;
359383
}
360384
sb.append(LPAREN);
361385
for (int i = 0; i < length; i++) {
362-
writeCoordinate(byteBuffer, hasZ, sb);
386+
writeCoordinate(byteBuffer, hasZ, hasM, sb);
363387
if (i != length - 1) {
364388
sb.append(COMMA);
365389
sb.append(SPACE);

0 commit comments

Comments
 (0)