Package org.geotools.geometry.jts

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

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2014, 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.Arrays;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateFilter;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.CoordinateSequenceComparator;
import com.vividsolutions.jts.geom.CoordinateSequenceFilter;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryComponentFilter;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.GeometryFilter;
import com.vividsolutions.jts.geom.IntersectionMatrix;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.geom.impl.CoordinateArraySequence;

/**
* A CircularString is a sequence of zero or more connected circular arc segments. A circular arc
* segment is a curved segment defined by three points in a two-dimensional plane; the first point
* cannot be the same as the third point.
*
* @author Andrea Aime - GeoSolutions
*/
public class CircularString extends LineString implements SingleCurvedGeometry<LineString> {

    /**
     * Helper class that automates the scan of the list of CircularArc in the controlpoint sequence
     */
    abstract class ArcScan {
        public ArcScan() {
            if (controlPoints.length == 3) {
                // single arc case
                CircularArc arc = new CircularArc(controlPoints);
                visitArc(arc);
            } else {
                // go over each 3-points set and linearize it
                double[] arcControlPoints = new double[6];
                CircularArc arc = new CircularArc(arcControlPoints);
                for (int i = 0; i <= controlPoints.length - 6; i += 4) {
                    // have the arc work off the new control points
                    System.arraycopy(controlPoints, i, arcControlPoints, 0, 6);
                    arc.reset();
                    visitArc(arc);
                }
            }
        }

        protected abstract void visitArc(CircularArc arc);

    }

    private static final long serialVersionUID = -5796254063449438787L;

    /**
     * This sequence is used as a fake to trick the constructor
     */
    static final CoordinateSequence FAKE_STRING_2D = new CoordinateArraySequence(new Coordinate[] {
            new Coordinate(0, 0), new Coordinate(1, 1) });

    double[] controlPoints;

    double tolerance;

    LineString linearized;

    public CircularString(CoordinateSequence points, GeometryFactory factory, double tolerance) {
        super(FAKE_STRING_2D, factory);
        this.tolerance = tolerance;
        if (points.getDimension() != 2) {
            throw new IllegalArgumentException("Circular strings are restricted to 2 dimensions "
                    + "at the moment. Contributions to get ND support welcomed!");
        }

        int pointCount = points.size();
        controlPoints = new double[pointCount * 2];
        for (int i = 0; i < pointCount; i++) {
            controlPoints[i * 2] = points.getX(i);
            controlPoints[i * 2 + 1] = points.getY(i);
        }
        init(controlPoints, tolerance);
    }

    public CircularString(double[] controlPoints, GeometryFactory factory, double tolerance) {
        super(FAKE_STRING_2D, factory);
        init(controlPoints, tolerance);
    }

    private void init(double[] controlPoints, double tolerance) {
        int length = controlPoints.length;
        if (length % 2 != 0) {
            throw new IllegalArgumentException(
                    "Invalid number of ordinates, must be even, but it is " + length + " instead");
        }
        int pointCount = length / 2;
        if (pointCount < 3 || (pointCount > 3 && (pointCount % 2) == 0)) {
            throw new IllegalArgumentException("Invalid number of points, a circular string"
                    + "is always made of an odd number of points, with a mininum of 3, "
                    + "and adding 2 for each extra circular arc in the sequence");
        }
        this.controlPoints = controlPoints;
        this.tolerance = tolerance;
    }

    @Override
    public double[] getControlPoints() {
        return controlPoints;
    }

    @Override
    public double getTolerance() {
        return tolerance;
    }

    @Override
    public int getNumArcs() {
        return (controlPoints.length - 6) / 4 + 1;
    }

    @Override
    public CircularArc getArcN(int arcIndex) {
        int baseIdx = arcIndex * 4;
        double[] arcControlPoints = new double[6];
        System.arraycopy(controlPoints, baseIdx, arcControlPoints, 0, 6);
        CircularArc arc = new CircularArc(arcControlPoints);
        return arc;
    }

    @Override
    public LineString linearize() {
        return linearize(this.tolerance);
    }


    public LineString linearize(double tolerance) {
        // use the cached one if we are asked for the default geometry tolerance
        boolean isDefaultTolerance = CircularArc.equals(tolerance, this.tolerance);
        if (linearized != null && isDefaultTolerance) {
            return linearized;
        }

        CoordinateSequence cs = getLinearizedCoordinateSequence(tolerance);
        LineString result = new LineString(cs, factory);
        if (isDefaultTolerance) {
            linearized = result;
        }

        return result;
    }

    public CoordinateSequence getLinearizedCoordinateSequence(final double tolerance) {
        boolean isDefaultTolerance = CircularArc.equals(tolerance, this.tolerance);
        if (linearized != null && isDefaultTolerance) {
            return linearized.getCoordinateSequence();
        }

        final GrowableOrdinateArray gar = new GrowableOrdinateArray();
        new ArcScan() {

            protected void visitArc(CircularArc arc) {
                // if it's not the first arc, we need to eliminate the last point,
                // as the end point of the last arc is the start point of the new one
                if (gar.size() > 0) {
                    gar.setSize(gar.size() - 2);
                }
                arc.linearize(tolerance, gar);
            }

        };

        CoordinateSequence cs = gar.toCoordinateSequence(getFactory());
        return cs;
    }

    /* Optimized overridden methods */

    public boolean isClosed() {
        return controlPoints[0] == controlPoints[controlPoints.length - 2]
                && controlPoints[1] == controlPoints[controlPoints.length - 1];
    }

    public int getDimension() {
        return super.getDimension();
    }

    public int getBoundaryDimension() {
        return super.getDimension();
    }

    public boolean isEmpty() {
        return false;
    }

    public String getGeometryType() {
        return "CircularString";
    }

    public Geometry reverse() {
        // reverse the control points
        double[] reversed = new double[controlPoints.length];
        System.arraycopy(controlPoints, 0, reversed, 0, controlPoints.length);
        GrowableOrdinateArray array = new GrowableOrdinateArray();
        array.addAll(controlPoints);
        array.reverseOrdinates(0, array.size() - 1);
        return new CircularString(array.getData(), getFactory(), tolerance);
    }

    public Point getInteriorPoint() {
        int idx = controlPoints.length / 2;
        return new Point(new CoordinateArraySequence(new Coordinate[] { new Coordinate(
                controlPoints[idx], controlPoints[idx + 1]) }), getFactory());
    }

    public Geometry getEnvelope() {
        return super.getEnvelope();
    }

    public Envelope getEnvelopeInternal() {
        return super.getEnvelopeInternal();
    }

    @Override
    protected Envelope computeEnvelopeInternal() {
        final Envelope result = new Envelope();
        new ArcScan() {

            protected void visitArc(CircularArc arc) {
                arc.expandEnvelope(result);
            }

        };

        return result;
    }

    public int getNumGeometries() {
        return 1;
    }

    public Geometry getGeometryN(int n) {
        return this;
    }

    public void setUserData(Object userData) {
        super.setUserData(userData);
    }

    public int getSRID() {
        return super.getSRID();
    }

    public void setSRID(int SRID) {
        super.setSRID(SRID);
    }

    public GeometryFactory getFactory() {
        return super.getFactory();
    }

    public Object getUserData() {
        return super.getUserData();
    }

    public PrecisionModel getPrecisionModel() {
        return super.getPrecisionModel();
    }

    public boolean isRectangle() {
        return false;
    }

    public boolean equalsExact(Geometry other) {
        return equalsExact(other, 0);
    }

    public boolean equalsExact(Geometry other, double tolerance) {
        if (other instanceof CircularString) {
            CircularString csOther = (CircularString) other;
            if (Arrays.equals(controlPoints, csOther.controlPoints)) {
                return true;
            }
        }
        return linearize(tolerance).equalsExact(other, tolerance);
    }

    public boolean equals(Geometry other) {
        if (other instanceof CircularString) {
            CircularString csOther = (CircularString) other;
            if (Arrays.equals(controlPoints, csOther.controlPoints)) {
                return true;
            }
        }
        return linearize().equals(other);
    }

    public boolean equalsTopo(Geometry other) {
        if (other instanceof CircularString) {
            CircularString csOther = (CircularString) other;
            if (Arrays.equals(controlPoints, csOther.controlPoints)) {
                return true;
            }
        }
        return linearize().equalsTopo(other);
    }

    public boolean equals(Object o) {
        if (o instanceof Geometry) {
            return equals((Geometry) o);
        } else {
            return false;
        }
    }

    public int hashCode() {
        return super.hashCode();
    }

    public String toString() {
        return toCurvedText();
    }

    public String toCurvedText() {
        StringBuilder sb = new StringBuilder("CIRCULARSTRING(");
        for (int i = 0; i < controlPoints.length;) {
            sb.append(controlPoints[i++] + " " + controlPoints[i++]);
            if (i < controlPoints.length) {
                sb.append(", ");
            }
        }
        sb.append(")");
        return sb.toString();
    }

    public boolean equalsNorm(Geometry g) {
        return super.equalsNorm(g);
    }

    public Point getPointN(int n) {
        if (n == 0) {
            return getStartPoint();
        } else {
            return linearize().getPointN(n);
        }
    }

    public Point getStartPoint() {
        return new Point(new CoordinateArraySequence(new Coordinate[] { new Coordinate(
                controlPoints[0], controlPoints[1]) }), getFactory());
    }

    public Point getEndPoint() {
        return new Point(
                new CoordinateArraySequence(new Coordinate[] { new Coordinate(
                        controlPoints[controlPoints.length - 2],
                        controlPoints[controlPoints.length - 1]) }), getFactory());
    }

    /*
     * Simple linearized delegate methods
     */

    public Coordinate[] getCoordinates() {
        return linearize().getCoordinates();
    }

    public CoordinateSequence getCoordinateSequence() {
        return linearize().getCoordinateSequence();
    }

    public Coordinate getCoordinateN(int n) {
        return linearize().getCoordinateN(n);
    }

    public Coordinate getCoordinate() {
        return linearize().getCoordinate();
    }

    public int getNumPoints() {
        return linearize().getNumPoints();
    }

    public boolean isRing() {
        return linearize().isRing();
    }

    public double getLength() {
        // todo: maybe compute the actual circular length?
        return linearize().getLength();
    }

    public Geometry getBoundary() {
        return linearize().getBoundary();
    }

    public boolean isCoordinate(Coordinate pt) {
        return linearize().isCoordinate(pt);
    }

    public void apply(CoordinateFilter filter) {
        linearize().apply(filter);
    }

    public void apply(CoordinateSequenceFilter filter) {
        linearize().apply(filter);
    }

    public void apply(GeometryFilter filter) {
        linearize().apply(filter);
    }

    public void apply(GeometryComponentFilter filter) {
        linearize().apply(filter);
    }

    public void normalize() {
        linearize().normalize();
    }

    public boolean isSimple() {
        return linearize().isSimple();
    }

    public boolean isValid() {
        return linearize().isValid();
    }

    public double distance(Geometry g) {
        return linearize().distance(g);
    }

    public boolean isWithinDistance(Geometry geom, double distance) {
        return linearize().isWithinDistance(geom, distance);
    }


    public double getArea() {
        return linearize().getArea();
    }

    public Point getCentroid() {
        return linearize().getCentroid();
    }

    public void geometryChanged() {
        linearize().geometryChanged();
    }

    public boolean disjoint(Geometry g) {
        return linearize().disjoint(g);
    }

    public boolean touches(Geometry g) {
        return linearize().touches(g);
    }

    public boolean intersects(Geometry g) {
        return linearize().intersects(g);
    }

    public boolean crosses(Geometry g) {
        return linearize().crosses(g);
    }

    public boolean within(Geometry g) {
        return linearize().within(g);
    }

    public boolean contains(Geometry g) {
        return linearize().contains(g);
    }

    public boolean overlaps(Geometry g) {
        return linearize().overlaps(g);
    }

    public boolean covers(Geometry g) {
        return linearize().covers(g);
    }

    public boolean coveredBy(Geometry g) {
        return linearize().coveredBy(g);
    }

    public boolean relate(Geometry g, String intersectionPattern) {
        return linearize().relate(g, intersectionPattern);
    }

    public IntersectionMatrix relate(Geometry g) {
        return linearize().relate(g);
    }



    public Geometry buffer(double distance) {
        return linearize().buffer(distance);
    }

    public Geometry buffer(double distance, int quadrantSegments) {
        return linearize().buffer(distance, quadrantSegments);
    }

    public Geometry buffer(double distance, int quadrantSegments, int endCapStyle) {
        return linearize().buffer(distance, quadrantSegments, endCapStyle);
    }

    public Geometry convexHull() {
        return linearize().convexHull();
    }

    public Geometry intersection(Geometry other) {
        return linearize().intersection(other);
    }

    public Geometry union(Geometry other) {
        return linearize().union(other);
    }

    public Geometry difference(Geometry other) {
        return linearize().difference(other);
    }

    public Geometry symDifference(Geometry other) {
        return linearize().symDifference(other);
    }

    public Geometry union() {
        return linearize().union();
    }

    public Geometry norm() {
        return linearize().norm();
    }

    public int compareTo(Object o) {
        return linearize().compareTo(o);
    }

    public int compareTo(Object o, CoordinateSequenceComparator comp) {
        return linearize().compareTo(o, comp);
    }

    @Override
    public String toText() {
        return linearize().toText();
    }

    @Override
    public int getCoordinatesDimension() {
        return 2;
    }

}
TOP

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

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.