001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, Geotools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */
017: package org.geotools.arcsde.data;
018:
019: import java.io.BufferedReader;
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.io.InputStreamReader;
023: import java.util.ArrayList;
024: import java.util.LinkedList;
025: import java.util.List;
026: import java.util.logging.Level;
027: import java.util.logging.Logger;
028:
029: import junit.framework.TestCase;
030:
031: import org.geotools.data.DataSourceException;
032:
033: import com.esri.sde.sdk.client.SDEPoint;
034: import com.esri.sde.sdk.client.SeCoordinateReference;
035: import com.esri.sde.sdk.client.SeException;
036: import com.esri.sde.sdk.client.SeShape;
037: import com.vividsolutions.jts.geom.Coordinate;
038: import com.vividsolutions.jts.geom.Geometry;
039: import com.vividsolutions.jts.geom.GeometryCollection;
040: import com.vividsolutions.jts.geom.GeometryFactory;
041: import com.vividsolutions.jts.geom.LineString;
042: import com.vividsolutions.jts.geom.MultiLineString;
043: import com.vividsolutions.jts.geom.MultiPoint;
044: import com.vividsolutions.jts.geom.MultiPolygon;
045: import com.vividsolutions.jts.geom.Point;
046: import com.vividsolutions.jts.geom.Polygon;
047: import com.vividsolutions.jts.io.ParseException;
048: import com.vividsolutions.jts.io.WKTReader;
049:
050: /**
051: * DOCUMENT ME!
052: *
053: * @author Gabriel Roldan, Axios Engineering
054: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/arcsde/datastore/src/test/java/org/geotools/arcsde/data/GeometryBuilderTest.java $
055: * @version $Id: GeometryBuilderTest.java 27863 2007-11-12 20:34:34Z desruisseaux $
056: */
057: public class GeometryBuilderTest extends TestCase {
058: /** DOCUMENT ME! */
059: static Logger LOGGER = org.geotools.util.logging.Logging
060: .getLogger(GeometryBuilderTest.class.getPackage().getName());
061:
062: /** DOCUMENT ME! */
063: private ArcSDEGeometryBuilder geometryBuilder = null;
064:
065: /** DOCUMENT ME! */
066: private WKTReader wktReader;
067:
068: /**
069: * Creates a new GeometryBuilderTest object.
070: *
071: * @param name DOCUMENT ME!
072: */
073: public GeometryBuilderTest(String name) {
074: super (name);
075: }
076:
077: /**
078: * DOCUMENT ME!
079: *
080: * @throws Exception DOCUMENT ME!
081: */
082: protected void setUp() throws Exception {
083: super .setUp();
084: this .wktReader = new WKTReader();
085: }
086:
087: /**
088: * DOCUMENT ME!
089: *
090: * @throws Exception DOCUMENT ME!
091: */
092: protected void tearDown() throws Exception {
093: this .geometryBuilder = null;
094: this .wktReader = null;
095: super .tearDown();
096: }
097:
098: /**
099: * DOCUMENT ME!
100: */
101: public void testGetDefaultValues() {
102: testGetDefaultValue(Point.class);
103: testGetDefaultValue(MultiPoint.class);
104: testGetDefaultValue(LineString.class);
105: testGetDefaultValue(MultiLineString.class);
106: testGetDefaultValue(Polygon.class);
107: testGetDefaultValue(MultiPolygon.class);
108: }
109:
110: /**
111: * DOCUMENT ME!
112: *
113: * @throws Exception DOCUMENT ME!
114: */
115: public void testPointBuilder() throws Exception {
116: testBuildJTSGeometries(Point.class, "pointtest.wkt");
117: }
118:
119: /**
120: * DOCUMENT ME!
121: *
122: * @throws Exception DOCUMENT ME!
123: */
124: public void testMultiPointBuilder() throws Exception {
125: testBuildJTSGeometries(MultiPoint.class, "multipointtest.wkt");
126: }
127:
128: /**
129: * DOCUMENT ME!
130: *
131: * @throws Exception DOCUMENT ME!
132: */
133: public void testLineStringBuilder() throws Exception {
134: testBuildJTSGeometries(LineString.class, "linestringtest.wkt");
135: }
136:
137: /**
138: * DOCUMENT ME!
139: *
140: * @throws Exception DOCUMENT ME!
141: */
142: public void testMultiLineStringBuilder() throws Exception {
143: testBuildJTSGeometries(MultiLineString.class,
144: "multilinestringtest.wkt");
145: }
146:
147: /**
148: * DOCUMENT ME!
149: *
150: * @throws Exception DOCUMENT ME!
151: */
152: public void testPolygonBuilder() throws Exception {
153: testBuildJTSGeometries(Polygon.class, "polygontest.wkt");
154: }
155:
156: /**
157: * DOCUMENT ME!
158: *
159: * @throws Exception DOCUMENT ME!
160: */
161: public void testMultiPolygonBuilder() throws Exception {
162: testBuildJTSGeometries(MultiPolygon.class,
163: "multipolygontest.wkt");
164: }
165:
166: /**
167: * DOCUMENT ME!
168: *
169: * @throws Exception DOCUMENT ME!
170: */
171: public void testConstructShapePoint() throws Exception {
172: Geometry[] testPoints = null;
173:
174: testPoints = loadTestData("pointtest.wkt");
175:
176: testBuildSeShapes(testPoints);
177: }
178:
179: /**
180: * DOCUMENT ME!
181: *
182: * @throws Exception DOCUMENT ME!
183: */
184: public void testConstructShapeMultiPoint() throws Exception {
185: Geometry[] testMultiPoints = null;
186:
187: testMultiPoints = loadTestData("multipointtest.wkt");
188:
189: testBuildSeShapes(testMultiPoints);
190: }
191:
192: /**
193: * DOCUMENT ME!
194: *
195: * @throws Exception DOCUMENT ME!
196: */
197: public void testConstructShapeLineString() throws Exception {
198: Geometry[] testLineStrings = null;
199:
200: testLineStrings = loadTestData("linestringtest.wkt");
201:
202: testBuildSeShapes(testLineStrings);
203: }
204:
205: /**
206: * DOCUMENT ME!
207: *
208: * @throws Exception DOCUMENT ME!
209: */
210: public void testConstructShapeMultiLineString() throws Exception {
211: Geometry[] testMultiLineStrings = null;
212:
213: testMultiLineStrings = loadTestData("multilinestringtest.wkt");
214:
215: testBuildSeShapes(testMultiLineStrings);
216: }
217:
218: /**
219: * DOCUMENT ME!
220: *
221: * @throws Exception DOCUMENT ME!
222: */
223: public void testConstructShapePolygon() throws Exception {
224: Geometry[] testPolygons = null;
225:
226: testPolygons = loadTestData("polygontest.wkt");
227:
228: testBuildSeShapes(testPolygons);
229: }
230:
231: /**
232: * DOCUMENT ME!
233: *
234: * @throws Exception DOCUMENT ME!
235: */
236: public void testConstructShapeMultiPolygon() throws Exception {
237: Geometry[] testMultiPolygons = null;
238:
239: testMultiPolygons = loadTestData("multipolygontest.wkt");
240:
241: testBuildSeShapes(testMultiPolygons);
242: }
243:
244: /**
245: * DOCUMENT ME!
246: *
247: * @throws Exception DOCUMENT ME!
248: */
249: public void testConstructShapeEmpty() throws Exception {
250: Geometry[] testEmptys = new Geometry[6];
251: testEmptys[0] = ArcSDEGeometryBuilder.builderFor(Point.class)
252: .getEmpty();
253: testEmptys[1] = ArcSDEGeometryBuilder.builderFor(
254: MultiPoint.class).getEmpty();
255: testEmptys[2] = ArcSDEGeometryBuilder.builderFor(
256: LineString.class).getEmpty();
257: testEmptys[3] = ArcSDEGeometryBuilder.builderFor(
258: MultiLineString.class).getEmpty();
259: testEmptys[4] = ArcSDEGeometryBuilder.builderFor(Polygon.class)
260: .getEmpty();
261: testEmptys[5] = ArcSDEGeometryBuilder.builderFor(
262: MultiPolygon.class).getEmpty();
263: testBuildSeShapes(testEmptys);
264: }
265:
266: /**
267: * tests each geometry in <code>geometries</code> using
268: * <code>testConstructShape(Geometry)</code>
269: *
270: * @param geometries DOCUMENT ME!
271: *
272: * @throws Exception DOCUMENT ME!
273: */
274: private static void testBuildSeShapes(Geometry[] geometries)
275: throws Exception {
276: for (int i = 0; i < geometries.length; i++) {
277: testConstructShape(geometries[i]);
278: }
279: }
280:
281: /**
282: * tests the building of SeShape objects from JTS Geometries. To do that,
283: * recieves a Geometry object, then creates a ArcSDEGeometryBuilder for it's
284: * geometry type and ask it to construct an equivalent SeShape. With this
285: * SeShape, checks that it's number of points is equal to the number of
286: * points in <code>geometry</code>, and then creates an equivalent
287: * Geometry object, wich in turn is checked for equality against
288: * <code>geometry</code>.
289: *
290: * @param geometry DOCUMENT ME!
291: *
292: * @throws Exception DOCUMENT ME!
293: */
294: private static void testConstructShape(Geometry geometry)
295: throws Exception {
296: LOGGER.finer("testConstructShape: testing " + geometry);
297:
298: Class geometryClass = geometry.getClass();
299: ArcSDEGeometryBuilder builder = ArcSDEGeometryBuilder
300: .builderFor(geometryClass);
301:
302: SeCoordinateReference cr = TestData.getGenericCoordRef();
303: if (LOGGER.isLoggable(Level.FINE)) {
304: System.err.println("\n\n******************\n"
305: + cr.getXYEnvelope());
306: }
307: Geometry equivalentGeometry = null;
308:
309: SeShape equivalentShape = builder.constructShape(geometry, cr);
310: int expectedNumOfPoints = geometry.getNumPoints();
311:
312: assertEquals(geometry + " - " + equivalentShape,
313: expectedNumOfPoints, equivalentShape.getNumOfPoints());
314: LOGGER
315: .fine("geometry and SeShape contains the same number of points: "
316: + equivalentShape.getNumOfPoints());
317:
318: LOGGER.finer("generating an SeShape's equivalent Geometry");
319: equivalentGeometry = builder.construct(equivalentShape);
320:
321: LOGGER.fine("now testing both geometries for equivalence: "
322: + geometry + " -- " + equivalentGeometry);
323:
324: assertEquals(geometry.getDimension(), equivalentGeometry
325: .getDimension());
326: LOGGER.fine("dimension test passed");
327:
328: assertEquals(geometry.getGeometryType(), equivalentGeometry
329: .getGeometryType());
330: LOGGER.fine("geometry type test passed");
331:
332: assertEquals(geometry + " - " + equivalentGeometry, geometry
333: .getNumPoints(), equivalentGeometry.getNumPoints());
334: LOGGER.fine("numPoints test passed");
335:
336: LOGGER.fine(geometry.getEnvelopeInternal() + " == "
337: + equivalentGeometry.getEnvelopeInternal());
338:
339: /*
340: assertEquals(geometry.getEnvelopeInternal(),
341: equivalentGeometry.getEnvelopeInternal());
342: */
343: assertEquals(geometry.getArea(), equivalentGeometry.getArea(),
344: 0.1);
345: LOGGER.fine("area test passed");
346: }
347:
348: /**
349: * Tests that the geometry builder for the geometry class given by
350: * <code>geometryClass</code> correctly constcucts JTS geometries fom
351: * ArcSDE Java API's <code>SeShape</code>.
352: *
353: * <p>
354: * To do so, first parses the WKT geometries from the properties file
355: * pointed by <code>"test-data/" + testDataSource</code>, then creates
356: * their corresponding <code>SeShape</code> objects and finally used
357: * ArcSDEGeometryBuilder to build the JTS geometries back, which are tested for
358: * equality against the original ones.
359: * </p>
360: *
361: * @param geometryClass a JTS geometry class
362: * @param testDataResource the resource name under "test-data/" which
363: * contains the geometries to load in WKT.
364: *
365: * @throws Exception for any problem that could arise
366: */
367: private void testBuildJTSGeometries(final Class geometryClass,
368: final String testDataResource) throws Exception {
369: LOGGER.fine("---- testBuildGeometries: testing "
370: + testDataResource + " ----");
371:
372: this .geometryBuilder = ArcSDEGeometryBuilder
373: .builderFor(geometryClass);
374: LOGGER.fine("created "
375: + this .geometryBuilder.getClass().getName());
376:
377: Geometry[] expectedGeometries = loadTestData(testDataResource);
378: Geometry createdGeometry;
379: Geometry expectedGeometry;
380: double[][][] sdeCoords;
381:
382: //create a sde CRS with a huge value range and 5 digits of presission
383: SeCoordinateReference seCRS = TestData.getGenericCoordRef();
384:
385: for (int i = 0; i < expectedGeometries.length; i++) {
386: expectedGeometry = expectedGeometries[i];
387: sdeCoords = geometryToSdeCoords(expectedGeometry, seCRS);
388:
389: //geometryBuilder.newGeometry is a protected method
390: //and should not be called directly. We use it here
391: //just for testing purposes. Instead, geometryBuilder.construct(SeShape)
392: //must be used
393: createdGeometry = this .geometryBuilder
394: .newGeometry(sdeCoords);
395: assertEquals(expectedGeometry.getClass(), createdGeometry
396: .getClass());
397: }
398: }
399:
400: /**
401: * DOCUMENT ME!
402: *
403: * @param jtsGeom DOCUMENT ME!
404: * @param seCRS DOCUMENT ME!
405: *
406: * @return DOCUMENT ME!
407: *
408: * @throws SeException DOCUMENT ME!
409: * @throws IOException DOCUMENT ME!
410: * @throws DataSourceException DOCUMENT ME!
411: */
412: private double[][][] geometryToSdeCoords(final Geometry jtsGeom,
413: final SeCoordinateReference seCRS) throws SeException,
414: IOException {
415: int numParts;
416: double[][][] sdeCoords;
417: GeometryCollection gcol = null;
418:
419: if (jtsGeom instanceof GeometryCollection) {
420: gcol = (GeometryCollection) jtsGeom;
421: } else {
422: Geometry[] geoms = { jtsGeom };
423: gcol = new GeometryFactory()
424: .createGeometryCollection(geoms);
425: }
426:
427: List allPoints = new ArrayList();
428: numParts = gcol.getNumGeometries();
429:
430: int[] partOffsets = new int[numParts];
431: Geometry geom;
432:
433: for (int currGeom = 0; currGeom < numParts; currGeom++) {
434: partOffsets[currGeom] = allPoints.size();
435: geom = gcol.getGeometryN(currGeom);
436:
437: Coordinate[] coords = geom.getCoordinates();
438:
439: for (int i = 0; i < coords.length; i++) {
440: Coordinate c = coords[i];
441: SDEPoint p = new SDEPoint(c.x, c.y);
442: allPoints.add(p);
443: }
444: }
445:
446: SDEPoint[] points = new SDEPoint[allPoints.size()];
447: allPoints.toArray(points);
448:
449: SeShape shape = new SeShape(seCRS);
450:
451: try {
452: if (jtsGeom instanceof Point || gcol instanceof MultiPoint) {
453: shape.generatePoint(points.length, points);
454: } else if (jtsGeom instanceof LineString
455: || jtsGeom instanceof MultiLineString) {
456: shape.generateLine(points.length, numParts,
457: partOffsets, points);
458: } else {
459: shape.generatePolygon(points.length, numParts,
460: partOffsets, points);
461: }
462: } catch (SeException e) {
463: LOGGER.warning(e.getSeError().getErrDesc());
464: throw new DataSourceException(e.getSeError().getErrDesc()
465: + ": " + jtsGeom, e);
466: }
467:
468: sdeCoords = shape.getAllCoords();
469:
470: return sdeCoords;
471: }
472:
473: /**
474: * DOCUMENT ME!
475: *
476: * @param coords DOCUMENT ME!
477: *
478: * @return DOCUMENT ME!
479: */
480: private double[] toSdeCoords(Coordinate[] coords) {
481: int nCoords = coords.length;
482: double[] sdeCoords = new double[2 * nCoords];
483: Coordinate c;
484:
485: for (int i = 0, j = 1; i < nCoords; i++, j += 2) {
486: c = coords[i];
487: sdeCoords[j - 1] = c.x;
488: sdeCoords[j] = c.y;
489: }
490:
491: return sdeCoords;
492: }
493:
494: /**
495: * DOCUMENT ME!
496: *
497: * @param resource DOCUMENT ME!
498: *
499: * @return DOCUMENT ME!
500: *
501: * @throws Exception DOCUMENT ME!
502: */
503: private Geometry[] loadTestData(final String resource)
504: throws Exception {
505: List testGeoms = new LinkedList();
506: Geometry g;
507: String line = null;
508:
509: try {
510: LOGGER.fine("loading test data test-data/" + resource);
511:
512: InputStream in = org.geotools.test.TestData.openStream(
513: null, resource);
514: BufferedReader reader = new BufferedReader(
515: new InputStreamReader(in));
516:
517: while ((line = reader.readLine()) != null) {
518: line = line.trim();
519:
520: if (line.startsWith("#") || "".equals(line)) {
521: continue;
522: }
523:
524: g = this .wktReader.read(line);
525: LOGGER.fine("loaded test geometry: " + g.toText());
526: testGeoms.add(g);
527: }
528: } catch (ParseException ex) {
529: LOGGER.severe("cant create a test geometry: "
530: + ex.getMessage());
531: throw ex;
532: } catch (IOException ex) {
533: LOGGER.severe("cant load test data " + resource + ": "
534: + ex.getMessage());
535: throw ex;
536: }
537:
538: return (Geometry[]) testGeoms.toArray(new Geometry[0]);
539: }
540:
541: /**
542: * given a geometry class, tests that ArcSDEGeometryBuilder.defaultValueFor that
543: * class returns an empty geometry of the same geometry class
544: *
545: * @param geometryClass DOCUMENT ME!
546: */
547: private void testGetDefaultValue(Class geometryClass) {
548: Geometry geom = ArcSDEGeometryBuilder
549: .defaultValueFor(geometryClass);
550: assertNotNull(geom);
551: assertTrue(geom.isEmpty());
552: assertTrue(geometryClass.isAssignableFrom(geom.getClass()));
553: }
554: }
|