Package org.geotools.geometry.jts

Source Code of org.geotools.geometry.jts.GeometryCoordinateSequenceTransformer

/*
*    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;

import java.util.ArrayList;
import java.util.List;

import org.geotools.referencing.operation.transform.AffineTransform2D;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;

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;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;


/**
* Service object that takes a geometry and applies a {@link MathTransform}
* to the coordinates it contains, creating a new
* geometry as the transformed output.
* <p>
* The standard usage pattern is
* to supply a {@link MathTransform} and @link CoordinateReferenceSystem} explicitly.
* The {@link #transform(Geometry)} method can then be
* used to construct transformed geometries using the {@link GeometryFactory}
* and {@link CoordinateSequenceFactory} of the input geometry.
*
* @author Andrea Aime
* @author Martin Davis
*
*
* @source $URL$
*/
public class GeometryCoordinateSequenceTransformer {
    private MathTransform transform = null;
    private CoordinateReferenceSystem crs;
    private CoordinateSequenceTransformer inputCSTransformer = null;
    private CoordinateSequenceTransformer csTransformer = null;
  private GeometryFactory currGeometryFactory = null;

    private boolean curveCompatible;
   
    /**
     * Creates a transformer which uses the {@link CoordinateSequenceFactory}
     * of the source geometries.
     */
    public GeometryCoordinateSequenceTransformer() {
      // the csTransformer is initialized from the first geometry
      // and the supplied transform
    }

    /**
     * Creates a transformer which uses a client-specified
     * {@link CoordinateSequenceTransformer}.
     * <p>
     * <b>WARNING:</b> The CoordinateSequenceTransformer must use
     * the same {@link CoordinateSequenceFactory} as the output
     * GeometryFactory, so that geometries are constructed consistently. 
     * 
     * @param transformer
     */
    public GeometryCoordinateSequenceTransformer(CoordinateSequenceTransformer transformer) {
      inputCSTransformer = transformer;
      csTransformer = transformer;
    }

    /**
     * Sets the math transform to be used for transformation
     * @param transform
     */
    public void setMathTransform(MathTransform transform) {
        this.transform = transform;
        this.curveCompatible = isCurveCompatible(transform);
    }

    /**
     * Sets the target coordinate reference system.
     * <p>
     * This value is used to set the coordinate reference system of geometries
     * after they have been transformed.
     * </p>
     * @param crs The target coordinate reference system.
     */
    public void setCoordinateReferenceSystem(CoordinateReferenceSystem crs) {
        this.crs = crs;
    }
   
    /**
     * Initializes the internal CoordinateSequenceTransformer
     * if not specified explicitly.
     *
     * @param gf the factory to use
     */
    private void init(GeometryFactory gf)
    {
      // don't init if csTransformer already exists
      if (inputCSTransformer != null)
        return;
      // don't reinit if gf is the same (the usual case)
      if (currGeometryFactory == gf)
        return;
     
      currGeometryFactory = gf;
      CoordinateSequenceFactory csf = gf.getCoordinateSequenceFactory();
      csTransformer = new DefaultCoordinateSequenceTransformer(csf);
    }
   
    /**
     * Applies the transform to the provided geometry,
     * creating a new transformed geometry.
     *
     * @param g the geometry to transform
     * @return a new transformed geometry
     * @throws TransformException
     */
    public Geometry transform(Geometry g) throws TransformException {
        GeometryFactory factory = g.getFactory();
        Geometry transformed = null;
       
        // lazily init csTransformer using geometry's CSFactory
        init(factory);
       
        if (g instanceof Point) {
            transformed = transformPoint((Point) g, factory);
        } else if (g instanceof MultiPoint) {
            MultiPoint mp = (MultiPoint) g;
            Point[] points = new Point[mp.getNumGeometries()];

            for (int i = 0; i < points.length; i++) {
                points[i] = transformPoint((Point) mp.getGeometryN(i), factory);
            }

            transformed = factory.createMultiPoint(points);
        } else if (g instanceof LineString) {
            transformed = transformLineString((LineString) g, factory);
        } else if (g instanceof MultiLineString) {
            MultiLineString mls = (MultiLineString) g;
            LineString[] lines = new LineString[mls.getNumGeometries()];

            for (int i = 0; i < lines.length; i++) {
                lines[i] = transformLineString((LineString) mls.getGeometryN(i), factory);
            }

            transformed = factory.createMultiLineString(lines);
        } else if (g instanceof Polygon) {
            transformed = transformPolygon((Polygon) g, factory);
        } else if (g instanceof MultiPolygon) {
            MultiPolygon mp = (MultiPolygon) g;
            Polygon[] polygons = new Polygon[mp.getNumGeometries()];

            for (int i = 0; i < polygons.length; i++) {
                polygons[i] = transformPolygon((Polygon) mp.getGeometryN(i), factory);
            }

            transformed = factory.createMultiPolygon(polygons);
        } else if (g instanceof GeometryCollection) {
            GeometryCollection gc = (GeometryCollection) g;
            Geometry[] geoms = new Geometry[gc.getNumGeometries()];

            for (int i = 0; i < geoms.length; i++) {
                geoms[i] = transform(gc.getGeometryN(i));
            }

            transformed = factory.createGeometryCollection(geoms);
        } else {
            throw new IllegalArgumentException("Unsupported geometry type " + g.getClass());
        }
       
        //copy over user data
        // do a special check for coordinate reference system
        transformed.setUserData(g.getUserData());

        if ((g.getUserData() == null) || g.getUserData() instanceof CoordinateReferenceSystem) {
            //set the new one to be the target crs
            if (crs != null) {
                transformed.setUserData(crs);
            }
        }
       
        return transformed;
    }

    /**
     *
     * @throws TransformException
     */
    public LineString transformLineString(LineString ls, GeometryFactory gf)
        throws TransformException {
        if (ls instanceof CurvedGeometry<?> && curveCompatible) {
            return transformCurvedLineString((CurvedGeometry) ls, gf);
        } else {
            return transformStraightLineString(ls, gf);
        }
    }

    private boolean isCurveCompatible(MathTransform mt) {
        if (!(mt instanceof AffineTransform2D)) {
            return false;
        }

        AffineTransform2D at = (AffineTransform2D) mt;
        // return true if we are scaling by the same amount, and the rotational
        // elements are equal in absolute value
        return at.getScaleX() == at.getScaleY()
                && Math.abs(at.getShearX()) == Math.abs(at.getShearY());
    }

    private LineString transformStraightLineString(LineString ls, GeometryFactory gf)
            throws TransformException {
        // if required, init csTransformer using geometry's CSFactory
        init(gf);
       
        CoordinateSequence cs = projectCoordinateSequence(ls.getCoordinateSequence());
        LineString transformed = null;
       
        if (ls instanceof LinearRing) {
            transformed = gf.createLinearRing(cs);
        } else {
            transformed = gf.createLineString(cs);
        }
       
        transformed.setUserData( ls.getUserData() );
        return transformed;
    }

    private LineString transformCurvedLineString(CurvedGeometry<?> curved, GeometryFactory gf)
            throws TransformException {
        CurvedGeometryFactory cf = CurvedGeometries.getFactory(curved);
        if (curved instanceof SingleCurvedGeometry<?>) {
            SingleCurvedGeometry<?> single = (SingleCurvedGeometry<?>) curved;
            double[] controlPoints = single.getControlPoints();
            double[] target = new double[controlPoints.length];
            transform.transform(controlPoints, 0, target, 0, controlPoints.length / 2);
            return cf.createCurvedGeometry(2, target);
        } else {
            CompoundCurvedGeometry<?> compound = (CompoundCurvedGeometry<?>) curved;
            List<LineString> reprojected = new ArrayList<>();
            for (LineString component : compound.getComponents()) {
                LineString ls = transformLineString(component, gf);
                reprojected.add(ls);
            }
            return cf.createCurvedGeometry(reprojected);
        }

    }

    /**
     * @param point
     *
     * @throws TransformException
     */
    public Point transformPoint(Point point, GeometryFactory gf)
        throws TransformException {
     
        // if required, init csTransformer using geometry's CSFactory
        init(gf);

        CoordinateSequence cs = projectCoordinateSequence(point.getCoordinateSequence());
        Point transformed = gf.createPoint(cs);
        transformed.setUserData( point.getUserData() );
        return transformed;
    }

    /**
     * @param cs a CoordinateSequence
     *
     * @throws TransformException
     */
    private CoordinateSequence projectCoordinateSequence(CoordinateSequence cs)
        throws TransformException {
        return csTransformer.transform(cs, transform);
    }

    /**
     * @param polygon
     * @throws TransformException
     */
    public Polygon transformPolygon(Polygon polygon, GeometryFactory gf)
        throws TransformException {
        LinearRing exterior = (LinearRing) transformLineString(polygon.getExteriorRing(), gf);
        LinearRing[] interiors = new LinearRing[polygon.getNumInteriorRing()];

        for (int i = 0; i < interiors.length; i++) {
            interiors[i] = (LinearRing) transformLineString(polygon.getInteriorRingN(i), gf);
        }

        Polygon transformed = gf.createPolygon(exterior, interiors);
        transformed.setUserData( polygon.getUserData() );
        return transformed;
    }
}
TOP

Related Classes of org.geotools.geometry.jts.GeometryCoordinateSequenceTransformer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.