From: <svn...@os...> - 2012-05-15 17:58:06
|
Author: mdavis Date: 2012-05-15 10:57:59 -0700 (Tue, 15 May 2012) New Revision: 38727 Added: branches/2.7.x/modules/library/main/src/test/java/org/geotools/geometry/jts/GeometryCoordinateSequenceTransformerTest.java Modified: branches/2.7.x/modules/library/api/src/main/java/org/geotools/geometry/jts/GeometryCoordinateSequenceTransformer.java Log: GEOT-4130, GeometryCoordinateSequenceTransformer now uses input CoordinateSequenceFactory by default Modified: branches/2.7.x/modules/library/api/src/main/java/org/geotools/geometry/jts/GeometryCoordinateSequenceTransformer.java =================================================================== --- branches/2.7.x/modules/library/api/src/main/java/org/geotools/geometry/jts/GeometryCoordinateSequenceTransformer.java 2012-05-15 17:57:46 UTC (rev 38726) +++ branches/2.7.x/modules/library/api/src/main/java/org/geotools/geometry/jts/GeometryCoordinateSequenceTransformer.java 2012-05-15 17:57:59 UTC (rev 38727) @@ -17,6 +17,7 @@ package org.geotools.geometry.jts; import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.CoordinateSequenceFactory; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryFactory; @@ -34,9 +35,14 @@ /** - * Service object that takes a geometry an applies a MathTransform on top - * of it. + * Service object that takes a geometry and applies a {@link MathTransform} to the coordinates it + * contains. + * <p> + * New geometries are constructed using the {@link GeometryFactory} of the input geometries. + * By default, this will use the same {@link CoordinateSequenceFactory} as the input geometries. + * </p> * @author Andrea Aime + * @author Martin Davis * * @source $URL$ */ @@ -44,11 +50,23 @@ private MathTransform transform; private CoordinateSequenceTransformer csTransformer; private CoordinateReferenceSystem crs; - + + /** + * Creates a transformer which uses the {@link CoordinateSequenceFactory} + * of the source geometries. + */ public GeometryCoordinateSequenceTransformer() { - csTransformer = new DefaultCoordinateSequenceTransformer(); + // the csTransformer is initialized from the first geometry } + /** + * Creates a transformer which uses a client-specified {@link CoordinateSequenceTransformer}. + * <p> + * <b>WARNING:</b> The CoordinateSequenceTransformer must use the same CoordinateSequenceFactory + * as the input geometries, so that geometries are constructed consistently. + * + * @param transformer + */ public GeometryCoordinateSequenceTransformer(CoordinateSequenceTransformer transformer) { csTransformer = transformer; } @@ -83,6 +101,12 @@ GeometryFactory factory = g.getFactory(); Geometry transformed = null; + // if required, lazily init csTransformer using geometry's CSFactory + if (csTransformer == null) { + CoordinateSequenceFactory csf = g.getFactory().getCoordinateSequenceFactory(); + csTransformer = new DefaultCoordinateSequenceTransformer(csf); + } + if (g instanceof Point) { transformed = transformPoint((Point) g, factory); } else if (g instanceof MultiPoint) { @@ -147,7 +171,7 @@ * * @throws TransformException */ - public LineString transformLineString(LineString ls, GeometryFactory gf) + private LineString transformLineString(LineString ls, GeometryFactory gf) throws TransformException { CoordinateSequence cs = projectCoordinateSequence(ls.getCoordinateSequence()); LineString transformed = null; @@ -167,7 +191,7 @@ * * @throws TransformException */ - public Point transformPoint(Point point, GeometryFactory gf) + private Point transformPoint(Point point, GeometryFactory gf) throws TransformException { CoordinateSequence cs = projectCoordinateSequence(point.getCoordinateSequence()); Point transformed = gf.createPoint(cs);; @@ -180,7 +204,7 @@ * * @throws TransformException */ - public CoordinateSequence projectCoordinateSequence(CoordinateSequence cs) + private CoordinateSequence projectCoordinateSequence(CoordinateSequence cs) throws TransformException { return csTransformer.transform(cs, transform); } @@ -189,7 +213,7 @@ * @param polygon * @throws TransformException */ - public Polygon transformPolygon(Polygon polygon, GeometryFactory gf) + private Polygon transformPolygon(Polygon polygon, GeometryFactory gf) throws TransformException { LinearRing exterior = (LinearRing) transformLineString(polygon.getExteriorRing(), gf); LinearRing[] interiors = new LinearRing[polygon.getNumInteriorRing()]; Added: branches/2.7.x/modules/library/main/src/test/java/org/geotools/geometry/jts/GeometryCoordinateSequenceTransformerTest.java =================================================================== --- branches/2.7.x/modules/library/main/src/test/java/org/geotools/geometry/jts/GeometryCoordinateSequenceTransformerTest.java (rev 0) +++ branches/2.7.x/modules/library/main/src/test/java/org/geotools/geometry/jts/GeometryCoordinateSequenceTransformerTest.java 2012-05-15 17:57:59 UTC (rev 38727) @@ -0,0 +1,211 @@ +/* + * GeoTools - The Open Source Java GIS Toolkit + * http://geotools.org + * + * (C) 2004-2008, Open Source Geospatial Foundation (OSGeo) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ +package org.geotools.geometry.jts; + +// J2SE dependencies +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; + +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.geotools.referencing.operation.transform.ProjectiveTransform; +import org.junit.Test; +import org.opengis.referencing.operation.MathTransform; +import org.opengis.referencing.operation.TransformException; + +import com.vividsolutions.jts.geom.CoordinateSequence; +import com.vividsolutions.jts.geom.CoordinateSequenceFilter; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +/** + * Tests the {@link GeometryCoordinateSequenceTransformer} implementation. + * + * @since 2.2 + * + * + * @source $URL$ + * @version $Id$ + * @author Martin Davis + */ +public class GeometryCoordinateSequenceTransformerTest { + + private GeometryFactory geomFact = new GeometryFactory( + new LiteCoordinateSequenceFactory()); + + private GeometryBuilder gb = new GeometryBuilder(geomFact); + + @Test + public void testLineString() throws Exception { + checkTransform(gb.lineStringZ(10, 11, 1, 20, 21, 2)); + checkTransform(gb.lineString(10, 11, 20, 21)); + } + + @Test + public void testPoint() throws Exception { + checkTransform(gb.point(10, 11)); + checkTransform(gb.pointZ(10, 11, 1)); + } + + @Test + public void testPolygon() throws Exception { + checkTransform(gb.circle(10, 10, 5, 20)); + checkTransform(gb.boxZ(10, 10, 20, 20, 99)); + checkTransform(gb.polygon(gb.boxZ(10, 10, 20, 20, 99), + gb.boxZ(11, 11, 19, 19, 99))); + } + + @Test + public void testMulti() throws Exception { + checkTransform(gb.multiPoint(10, 10, 5, 20)); + checkTransform(gb.multiLineString(gb.lineString(10, 10, 20, 20), + gb.lineString(10, 10, 20, 20))); + checkTransform(gb.multiPolygon(gb.boxZ(10, 10, 20, 20, 99), + gb.boxZ(11, 11, 19, 19, 99))); + } + + @Test + public void testGeometryCollection() throws Exception { + checkTransform(gb.geometryCollection(gb.point(10, 11), + gb.lineString(10, 10, 20, 20), gb.box(10, 10, 20, 20))); + } + + /** + * Confirm that testing method is accurate! + * + * @throws Exception + */ + @Test + public void testDifferentDimensionsFailure() throws Exception { + Geometry g1 = gb.box(10, 10, 20, 20); + Geometry g2 = gb.boxZ(10, 10, 20, 20, 99); + assertFalse(hasSameValuesAndStructure(g1, g2)); + } + + private static final double ORD_TOLERANCE = 1.0e-6; + + /** + * Check transformation correctness by transforming forwards and backwards using + * inverse MathTransforms. + * + * @param g + * @throws TransformException + */ + private void checkTransform(Geometry g) throws TransformException { + GeometryCoordinateSequenceTransformer gcsTrans = new GeometryCoordinateSequenceTransformer(); + gcsTrans.setCoordinateReferenceSystem(DefaultGeographicCRS.WGS84); + MathTransform trans = ProjectiveTransform.createTranslation(2, 100); + gcsTrans.setMathTransform(trans); + + GeometryCoordinateSequenceTransformer gcsTransInv = new GeometryCoordinateSequenceTransformer(); + gcsTransInv.setCoordinateReferenceSystem(DefaultGeographicCRS.WGS84); + MathTransform transInv = ProjectiveTransform.createTranslation(2, -100); + gcsTransInv.setMathTransform(transInv); + + Geometry gTrans = gcsTrans.transform(g); + Geometry g2 = gcsTransInv.transform(gTrans); + + // result better be a different geometry + assertTrue(g != g2); + assertTrue(hasSameValuesAndStructure(g, g2)); + } + + boolean hasSameValuesAndStructure(Geometry g1, Geometry g2) { + if (!g1.equalsExact(g2, ORD_TOLERANCE)) + return false; + if (g1.getFactory() != g2.getFactory()) + return false; + + CoordinateSequence seq = CoordinateSequenceFinder.find(g1); + if (!CoordinateSequenceSchemaChecker.check(g2, seq.getClass(), + seq.getDimension())) + return false; + return true; + } + + static class CoordinateSequenceFinder implements CoordinateSequenceFilter { + + public static CoordinateSequence find(Geometry g) { + CoordinateSequenceFinder finder = new CoordinateSequenceFinder(); + g.apply(finder); + return finder.getSeq(); + } + + private CoordinateSequence firstSeqFound = null; + + public CoordinateSequence getSeq() { + return firstSeqFound; + } + + public void filter(CoordinateSequence seq, int i) { + if (firstSeqFound == null) + firstSeqFound = seq; + + } + + public boolean isDone() { + return firstSeqFound != null; + } + + public boolean isGeometryChanged() { + return false; + } + } + + static class CoordinateSequenceSchemaChecker implements + CoordinateSequenceFilter { + + public static boolean check(Geometry g, Class coordSeqClass, int dimension) { + CoordinateSequenceSchemaChecker checkCS = new CoordinateSequenceSchemaChecker( + coordSeqClass, dimension); + g.apply(checkCS); + return checkCS.isSame(); + } + + private Class coordSeqClass; + + private int dimension; + + private boolean isSame = true; + + public CoordinateSequenceSchemaChecker(Class coordSeqClass, int dimension) { + this.coordSeqClass = coordSeqClass; + this.dimension = dimension; + } + + public boolean isSame() { + return isSame; + } + + public void filter(CoordinateSequence seq, int i) { + if (seq.getClass() != coordSeqClass) + isSame = false; + if (seq.getDimension() != dimension) + isSame = false; + } + + public boolean isDone() { + return !isSame; + } + + + public boolean isGeometryChanged() { + return false; + } + + } + +} |