Skip to content

Commit

Permalink
handle 2.5D geometry type codes
Browse files Browse the repository at this point in the history
  • Loading branch information
bosborn committed May 2, 2018
1 parent a26b26f commit cc089f0
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 4 deletions.
11 changes: 11 additions & 0 deletions src/main/java/mil/nga/wkb/io/ByteReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ public int readInt() {
return value;
}

/**
* Read an unsigned integer
*
* @return unsigned integer
*/
public long readUnsignedInt() {
int intValue = readInt();
long value = intValue & 0xffffffffL;
return value;
}

/**
* Read a double
*
Expand Down
22 changes: 18 additions & 4 deletions src/main/java/mil/nga/wkb/io/WkbGeometryReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@
*/
public class WkbGeometryReader {

/**
* 2.5D bit
*/
private static final long WKB25D = Long.decode("0x80000000");

/**
* Read a geometry from the byte reader
*
Expand Down Expand Up @@ -148,8 +153,19 @@ public static GeometryTypeInfo readGeometryType(ByteReader reader) {
: ByteOrder.LITTLE_ENDIAN;
reader.setByteOrder(byteOrder);

// Read the geometry type integer
int geometryTypeWkbCode = reader.readInt();
// Read the geometry type unsigned integer
long unsignedGeometryTypeWkbCode = reader.readUnsignedInt();

boolean hasZ = false;
boolean hasM = false;

// Check for 2.5D geometry types
if (unsignedGeometryTypeWkbCode > WKB25D) {
hasZ = true;
unsignedGeometryTypeWkbCode -= WKB25D;
}

int geometryTypeWkbCode = (int) unsignedGeometryTypeWkbCode;

// Look at the last 2 digits to find the geometry type code (1 - 14)
int geometryTypeCode = geometryTypeWkbCode % 1000;
Expand All @@ -160,8 +176,6 @@ public static GeometryTypeInfo readGeometryType(ByteReader reader) {

// Determine if the geometry has a z (3d) or m (linear referencing
// system) value
boolean hasZ = false;
boolean hasM = false;
switch (geometryTypeMode) {
case 0:
break;
Expand Down
69 changes: 69 additions & 0 deletions src/test/java/mil/nga/wkb/test/WKBTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,58 @@ public void testGeometryCollection() throws IOException {

}

@Test
public void testMultiPolygon25() throws IOException {

// Test a pre-created WKB hex saved as a 2.5D MultiPolygon

byte[] bytes = hexStringToByteArray("0106000080010000000103000080010000000F0000007835454789C456C0DFDB63124D3F2C4000000000000000004CE4512E89C456C060BF20D13F3F2C400000000000000000A42EC6388CC456C0E0A50400423F2C400000000000000000B4E3B1608CC456C060034E67433F2C400000000000000000F82138508DC456C09FD015C5473F2C400000000000000000ECD6591B8CC456C000C305BC5B3F2C4000000000000000001002AD0F8CC456C060DB367D5C3F2C40000000000000000010996DEF8AC456C0BF01756A6C3F2C4000000000000000007054A08B8AC456C0806A0C1F733F2C4000000000000000009422D81D8AC456C041CA3C5B8A3F2C4000000000000000003CCB05C489C456C03FC4FC52AA3F2C400000000000000000740315A689C456C0BFC8635EB33F2C400000000000000000E4A5630B89C456C0DFE726D6B33F2C400000000000000000F45A4F3389C456C000B07950703F2C4000000000000000007835454789C456C0DFDB63124D3F2C400000000000000000");

TestCase.assertEquals(1, bytes[0]); // little endian
TestCase.assertEquals(GeometryType.MULTIPOLYGON.getCode(), bytes[1]);
TestCase.assertEquals(0, bytes[2]);
TestCase.assertEquals(0, bytes[3]);
TestCase.assertEquals(-128, bytes[4]);

Geometry geometry = WKBTestUtils.readGeometry(bytes);
TestCase.assertTrue(geometry instanceof MultiPolygon);
TestCase.assertEquals(geometry.getGeometryType(),
GeometryType.MULTIPOLYGON);
MultiPolygon multiPolygon = (MultiPolygon) geometry;
TestCase.assertTrue(multiPolygon.hasZ());
TestCase.assertFalse(multiPolygon.hasM());
TestCase.assertEquals(1, multiPolygon.numGeometries());
Polygon polygon = multiPolygon.getPolygons().get(0);
TestCase.assertTrue(polygon.hasZ());
TestCase.assertFalse(polygon.hasM());
TestCase.assertEquals(1, polygon.numRings());
LineString ring = polygon.getRings().get(0);
TestCase.assertTrue(ring.hasZ());
TestCase.assertFalse(ring.hasM());
TestCase.assertEquals(15, ring.numPoints());
for (Point point : ring.getPoints()) {
TestCase.assertTrue(point.hasZ());
TestCase.assertFalse(point.hasM());
TestCase.assertNotNull(point.getZ());
TestCase.assertNull(point.getM());
}

byte[] multiPolygonBytes = WKBTestUtils.writeBytes(multiPolygon,
ByteOrder.LITTLE_ENDIAN);
Geometry geometry2 = WKBTestUtils.readGeometry(multiPolygonBytes);

geometryTester(geometry, geometry2);

TestCase.assertEquals(bytes.length, multiPolygonBytes.length);
int equalBytes = 0;
for (int i = 0; i < bytes.length; i++) {
if (bytes[i] == multiPolygonBytes[i]) {
equalBytes++;
}
}
TestCase.assertEquals(bytes.length - 6, equalBytes);
}

/**
* Test the geometry writing to and reading from bytes
*
Expand Down Expand Up @@ -413,4 +465,21 @@ private void geometryTester(Geometry geometry, Geometry compareGeometry)
WKBTestUtils.compareEnvelopes(envelope1, envelope2);
}

/**
* Convert the hex string to a byte array
*
* @param hex
* hex string
* @return byte array
*/
private static byte[] hexStringToByteArray(String hex) {
int len = hex.length();
byte[] bytes = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character
.digit(hex.charAt(i + 1), 16));
}
return bytes;
}

}

1 comment on commit cc089f0

@GrayCygnus
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes worked great, and seemed to solve my Issue

Please sign in to comment.