1 /* 2 * Copyright (c) 2016 Vivid Solutions. 3 * 4 * All rights reserved. This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * and Eclipse Distribution License v. 1.0 which accompanies this distribution. 7 * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html 8 * and the Eclipse Distribution License is available at 9 * 10 * http://www.eclipse.org/org/documents/edl-v10.php. 11 */ 12 package org.locationtech.jts.io; 13 14 import java.io.IOException; 15 16 import org.locationtech.jts.geom.Coordinate; 17 import org.locationtech.jts.geom.CoordinateFilter; 18 import org.locationtech.jts.geom.CoordinateSequenceComparator; 19 import org.locationtech.jts.geom.Geometry; 20 import org.locationtech.jts.geom.GeometryFactory; 21 import org.locationtech.jts.geom.impl.PackedCoordinateSequenceFactory; 22 import org.locationtech.jts.util.GeometricShapeFactory; 23 24 import junit.framework.TestCase; 25 import junit.textui.TestRunner; 26 27 28 /** 29 * Tests the {@link WKBReader} and {@link WKBWriter}. 30 * Tests all geometries with both 2 and 3 dimensions and both byte orderings. 31 */ 32 public class WKBTest 33 extends TestCase 34 { main(String args[])35 public static void main(String args[]) { 36 TestRunner.run(WKBTest.class); 37 } 38 39 private GeometryFactory geomFactory = new GeometryFactory(); 40 private WKTReader rdr = new WKTReader(geomFactory); 41 WKBTest(String name)42 public WKBTest(String name) 43 { 44 super(name); 45 } 46 testFirst()47 public void testFirst() 48 throws IOException, ParseException 49 { 50 runWKBTest("MULTIPOINT ((0 0), (1 4), (100 200))"); 51 } 52 testPointPCS()53 public void testPointPCS() throws IOException, ParseException { 54 runWKBTestPackedCoordinate("POINT (1 2)"); 55 } 56 testPoint()57 public void testPoint() throws IOException, ParseException { 58 runWKBTest("POINT (1 2)"); 59 } 60 testPointEmpty()61 public void testPointEmpty() throws IOException, ParseException { 62 runWKBTest("POINT EMPTY"); 63 } 64 testLineString()65 public void testLineString() 66 throws IOException, ParseException 67 { 68 runWKBTest("LINESTRING (1 2, 10 20, 100 200)"); 69 } testPolygon()70 public void testPolygon() 71 throws IOException, ParseException 72 { 73 runWKBTest("POLYGON ((0 0, 100 0, 100 100, 0 100, 0 0))"); 74 } testPolygonWithHole()75 public void testPolygonWithHole() 76 throws IOException, ParseException 77 { 78 runWKBTest("POLYGON ((0 0, 100 0, 100 100, 0 100, 0 0), (1 1, 1 10, 10 10, 10 1, 1 1) )"); 79 } testMultiPoint()80 public void testMultiPoint() 81 throws IOException, ParseException 82 { 83 runWKBTest("MULTIPOINT ((0 0), (1 4), (100 200))"); 84 } testMultiLineString()85 public void testMultiLineString() 86 throws IOException, ParseException 87 { 88 runWKBTest("MULTILINESTRING ((0 0, 1 10), (10 10, 20 30), (123 123, 456 789))"); 89 } testMultiPolygon()90 public void testMultiPolygon() 91 throws IOException, ParseException 92 { 93 runWKBTest("MULTIPOLYGON ( ((0 0, 100 0, 100 100, 0 100, 0 0), (1 1, 1 10, 10 10, 10 1, 1 1) ), ((200 200, 200 250, 250 250, 250 200, 200 200)) )"); 94 } 95 testGeometryCollection()96 public void testGeometryCollection() 97 throws IOException, ParseException 98 { 99 runWKBTest("GEOMETRYCOLLECTION ( POINT ( 1 1), LINESTRING (0 0, 10 10), POLYGON ((0 0, 100 0, 100 100, 0 100, 0 0)) )"); 100 } 101 testNestedGeometryCollection()102 public void testNestedGeometryCollection() 103 throws IOException, ParseException 104 { 105 runWKBTest("GEOMETRYCOLLECTION ( POINT (20 20), GEOMETRYCOLLECTION ( POINT ( 1 1), LINESTRING (0 0, 10 10), POLYGON ((0 0, 100 0, 100 100, 0 100, 0 0)) ) )"); 106 } testLineStringEmpty()107 public void testLineStringEmpty() 108 throws IOException, ParseException 109 { 110 runWKBTest("LINESTRING EMPTY"); 111 } 112 testBigPolygon()113 public void testBigPolygon() 114 throws IOException, ParseException 115 { 116 GeometricShapeFactory shapeFactory = new GeometricShapeFactory(geomFactory); 117 shapeFactory.setBase(new Coordinate(0,0)); 118 shapeFactory.setSize(1000); 119 shapeFactory.setNumPoints(1000); 120 Geometry geom = shapeFactory.createRectangle(); 121 runWKBTest(geom, 2, false); 122 } 123 testPolygonEmpty()124 public void testPolygonEmpty() 125 throws IOException, ParseException 126 { 127 runWKBTest("POLYGON EMPTY"); 128 } testMultiPointEmpty()129 public void testMultiPointEmpty() 130 throws IOException, ParseException 131 { 132 runWKBTest("MULTIPOINT EMPTY"); 133 } testMultiLineStringEmpty()134 public void testMultiLineStringEmpty() 135 throws IOException, ParseException 136 { 137 runWKBTest("MULTILINESTRING EMPTY"); 138 } testMultiPolygonEmpty()139 public void testMultiPolygonEmpty() 140 throws IOException, ParseException 141 { 142 runWKBTest("MULTIPOLYGON EMPTY"); 143 } testGeometryCollectionEmpty()144 public void testGeometryCollectionEmpty() 145 throws IOException, ParseException 146 { 147 runWKBTest("GEOMETRYCOLLECTION EMPTY"); 148 } 149 runWKBTest(String wkt)150 private void runWKBTest(String wkt) throws IOException, ParseException 151 { 152 runWKBTestCoordinateArray(wkt); 153 runWKBTestPackedCoordinate(wkt); 154 } 155 runWKBTestPackedCoordinate(String wkt)156 private void runWKBTestPackedCoordinate(String wkt) throws IOException, ParseException { 157 GeometryFactory geomFactory = new GeometryFactory( 158 new PackedCoordinateSequenceFactory(PackedCoordinateSequenceFactory.DOUBLE)); 159 WKTReader rdr = new WKTReader(geomFactory); 160 Geometry g = rdr.read(wkt); 161 162 // Since we are using a PCS of dim=2, only check 2-dimensional storage 163 runWKBTest(g, 2, true); 164 runWKBTest(g, 2, false); 165 } 166 runWKBTestCoordinateArray(String wkt)167 private void runWKBTestCoordinateArray(String wkt) throws IOException, ParseException { 168 GeometryFactory geomFactory = new GeometryFactory(); 169 WKTReader rdr = new WKTReader(geomFactory); 170 Geometry g = rdr.read(wkt); 171 172 // CoordinateArrays support dimension 3, so test both dimensions 173 runWKBTest(g, 2, true); 174 runWKBTest(g, 2, false); 175 runWKBTest(g, 3, true); 176 runWKBTest(g, 3, false); 177 } 178 runWKBTest(Geometry g, int dimension, boolean toHex)179 private void runWKBTest(Geometry g, int dimension, boolean toHex) 180 throws IOException, ParseException 181 { 182 setZ(g); 183 runWKBTest(g, dimension, ByteOrderValues.LITTLE_ENDIAN, toHex); 184 runWKBTest(g, dimension, ByteOrderValues.BIG_ENDIAN, toHex); 185 } 186 runWKBTest(Geometry g, int dimension, int byteOrder, boolean toHex)187 private void runWKBTest(Geometry g, int dimension, int byteOrder, boolean toHex) 188 throws IOException, ParseException 189 { 190 runGeometry(g, dimension, byteOrder, toHex, 100); 191 runGeometry(g, dimension, byteOrder, toHex, 0); 192 runGeometry(g, dimension, byteOrder, toHex, 101010); 193 runGeometry(g, dimension, byteOrder, toHex, -1); 194 } 195 setZ(Geometry g)196 private void setZ(Geometry g) 197 { 198 g.apply(new AverageZFilter()); 199 } 200 201 //static Comparator comp2D = new Coordinate.DimensionalComparator(); 202 //static Comparator comp3D = new Coordinate.DimensionalComparator(3); 203 204 static CoordinateSequenceComparator comp2 = new CoordinateSequenceComparator(2); 205 static CoordinateSequenceComparator comp3 = new CoordinateSequenceComparator(3); 206 207 /** 208 * Use single WKB reader, to ensure it can be used for multiple input geometries 209 */ 210 WKBReader wkbReader = new WKBReader(geomFactory); 211 runGeometry(Geometry g, int dimension, int byteOrder, boolean toHex, int srid)212 void runGeometry(Geometry g, int dimension, int byteOrder, boolean toHex, int srid) 213 throws IOException, ParseException 214 { 215 boolean includeSRID = false; 216 if (srid >= 0) { 217 includeSRID = true; 218 g.setSRID(srid); 219 } 220 221 WKBWriter wkbWriter = new WKBWriter(dimension, byteOrder, includeSRID); 222 byte[] wkb = wkbWriter.write(g); 223 String wkbHex = null; 224 if (toHex) 225 wkbHex = WKBWriter.toHex(wkb); 226 227 if (toHex) 228 wkb = WKBReader.hexToBytes(wkbHex); 229 Geometry g2 = wkbReader.read(wkb); 230 231 CoordinateSequenceComparator comp = (dimension == 2) ? comp2 : comp3; 232 boolean isEqual = (g.compareTo(g2, comp) == 0); 233 assertTrue(isEqual); 234 235 if (includeSRID) { 236 boolean isSRIDEqual = g.getSRID() == g2.getSRID(); 237 assertTrue(isSRIDEqual); 238 } 239 } 240 } 241 242 class AverageZFilter implements CoordinateFilter 243 { filter(Coordinate coord)244 public void filter(Coordinate coord) 245 { 246 coord.setZ((coord.x + coord.y) / 2); 247 } 248 } 249 250