/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2006-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.iso.primitive; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.geotools.geometry.iso.coordinate.CurveSegmentImpl; import org.geotools.geometry.iso.coordinate.DirectPositionImpl; import org.geotools.geometry.iso.coordinate.EnvelopeImpl; import org.geotools.geometry.iso.coordinate.GeometryFactoryImpl; import org.geotools.geometry.iso.coordinate.LineStringImpl; import org.geotools.geometry.iso.coordinate.PointArrayImpl; import org.geotools.geometry.iso.coordinate.PositionImpl; import org.geotools.geometry.iso.io.GeometryToString; import org.geotools.geometry.iso.operation.IsSimpleOp; import org.geotools.geometry.iso.operation.Merger; import org.geotools.geometry.iso.util.DoubleOperation; import org.geotools.geometry.iso.util.algorithmND.AlgoPointND; import org.opengis.geometry.DirectPosition; import org.opengis.geometry.Envelope; import org.opengis.geometry.Geometry; import org.opengis.geometry.MismatchedDimensionException; import org.opengis.geometry.complex.CompositeCurve; import org.opengis.geometry.coordinate.GeometryFactory; import org.opengis.geometry.coordinate.LineSegment; import org.opengis.geometry.coordinate.LineString; import org.opengis.geometry.coordinate.ParamForPoint; import org.opengis.geometry.coordinate.Position; import org.opengis.geometry.primitive.Curve; import org.opengis.geometry.primitive.CurveBoundary; import org.opengis.geometry.primitive.CurveSegment; import org.opengis.geometry.primitive.OrientableCurve; import org.opengis.geometry.primitive.OrientablePrimitive; import org.opengis.geometry.primitive.Point; import org.opengis.geometry.primitive.PrimitiveFactory; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.MathTransform; import org.opengis.referencing.operation.TransformException; /** * Curve (Figure 11 of the ISO 19107 v5) is a descendent subtype of Primitive * through OrientablePrimitive. It is the basis for 1-dimensional geometry. A * curve is a continuous image of an open interval and so could be written as a * parameterized function such as c(t):(a, b) -> E^n where "t" is a real * parameter and E^n is Euclidean space of dimension n (usually 2 or 3, as * determined by the coordinate reference system). Any other parameterization * that results in the same image curve, traced in the same direction, such as * any linear shifts and positive scales such as e(t) = c(a + t(b-a)):(0,1) -> * E^n, is an equivalent representation of the same curve. For the sake of * simplicity, Curves should be parameterized by arc length, so that the * parameterization operation inherited from GenericCurve will be valid for * parameters between 0 and the length of the curve. * * Curves are continuous, connected, and have a measurable length in terms of * the coordinate system. The orientation of the curve is determined by this * parameterization, and is consistent with the tangent function, which * approximates the derivative function of the parameterization and shall always * point in the "forward" direction. The parameterization of the reversal of the * curve defined by c(t):(a, b) -> E^n would be defined by a function of the * form s(t) = c(a + b - t):(a, b)?E^n. * * A curve is composed of one or more curve segments. Each curve segment within * a curve may be defined using a different interpolation method. The curve * segments are connected to one another, with the end point of each segment * except the last being the start point of the next segment in the segment * list. * * * * * @source $URL$ * @version <A HREF="http://www.opengis.org/docs/01-101.pdf">Abstract * Specification V5</A> * @author Jackson Roehrig & Sanjay Jena * */ public class CurveImpl extends OrientableCurveImpl implements Curve { private static final long serialVersionUID = -9117646009629975742L; /** * The association "segmentation" lists the CurveSegments of Curve, each of * which defines the direct position of points along a portion of the curve. * The order of the CurveSegments is the order in which they are used to * trace the Curve. * * Curve::segment [1..n] : Sequence<CurveSegment> _______________________ * CurveSegment::curve [0,1] : Reference<Curve> * * For a particular parameter interval, the Curve and CurveSegment agree. * * CurveSegment: * * {curve.startParam() <= self.startParam()}; * * {curve.endParam() >= self.endParam()}; * * {self.startParam() < self.endParam()}; * * {s : Distance (startParam() <= s <= endParam()) implies * * (curve.parameterization(s) = self.parameterization(s))} * * * NOTE: In the standard, curve segments do not appear except in the context * of a curve, and therefore the cardinality of the “curve” role in this * association could be “1” which would preclude the use of curve segments * except in this manner. While this would not affect this Standard, leaving * the cardinality as “0..1” allows other standards based on this one to use * curve segments in a more open-ended manner. * * The field type AbstractSequentialList<CurveSegmentImpl> is implemented * mainly outside of the feature geometry packages. The curve implementation * iterates through segment, which could access its elements on the fly from * any source. The segments may not be necessarily stored in the memory. */ private List<CurveSegment> curveSegments = null; private EnvelopeImpl envelope = null; /** * Boundary of the Curve */ protected CurveBoundaryImpl boundary = null; /** * The Curve constructor takes an abstract sequential list of CurveSegments * with the appropriate end-to-start relationships and creates a Curve. * * Curve::Curve(segment[1..n] : CurveSegment) : Curve * * The start position of the first segment and the end position of the last * segment must be associated to a PointImpl. If they are associated instead * of that to a direct position, then this direct position will be used to * construct a new Point. * * @param crs * @param segments * @throws IllegalArgumentException, * if the array of CurveSegments is empty or does not fulfill * the requirements of the CurveSegments */ public CurveImpl(CoordinateReferenceSystem crs, List<? extends CurveSegment> segments) throws IllegalArgumentException { super(crs); this.initialize(segments); } /** * The Curve constructor takes an abstract sequential list of CurveSegments * with the appropriate end-to-start relationships and creates a Curve. * * Curve::Curve(segment[1..n] : CurveSegment) : Curve * * The start position of the first segment and the end position of the last * segment must be associated to a PointImpl. If they are associated instead * of that to a direct position, then this direct position will be used to * construct a new Point. * * Contained primitives must be curve segments or points. If it is a curve * * @param factory * @param segments * @param containedPrimitive * @param containingPrimitive * @param complex * @throws IllegalArgumentException */ // TODO Selbe frage auch hier: brauchen wir diesen constructor? // public CurveImpl(FeatGeomFactoryImpl factory, List<CurveSegmentImpl> // segments, // Set<Primitive> containedPrimitive, // Set<Primitive> containingPrimitive, Set<Complex> complex) // throws IllegalArgumentException { // super(factory, containedPrimitive, containingPrimitive, complex); // this.initialize(segments); // } public CurveImpl(LineSegment edge) { this( edge.getControlPoints().getCoordinateReferenceSystem(), Collections.singletonList( edge ) ); } /** * Initialize Curve attributes - Set segments - Calculate Envelope - * Calculate Parametrisation * * @param segments */ private void initialize(List<? extends CurveSegment> segments) { if ((segments == null) || segments.isEmpty()) throw new IllegalArgumentException( "The list of CurveSegments ist empty."); //$NON-NLS-1$ // set the segment this.curveSegments = (List<CurveSegment>) segments; // set the curve envelope Iterator<? extends CurveSegment> it = segments.iterator(); CurveSegmentImpl cs0 = (CurveSegmentImpl) it.next(); cs0.setCurve(this); this.envelope = new EnvelopeImpl(cs0.getEnvelope()); Position p0 = cs0.getStartPosition(); // Änderung durch Sanjay, da in bisheriger Version nicht der Fall // berücksichtigt wurde, dass nur 1 CurveSegment existiert CurveSegmentImpl cs1 = null; while (it.hasNext()) { cs1 = (CurveSegmentImpl) it.next(); // set the segment / curve association cs1.setCurve(this); // expand the curve envelope this.envelope.expand(cs1.getEnvelope()); if (!cs0.getEndPoint().equals(cs1.getStartPoint())) { throw new IllegalArgumentException( "Curvesegments are not continuous. Following curve segments are disjoint:" //$NON-NLS-1$ + cs0 + " and " + cs1); //$NON-NLS-1$ } cs0 = cs1; } Position p1 = cs0.getEndPosition(); Point pt0 = toPoint( p0 ); Point pt1 = toPoint( p1 ); if (pt0 == null) { DirectPositionImpl copy = new DirectPositionImpl(p0.getDirectPosition()); pt0 = new PointImpl(copy); //pt0 = this.getFeatGeometryFactory().getPrimitiveFactory().createPoint(p0); } if (pt1 == null) { DirectPositionImpl copy = new DirectPositionImpl(p1.getDirectPosition()); pt1 = new PointImpl(copy); //pt1 = this.getFeatGeometryFactory().getPrimitiveFactory().createPoint(p1); } // Calculate and Set Boundary this.boundary = this.calculateBoundary(pt0, pt1); /* Calculate Parametrisation */ this.calculateParametrisation(); } private Point toPoint( Position position ){ if( position instanceof Point ){ return (Point) position; } return new PointImpl( new DirectPositionImpl(position)); } /** * Calculates the Boundary for the curve * * @param start * @param end * @return CurveBoundary */ private CurveBoundaryImpl calculateBoundary(Point start, Point end) { // Return null if start point and end point are equal. // This is a design decision made by us, since the Abstract // Specification does not give any restrictions in that point. if (start.equals(end)) return null; else // Return the CurveBoundary defined by the start and end point of this curve return new CurveBoundaryImpl(getCoordinateReferenceSystem(), start, end); //return this.getFeatGeometryFactory().getPrimitiveFactory().createCurveBoundary(start, end); } public OrientableCurve[] getProxy() { return (OrientableCurve[]) super.getProxy(); } /* * (non-Javadoc) * * @see org.geotools.geometry.featgeom.root.GeometryImpl#clone() */ public CurveImpl clone() throws CloneNotSupportedException { // Test OK // Create a new Curve by cloning the direct positions which define the control points of this curve List<DirectPosition> dPList = this.asDirectPositions(); List<DirectPosition> newDPList = new ArrayList<DirectPosition>(); for (int i=0; i<dPList.size(); i++) { newDPList.add( new DirectPositionImpl( dPList.get(i) )); } List<Position> rPositions = new LinkedList<Position>(); for (int i = 0; i < newDPList.size(); i++) { rPositions.add(new PositionImpl(newDPList.get(i))); } // Create List of Position´s List<Position> positionList = rPositions; // Create List of CurveSegment´s (LineString´s) LineStringImpl lineString = new LineStringImpl(new PointArrayImpl( positionList), 0.0); List<CurveSegment> segments = new ArrayList<CurveSegment>(); segments.add(lineString); return new CurveImpl(crs, segments); //return (CurveImpl) this.getFeatGeometryFactory().getPrimitiveFactory().createCurveByDirectPositions(newDPList); } /* * (non-Javadoc) * * @see org.geotools.geometry.featgeom.primitive.OrientablePrimitiveImpl#createProxy() */ protected OrientablePrimitive createProxy() { // TODO semantic SJ, JR // TODO implementation // TODO test // TODO documentation return new CurveProxy(this); } /* * (non-Javadoc) * * @see org.geotools.geometry.featgeom.primitive.PrimitiveImpl#getBoundary() */ public CurveBoundary getBoundary() { // Returns the boundary of this Curve, which is of type CurveBoundary return this.boundary; } /* * (non-Javadoc) * * @see org.geotools.geometry.featgeom.root.GeometryImpl#getEnvelope() */ public Envelope getEnvelope() { // Return the envelope of this Curve return this.envelope; } /** * @param distance */ public void split(double distance) { for (CurveSegment curveSegment : this.curveSegments) { ((CurveSegmentImpl) curveSegment).split(distance); } } /** * @param dist * @return CurveSegmentImpl */ protected CurveSegmentImpl getSegmentAt(double dist) { // if ( this.orientation() == // OrientablePrimitive.Orientation.NEGATIVE) dist = this.length - // dist; if (this.curveSegments == null) return null; double length = 0.0; for (CurveSegment curveSegment : this.curveSegments) { length = DoubleOperation.add(length, ((CurveSegmentImpl) curveSegment).length()); //length += ((CurveSegmentImpl) curveSegment).length(); if (dist < length) return (CurveSegmentImpl) curveSegment; } return (CurveSegmentImpl) this.curveSegments.get(this.curveSegments .size() - 1); } /** * The operations "startPoint" shall return the DirectPositions of the first * point, respectively on the GenericCurve. This differs from the boundary * operator in Primitive, since it returns only the values of these two * points, not representative objects. GenericCurve::startPoint() : * DirectPosition2D * * @return an <code>DirectPosition2D</code> value */ public DirectPosition getStartPoint() { // Return first Point of this curve return this.curveSegments.get(0).getStartPoint(); } /** * The operations "endPoint" shall return the DirectPositions of the last * point, respectively on the GenericCurve. This differs from the boundary * operator in Primitive, since it returns only the values of these two * points, not representative objects. GenericCurve::startPoint() : * DirectPosition2D * * @return an <code>DirectPosition2D</code> value */ /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#getEndPoint() */ public DirectPosition getEndPoint() { /* Return End Point of last CurveSegment */ return this.curveSegments.get(this.curveSegments.size() - 1) .getEndPoint(); } /** * The operation "paramForPoint" shall return the parameter for this * GenericCurve at the passed DirectPosition. If the DirectPosition is not * on the curve, the nearest point on the curve shall be used. * * GenericCurve::paramForPoint(p : DirectPosition2D) : Set<Distance>, * DirectPosition2D * * The DirectPosition closest is the actual value for the "p" used, that is, * it shall be the point on the GenericCurve closest to the coordinate * passed in as "p". The return set will contain only one distance, unless * the curve is not simple. If there is more than one DirectPosition on the * GenericCurve at the same minimal distance from the passed "p", the return * value may be an arbitrary choice of one of the possible answers. * * @param p * an <code>DirectPosition2D</code> value * @return Array of parameters for the Position */ /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#getParamForPoint(org.opengis.geometry.coordinate.DirectPosition) */ public ParamForPoint getParamForPoint(DirectPosition p) { // TODO semantic SJ, JR // TODO implementation // TODO test // TODO documentation /* Initialise paramForPoints with set of first Segment */ ParamForPoint paramForPoints = this.curveSegments.get(0) .getParamForPoint(p); double minDistanceSquare = AlgoPointND.getDistanceSquare(p.getCoordinate(), paramForPoints.getPosition().getCoordinate()); //double minDistanceSquare = ((DirectPositionImpl) p).distanceSquare(paramForPoints.getDirectPosition()); double actDistanceSquare = 0.0; /* Loop all other segments and check if the distance of them is smaller */ for (int i = 1; i < this.curveSegments.size(); i++) { ParamForPoint paramForPoints1 = this.curveSegments.get(i) .getParamForPoint(p); actDistanceSquare = AlgoPointND.getDistanceSquare(p.getCoordinate(), paramForPoints1.getPosition().getCoordinate()); //actDistanceSquare = ((DirectPositionImpl) p).distanceSquare(paramForPoints1.getDirectPosition()); if (actDistanceSquare <= minDistanceSquare) { // TODO // /* If other params are closer, clear list of params */ // if (actDistanceSquare < minDistanceSquare) { // ((ParamForPoint)paramForPoints).clear(); // } // /* Add new minimal distances to list of params */ // for (int j = 0; j < obj.length; j++) { // paramForPoints.add((Double) obj[j]); // } // minDistanceSquare = actDistanceSquare; } } return paramForPoints; } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#forParam(double) */ public DirectPosition forParam(double distance) { // Test ok - valid for n dimensional space if (distance < this.getStartParam() || distance > this.getEndParam()) throw new IllegalArgumentException("Distance parameter not in parametrisation range."); //$NON-NLS-1$ int index = 0; while (index < this.curveSegments.size() && distance > this.curveSegments.get(index).getEndParam()) { index++; } /* Return DirectPosition using the same function of the Curve Segment */ return this.curveSegments.get(index).forParam(distance); } // /** // * The operation "constrParam" shall be an alternate representation of the // * curve as the continuous image of a real number interval without the // * restriction that the parameter represents the arc length of the curve, // * nor restrictions between a Curve and its component CurveSegments. The // * most common use of this operation is to expose the constructive equations // * of the underlying curve, especially useful when that curve is used to // * construct a parametric surface. // * // * GenericCurve::constrParam(cp : Real) : DirectPosition2D // * // * @param cp // * a <code>double</code> value // * @return an <code>DirectPosition2D</code> value // */ // public DirectPosition constrParam(double cp) { // return this.forParam(DoubleOperation.mult(cp, this.length())); // } /* (non-Javadoc) * @see org.opengis.geometry.coordinate.GenericCurve#length(double, double) */ public double length(double par1, double par2) { if (par1 < 0 || par2 > this.length()) throw new IllegalArgumentException( "Parameter out of parametrisation range."); //$NON-NLS-1$ /* Return difference of the two parameters */ return DoubleOperation.subtract(par2, par1); } /** * This third form of the operation length returns length(0.0,length) * * @return length */ public double length() { /* Return absolute difference between End and Start Param */ return Math.abs(DoubleOperation.subtract(this.getEndParam(), this.getStartParam())); } /** * The function "asLineString" constructs a line string (sequence of line * segments) where the control points (ends of the segments) lie on this * curve. If "maxSpacing" is given (not zero), then the distance between * control points along the generated curve is not more than "maxSpacing". * If "maxOffset" is given (not zero), the distance between generated curve * at any point and the original curve is be more than the "maxOffset". If * both parameters are set, then both criteria are met. If the original * control points of the curve lie on the curve, then they are included in * the returned LineString's controlPoints. If both parameters are set to * zero, then the line string returned is constructed from the control * points of the original curve. * * GenericCurve::asLineString(spacing : Distance = 0, offset : Distance = 0) : * LineString * * NOTE This function is useful in creating linear approximations of the * curve for simple actions such as display. It is often referred to as a * "stroked curve". For this purpose, the "maxOffset" version is useful in * maintaining a minimal representation of the curve appropriate for the * display device being targeted. This function is also useful in preparing * to transform a curve from one coordinate reference system to another by * transforming its control points. In this case, the "maxSpacing" version * is more appropriate. Allowing both parameters to default to zero does not * seem to have any useful geographic nor geometric interpretation unless * further information is known about how the curves were constructed. * * @return an <code>LineString</code> value */ public List<LineSegment> asLineSegments() { /* Schleife ueber alle CurveSegments */ ArrayList<LineSegment> mergedSegments = new ArrayList<LineSegment>(); for (CurveSegment curveSegment : this.curveSegments) { LineString lineString = curveSegment.asLineString(0, 0); List<LineSegment> lineSegments = lineString.asLineSegments(); for (LineSegment lineSegment : lineSegments) mergedSegments.add(lineSegment); } return mergedSegments; } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#asLineString(double, * double) */ public LineStringImpl asLineString(double spacing, double offset) { // TODO semantic SJ, JR // TODO implementation // TODO test // TODO documentation if (this.curveSegments.isEmpty()) return null; CurveSegment seg = this.curveSegments.get(0); LineStringImpl ls = (LineStringImpl) seg.asLineString(spacing, offset); // TODO Wirft fehler // UEber FActory instanzieren! LineStringImpl result = new LineStringImpl(ls); for (int i = 1; i < this.curveSegments.size(); ++i) { seg = this.curveSegments.get(i); ls = (LineStringImpl) seg.asLineString(spacing, offset); result = result.merge(ls); } /* Set StartParam for new LineString */ result.setStartParam(this.getStartParam()); /* Set EndParam for new LineString */ result.setEndParam(this.getEndParam()); return result; } /** * @return LineStringImpl */ public LineStringImpl asLineString() { return this.asLineString(0.0, 0.0); } /** * The method <code>dimension</code> returns the inherent dimension of * this Object, which is less than or equal to the coordinate dimension. The * dimension of a collection of geometric objects is the largest dimension * of any of its pieces. Points are 0-dimensional, curves are 1-dimensional, * surfaces are 2-dimensional, and solids are 3-dimensional. Locally, the * dimension of a geometric object at a point is the dimension of a local * neighborhood of the point - that is the dimension of any coordinate * neighborhood of the point. Dimension is unambiguously defined only for * DirectPositions interior to this Object. If the passed DirectPosition2D * is NULL, then the method returns the largest possible dimension for any * DirectPosition2D in this Object. * * @param point * a <code>DirectPosition2D</code> value * @return an <code>int</code> value */ /* * (non-Javadoc) * * @see org.geotools.geometry.featgeom.root.GeometryImpl#getDimension(org.opengis.geometry.coordinate.DirectPosition) */ public int getDimension(DirectPosition point) { // TODO semantic SJ, JR // TODO implementation // TODO test // TODO documentation if (point == null) return 1; return Math.min(point.getDimension(), 1); } /** * Sets the Parametization values for the Curvesegments Start- and End Param * Constructed Start- and End Param */ private void calculateParametrisation() { if (this.curveSegments == null || this.curveSegments.size() == 0) throw new IllegalArgumentException("Segment array not set."); //$NON-NLS-1$ double tmpLineLength = 0; double totalValue = 0; for (int i = 0; i < this.curveSegments.size(); i++) { // Get length of the LineString (before updating the StartParam of the CurveSegment) tmpLineLength = ((LineStringImpl) (this.curveSegments.get(i))) .length(); // Set Start Param ((LineStringImpl) this.curveSegments.get(i)) .setStartParam(totalValue); // Add length of LineString to total length totalValue = DoubleOperation.add(totalValue, tmpLineLength); //totalValue += tmpLineLength; // Set End Param ((LineStringImpl) this.curveSegments.get(i)) .setEndParam(totalValue); } // LineStringImpl tmpLineString = null; // for (int i = 0; i < this.curveSegments.size(); i++) { // tmpLineString = (LineStringImpl) this.curveSegments.get(i); // // JR gelöscht // } } /* * (non-Javadoc) * * @see org.geotools.geometry.featgeom.root.GeometryImpl#getRepresentativePoint() */ public DirectPosition getRepresentativePoint() { // Return point in the middle of the curve return this.forConstructiveParam(0.5); } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.root.Geometry#isSimple() */ public boolean isSimple() { // Test ok // Test simplicity by building a topological graph and testing for self-intersection IsSimpleOp simpleOp = new IsSimpleOp(); return simpleOp.isSimple(this); } /* * (non-Javadoc) * * @see org.opengis.geometry.primitive.Curve#getSegments() */ public List<CurveSegment> getSegments() { // ok // Return the CurveSegments that define this curve return this.curveSegments; } /* * (non-Javadoc) * * @see org.opengis.geometry.primitive.OrientableCurve#getComposite() */ public CompositeCurve getComposite() { // TODO semantic SJ, JR // TODO implementation // TODO test // TODO documentation return null; } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#getTangent(double) */ public double[] getTangent(double distance) { // Test OK - valid for n dimensional space if (distance < this.getStartParam() || distance > this.getEndParam()) throw new IllegalArgumentException("Distance parameter not in parametrisation range."); //$NON-NLS-1$ // Loop all Segments (LineStrings) until the the LineString, which // contains position at distance, is found int i = 0; while (this.curveSegments.get(i).getEndParam() < distance && i < curveSegments.size()) { i++; } /* Delegate work to according LineString */ return this.curveSegments.get(i).getTangent(distance); } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#getStartParam() */ public double getStartParam() { // Test ok /* The StartParam for a Curve shall always be 0. */ return 0.0; } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#getEndParam() */ public double getEndParam() { // Test ok /* Return EndParam of last Curve Segment */ return this.curveSegments.get(this.curveSegments.size() - 1) .getEndParam(); } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#getStartConstructiveParam() */ public double getStartConstructiveParam() { // Test ok /* The StartConstrParam for a Curve shall always be 0. */ return 0.0; } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#getEndConstructiveParam() */ public double getEndConstructiveParam() { // Test ok /* The EndConstrParam for a Curve shall always be 1. */ return 1; } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#forConstructiveParam(double) */ public DirectPosition forConstructiveParam(double cp) { // Test ok - valid for n dimensional space // Return the Position at param (cp * lengthOfLineString) double par = DoubleOperation.mult(cp, this.length()); return this.forParam(par); } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.GenericCurve#length(org.opengis.geometry.coordinate.Position, * org.opengis.geometry.coordinate.Position) */ public double length(Position point1, Position point2) { // TODO semantic SJ, JR // TODO implementation // TODO test // TODO documentation /* Default-Values */ if (point1 == null && point2 == null) return this.length(); // if (point1 == null) // point1 = new PositionImpl(this.getStartPoint()); // if (point2 == null) // point2 = new PositionImpl(this.getEndPoint()); /* Get all Params for closest points to startposition point1 */ ParamForPoint startParams = this.getParamForPoint(point1.getDirectPosition()); /* Get all Params for closest points to endposition point2 */ ParamForPoint endParams = this.getParamForPoint(point2.getDirectPosition()); /* * Compare the distances between each found startParam and endParam and * choose the smallest one */ double minDistance = Math.abs(DoubleOperation.subtract(startParams.getDistance(), endParams.getDistance())); // double actDistance = 0.0; // for (int i = 1; i < startParams.length; i++) { // for (int j = 1; i < endParams.length; j++) { // actDistance = Math.abs((Double) this.getStartParams[0] // - (Double) endParams[0]); // if (actDistance < minDistance) { // minDistance = actDistance; return minDistance; } /** * Returns the DirectPositions which define the control points of this Curve * * @return */ public List<DirectPosition> asDirectPositions() { List<DirectPosition> rList = new ArrayList<DirectPosition>(); CurveSegment tSegment = null; // Iterate all CurveSegments (= LineStrings) for (int i = 0; i < this.curveSegments.size(); i++) { tSegment = this.curveSegments.get(i); // TODO: This version only handles the CurveSegment type LineString LineStringImpl tLineString = (LineStringImpl) tSegment; Iterator<LineSegment> tLineSegmentIter = tLineString .asLineSegments().iterator(); while (tLineSegmentIter.hasNext()) { LineSegment tLineSegment = tLineSegmentIter.next(); // Add new Coordinate, which is the start point of the actual // LineSegment rList.add( tLineSegment.getStartPoint().getDirectPosition() ); } } // Add new Coordinate, which is the end point of the last curveSegment rList.add( tSegment.getEndPoint() ); return rList; } /** * Constructs a new Curve by merging this Curve with another Curve * The two input curves will not be modified. * There will be no more references to positions or lists of the input curves, all values are copied. * * @param other * @return */ public CurveImpl merge(CurveImpl other) { // Test ok Merger merger = new Merger( crs );// new Merger(this.getFeatGeometryFactory()); return merger.merge(this, other); } /* (non-Javadoc) * @see java.lang.Object#toString() */ public String toString() { return GeometryToString.getString(this); } @Override public int hashCode() { final int PRIME = 31; int result = 1; result = PRIME * result + ((curveSegments == null) ? 0 : curveSegments.hashCode()); result = PRIME * result + ((envelope == null) ? 0 : envelope.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final CurveImpl other = (CurveImpl) obj; if (curveSegments == null) { if (other.curveSegments != null) return false; } else if (!curveSegments.equals(other.curveSegments)) return false; if (envelope == null) { if (other.envelope != null) return false; } else if (!envelope.equals(other.envelope)) return false; return true; } /* * (non-Javadoc) * * @see org.opengis.geometry.coordinate.root.Geometry#transform(org.opengis.referencing.crs.CoordinateReferenceSystem, * org.opengis.referencing.operation.MathTransform) */ public Geometry transform(CoordinateReferenceSystem newCRS, MathTransform transform) throws MismatchedDimensionException, TransformException { // loop through each point in this curve and transform it to the new CRS, then // use the new points to build a new curve and return that. PrimitiveFactory primitiveFactory = new PrimitiveFactoryImpl(newCRS, getPositionFactory()); GeometryFactory geometryFactory = new GeometryFactoryImpl(newCRS, getPositionFactory()); DirectPositionImpl dp1 = null; List<DirectPosition> currentpositions = asDirectPositions(); Iterator<DirectPosition> iter = currentpositions.iterator(); List<Position> newpositions = new ArrayList<Position>(); while (iter.hasNext()) { DirectPosition thispos = (DirectPosition) iter.next(); dp1 = new DirectPositionImpl(newCRS); dp1 = (DirectPositionImpl) transform.transform(thispos, dp1); newpositions.add(dp1); } // use the new positions list to build a new curve and return it LineString lineString = geometryFactory.createLineString(newpositions); List curveSegmentList = Collections.singletonList(lineString); CurveImpl newCurve = (CurveImpl) primitiveFactory.createCurve(curveSegmentList); return newCurve; } }