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