/*
* 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.coordinate;
import java.io.Serializable;
import org.geotools.geometry.iso.primitive.CurveBoundaryImpl;
import org.geotools.geometry.iso.primitive.CurveImpl;
import org.geotools.geometry.iso.primitive.PointImpl;
import org.geotools.geometry.iso.util.DoubleOperation;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.Envelope;
import org.opengis.geometry.coordinate.Position;
import org.opengis.geometry.primitive.CurveInterpolation;
import org.opengis.geometry.primitive.CurveSegment;
/**
*
* CurveSegment defines a homogeneous segment of a Curve. Each CurveSegment
* shall be in, at most, one Curve.
*
* @author Jackson Roehrig & Sanjay Jena
*
*
*
* @source $URL$
*/
public abstract class CurveSegmentImpl implements CurveSegment, Serializable {
/**
*
* The startParam indicates the parameter for the startPoint
*
* GenericCurve::startParam() : Distance
*
* GenericCurve:
*
* {parameterization(startParam()) = startPoint()};
*
* {parameterization(endParam()) = endPoint()};
*
* {length() = endParam() - startParam()}
*
* The start and end parameter of a Curve are always 0 and the arc length of
* the curve respectively. For CurveSegments within a Curve, the start and
* end parameters of the CurveSegment are equal to those of the Curve where
* this segment begins and ends in the Segmentation association, so that the
* startParam of any segment (except the first) is equal to the endParam of
* the previous segment. If a GenericCurve is used for other purposes, there
* shall be a restriction that the two parameters must differ by the arc
* length of the GenericCurve.
*/
protected double startParam;
/**
* The endParam indicates the parameter for the endPoint
*
* GenericCurve::endParam() : Distance
*
* GenericCurve:
*
* {parameterization(startParam()) = startPoint()};
*
* {parameterization(endParam()) = endPoint()};
*
* {length() = endParam() - startParam()}
*
* The start and end parameter of a Curve are always 0 and the arc length of
* the curve respectively. For CurveSegments within a Curve, the start and
* end parameters of the CurveSegment are equal to those of the Curve where
* this segment begins and ends in the Segmentation association, so that the
* startParam of any segment (except the first) is equal to the endParam of
* the previous segment. If a GenericCurve is used for other purposes, there
* shall be a restriction that the two parameters must differ by the arc
* length of the GenericCurve.
*
*/
protected double endParam;
/**
* The attribute "interpolation" specifies the curve interpolation mechanism
* used for this segment. This mechanism uses the control points and control
* parameters to determine the position of this CurveSegment.
*
* CurveSegment::interpolation : CurveInterpolation = "linear"
*
*/
protected CurveInterpolation interpolation = null;
/**
* Segmentation association from specification of Curve The association
* "segmentation" lists the components (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 this 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.
*/
private CurveImpl curve;
/**
* @param startPar
*/
public CurveSegmentImpl(double startPar) {
this.curve = null;
this.startParam = startPar;
this.endParam = -1;
}
/**
* @param other
*/
public CurveSegmentImpl(CurveSegmentImpl other) {
this.curve = other.curve;
this.startParam = other.startParam;
this.endParam = other.endParam;
}
/* (non-Javadoc)
* @see org.opengis.geometry.primitive.CurveSegment#getBoundary()
*/
public CurveBoundaryImpl getBoundary() {
return new CurveBoundaryImpl(this.getCurve().getCoordinateReferenceSystem(),
new PointImpl(this.getStartPoint()),
new PointImpl(this.getEndPoint()) );
}
public CurveInterpolation getInterpolation() {
return this.interpolation;
}
/**
* Sets the type of interpolation
*
* @param interpolation
*/
protected void setInterpolation(CurveInterpolation interpolation) {
this.interpolation = interpolation;
}
/**
* Sets the Curve the Curve Segment belongs to
*
* @param curve
*/
public void setCurve(CurveImpl curve) {
if (curve == null)
throw new IllegalArgumentException("Curve not passed"); //$NON-NLS-1$
this.curve = curve;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.primitive.CurveSegment#getCurve()
* @version Implementation OK
*/
public CurveImpl getCurve() {
if (this.curve == null)
throw new IllegalArgumentException("Parent Curve not set."); //$NON-NLS-1$
return this.curve;
}
/**
* The operation "samplePoint" returns an ordered array of point values
* (PointArray) that lie on the CurveSegment. In most cases, these will be
* related to control points used in the construction of the segment.
*
* CurveSegment::samplePoint() : PointArray
*
* NOTE The controlPoints of a curve segment are use to control its shape,
* and are not always on the curve segment itself. For example in a spline
* curve, the curve segment is given as a weighted vector sum of the
* controlPoints. Each weight function will have a maximum within the
* constructive parameter interval, which will roughly correspond to the
* point on the curve where it passes closest that the corresponding
* controlPoint. These points, the values of the curve at the maxima of the
* weight functions, will be the sample points for the curve segment.
*
* @return
*/
// public abstract PointArray samplePoint();
/**
* The operation "boundary" on CurveSegment operates with the same semantics
* as that on Curve except that the end points of a CurveSegment are not
* necessarily existing Points and thus the boundary may contain transient
* Points.
*
* CurveSegment::boundary() : CurveBoundary
*
* NOTE The above CurveBoundary will almost always be two distinct
* positions, but, like Curves, CurveSegments can be cycles in themselves.
* The most likely scenario is that all of the points used will be
* transients (constructed to support the return value), except for the
* startPoint and endPoint of the aggregated Curve. These two positions, in
* the case where the Curve is involved in a Complex, will be represented as
* Points in the same Complex.
*
* @return
*/
// public abstract CurveBoundary getBoundary();
/**
* The reverse of a CurveSegment simply reverses the orientation of the
* parameterizations of the segment. CurveSegment::reverse() : CurveSegment
*
* @return DirectPositionImpl
*/
// public abstract CurveSegment reverse();
public abstract DirectPosition getStartPoint();
public abstract DirectPosition getEndPoint();
/**
* @return start position
*/
public abstract Position getStartPosition();
/**
* @return end position
*/
public abstract Position getEndPosition();
/**
* GenericCurve: {parameterization(startParam()) = startPoint()};
* {parameterization(endParam()) = endPoint()}; {length() = endParam() -
* startParam()} returns the length => {length() = this.endParam() -
* this.startParam()} Returns the complete length of the CurveSegment
*
* @return double
* @version Implementation OK
*/
public double length() {
return DoubleOperation.subtract(this.getEndParam(), this.getStartParam());
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.GenericCurve#getStartParam()
* @version Implementation OK
*/
public double getStartParam() {
return this.startParam;
}
/**
* @param Value
*/
public void setStartParam(double Value) {
this.startParam = Value;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.GenericCurve#getEndParam()
* @version Implementation OK
*/
public double getEndParam() {
return this.endParam;
}
/**
* Set the parameter for the endPoint
*
* @param Value
*/
public void setEndParam(double Value) {
this.endParam = Value;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.GenericCurve#getStartConstructiveParam()
*/
public double getStartConstructiveParam() {
// OK
return DoubleOperation.div(this.getStartParam(), this.curve.length());
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.GenericCurve#getEndConstructiveParam() @
*/
public double getEndConstructiveParam() {
// OK
return DoubleOperation.div(this.getEndParam(), this.curve.length());
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.GenericCurve#length(org.opengis.geometry.coordinate.Position,
* org.opengis.geometry.coordinate.Position)
* @version Not verified whether this methods works correctly and
* appropriately
*/
public double length(Position point0, Position point1) {
// this method seems to be broken currently because getParamForPoint
// has problems
throw new UnsupportedOperationException("not implemented yet.");
// /* Default-Values */
// if (point0 == null && point1 == null)
// return this.length();
// if (point0 == null)
// point0 = new PositionImpl((DirectPosition) this.getStartPoint().clone());
// //point0 = this.getCurve().getFeatGeometryFactory()
// //.getGeometryFactoryImpl().createPosition(this.getStartPoint());
// if (point1 == null)
// point1 = new PositionImpl((DirectPosition) this.getEndPoint().clone());
// //point1 = this.getCurve().getFeatGeometryFactory()
// //.getGeometryFactoryImpl().createPosition(this.getEndPoint());
// /* Get all Params for closest points to startposition point1 */
// ParamForPoint obj0 = this.getParamForPoint(point0.getPosition());
// /* Get all Params for closest points to endposition point2 */
// ParamForPoint obj1 = this.getParamForPoint(point1.getPosition());
//
// /*
// * Compare the distances between each found startParam and endParam and
// * choose the smallest one
// */
// double minLength = Double.MAX_VALUE;
//
// minLength = Math.min(Math.abs(obj0.getDistance() - obj1.getDistance()),
// minLength);
// // for( Object param0 : obj0) {
// // for( Object param1 : obj1) {
// // minLength = Math.min(Math.abs((Double)param0 - (Double)param1),
// // minLength);
// // }
// // }
// return minLength;
}
/*
* (non-Javadoc)
*
* @see org.opengis.geometry.coordinate.GenericCurve#length(double,
* double)
*/
public double length(double par1, double par2) {
// OK
double parDif = Math.abs(DoubleOperation.subtract(par1, par2));
return DoubleOperation.mult(parDif, this.getCurve().length());
}
/**
* Added to Class requirements of CurveSegments Returns the envelope of the
* CurveSegment
*
* @return Envelope of the CurveSegment
*/
public abstract Envelope getEnvelope();
/**
* @param distance
*/
public abstract void split(double distance);
/**
* The method "isSimple" returns TRUE if this Object has no interior point
* of self-intersection or self-tangency. In mathematical formalisms, this
* means that every point in the interior of the object must have a metric
* neighborhood whose intersection with the object is isomorphic to an
* n-sphere, where n is the dimension of this Object. Since most coordinate
* geometries are represented, either directly or indirectly by functions
* from regions in Euclidean space of their topological dimension, the
* easiest test for simplicity to require that a function exist that is
* one-to-one and bicontinuous (continuous in both directions). Such a
* function is a topological isomorphism. This test does not work for
* "closed" objects (that is, objects for which the isCycle method returns
* TRUE). While Complexes contain only simple Objects, non-simple Objects
* are often used in "spaghetti" data sets.
*
* @return a <code>boolean</code> value
*/
// this method is not part of the specification
// public abstract boolean isSimple();
// this method is not part of the specification
}