/*$************************************************************************************************
**
** $Id$
**
** $Source: /cvs/ctree/LiteGO1/src/jar/com/polexis/lite/spatialschema/geometry/primitive/CurveImpl.java,v $
**
** Copyright (C) 2003 Open GIS Consortium, Inc. All Rights Reserved. http://www.opengis.org/Legal/
**
*************************************************************************************************/
package org.geotoolkit.geometry.isoonjts.spatialschema.geometry.primitive;
import java.util.*;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
import org.apache.sis.geometry.GeneralDirectPosition;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.JTSGeometry;
import org.geotoolkit.geometry.isoonjts.JTSUtils;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.AbstractJTSGeometry;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.NotifyingArrayList;
import org.geotoolkit.geometry.isoonjts.spatialschema.geometry.geometry.JTSLineString;
import org.geotoolkit.internal.jaxb.CurveArrayType;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.geometry.DirectPosition;
import org.opengis.geometry.complex.CompositeCurve;
import org.opengis.geometry.coordinate.GenericCurve;
import org.opengis.geometry.coordinate.LineString;
import org.opengis.geometry.coordinate.ParamForPoint;
import org.opengis.geometry.coordinate.PointArray;
import org.opengis.geometry.coordinate.Position;
import org.opengis.geometry.primitive.Curve;
import org.opengis.geometry.primitive.CurveSegment;
import org.opengis.geometry.primitive.OrientableCurve;
import org.opengis.geometry.primitive.CurveBoundary;
/**
* Simple implementation of the Curve interface that does not implement any
* of the (hard) math functions like intersection, etc. A curve consists of
* any number of CurveSegment objects (such as LineCharSequences) that must be
* connected end-to-end.
* @module
*/
@XmlType(name="CurveType", namespace="http://www.opengis.net/gml")
public class JTSCurve extends AbstractJTSGeometry implements Curve {
/**
* Component parts of the Curve. Each element must implement CurveSegment.
*/
private List<CurveSegment> curveSegments;
/**
* Creates a new {@code JTSCurve}.
*/
public JTSCurve() {
this(null);
}
/**
* Creates a new {@code JTSCurve}.
* @param crs
*/
public JTSCurve(final CoordinateReferenceSystem crs) {
super(crs);
curveSegments = new NotifyingArrayList<CurveSegment>(this);
}
/**
* {@inheritDoc }
*/
@Override
public CurveBoundary getBoundary() {
return (CurveBoundary) super.getBoundary();
}
/**
* {@inheritDoc }
*/
@Override
public final List<CurveSegment> getSegments() {
return curveSegments;
}
/**
* {@inheritDoc }
*/
@Override
public final DirectPosition getStartPoint() {
return (curveSegments.get(0)).getStartPoint();
}
/**
* {@inheritDoc }
*/
@Override
public final DirectPosition getEndPoint() {
return (curveSegments.get(curveSegments.size() - 1)).getEndPoint();
}
/**
* {@inheritDoc }
*/
@Override
public double [] getTangent(final double s) {
// PENDING(CSD): Implement me!
return new double[0];
}
/**
* {@inheritDoc }
*/
@Override
public final double getStartParam() {
return 0.0;
}
/**
* {@inheritDoc }
*/
@Override
public final double getEndParam() {
return this.length(0, getEndConstructiveParam());
}
/**
* {@inheritDoc }
*/
@Override
public final double getStartConstructiveParam() {
return 0.0;
}
/**
* {@inheritDoc }
*/
@Override
public final double getEndConstructiveParam() {
return curveSegments.size();
}
// We choose to parameterize the curve as a function from the interval
// [0, n] to R_n, where interval [i, i+1] corresponds to curve i, and
// the in between points are mapped linearly between the constructive params
// of curve i, i.e. C(i+d) = C_i((1-d)*scp + d*ecp), 0 <= d < 1, scp is the
// start constructive param of curve segment i, ecp is the end constructive
// param of curve segment i.
@Override
public final DirectPosition forConstructiveParam(final double cp) {
int n = curveSegments.size();
int i = (int) cp;
if (i < 0) {
i = 0;
}
else if (i > n) {
i = n;
}
if (i == n) {
return (curveSegments.get(n - 1)).getEndPoint();
}
else {
CurveSegment cs = curveSegments.get(i);
double d = cp - i; // 0 <= d < 1
return cs.forConstructiveParam(
(1-d) * cs.getStartConstructiveParam() +
d * cs.getEndConstructiveParam());
}
}
/**
* {@inheritDoc }
*/
@Override
public final DirectPosition forParam(final double s) {
return null;
}
/**
* Not implemented. Always just returns null.
*/
@Override
public ParamForPoint getParamForPoint(final DirectPosition p) {
return null;
}
/**
* Not implemented. Always returns zero.
*/
@Override
public double length(final DirectPosition point1, final DirectPosition point2) {
return 0.0;
}
/**
* Not implemented. Always returns 0.
* This wouldn't be hard to implement, though. You'd just sum over the
* CurveSegments that comprise this object.
*/
@Override
public double length(final double cparam1, final double cparam2) {
return 0.0;
}
/**
* Not fully implemented. Returns null, unless all CurveSegments are LineCharSequences,
* in which case it returns a concatenation of all the LineCharSequences.
* In future versions this could be implemented by delegating to the comprising segments.
*/
@Override
public LineString asLineString(final double maxSpacing, final double maxOffset) {
int count = curveSegments.size();
if (count == 1) {
Object segment1 = curveSegments.get(0);
if (segment1 instanceof LineString) {
return (LineString) segment1;
}
} else if (count > 0) {
boolean allLineString = true;
JTSLineString lsi = new JTSLineString();
LineString ls = null;
List retList = lsi.getControlPoints().positions();
Object lastPoint = null;
List segList = null;
for (int i = 0; i < count && allLineString; i++) {
Object segment = curveSegments.get(0);
if (segment instanceof LineString) {
segList = ((LineString) segment).getControlPoints().positions();
if (segList.get(0).equals(lastPoint)) {
retList.remove(retList.size() - 1);
}
retList.addAll(segList);
lastPoint = retList.get(retList.size() - 1);
} else {
allLineString = false;
}
}
if (allLineString) {
return lsi;
}
}
return null;
}
/**
* Returns null.
*/
@Override
public CompositeCurve getComposite() {
return null;
}
@Override
public int getOrientation() {
return +1;
}
/**
* Returns "this". Should return the containing primitive, if any.
*/
@Override
public Curve getPrimitive() {
return this;
}
/**
* Not implemented. Always returns an empty set.
*/
@Override
public Set getContainedPrimitives() {
return Collections.EMPTY_SET;
}
/**
* Not implemented (and probably never will be since traversal of this
* association would require a lot of extra work). Always returns an
* empty set.
*/
@Override
public Set getContainingPrimitives() {
return Collections.EMPTY_SET;
}
/**
* Not implemented (and probably never will be since traversal of this
* association would require a lot of extra work). Always returns an
* empty set.
*/
@Override
public Set getComplexes() {
return Collections.EMPTY_SET;
}
/**
* Not implemented. Returns null.
*/
@Override
public OrientableCurve[] getProxy() {
return null;
}
/**
* Not implemented. Returns null.
*/
@Override
public GenericCurve reverse() {
return null;
}
/**
* Not implemented. Returns null.
*/
@Override
public PointArray getSamplePoints() {
return null;
}
@XmlElement(name="segments", namespace="http://www.opengis.net/gml")
public CurveArrayType getCurveArray() {
return new CurveArrayType(curveSegments);
}
public void setCurveArray(final CurveArrayType array) {
curveSegments = new NotifyingArrayList<CurveSegment>(this);
for (CurveSegment c : array.getCurveSegments()) {
JTSLineString line = (JTSLineString) c;
JTSLineString newLine = new JTSLineString(getCoordinateReferenceSystem());
for (Position p : line.getPositions()) {
if (p instanceof GeneralDirectPosition) {
((GeneralDirectPosition) p).setCoordinateReferenceSystem(getCoordinateReferenceSystem());
newLine.getPositions().add(p);
}
}
curveSegments.add(newLine);
}
}
/**
* {@inheritDoc }
*/
@Override
protected com.vividsolutions.jts.geom.Geometry computeJTSPeer() {
// For each segment that comprises us, get the JTS peer.
int n = curveSegments.size();
ArrayList allCoords = new ArrayList();
for (int i=0; i<n; i++) {
JTSGeometry g = (JTSGeometry) curveSegments.get(i);
com.vividsolutions.jts.geom.LineString jts =
(com.vividsolutions.jts.geom.LineString) g.getJTSGeometry();
int m = jts.getNumPoints();
for (int j=0; j<m; j++) {
allCoords.add(jts.getCoordinateN(j));
}
if (i != (n-1))
allCoords.remove(allCoords.size()-1);
}
com.vividsolutions.jts.geom.Coordinate [] coords =
new com.vividsolutions.jts.geom.Coordinate[allCoords.size()];
allCoords.toArray(coords);
return JTSUtils.GEOMETRY_FACTORY.createLineString(coords);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(super.toString());
sb.append("segments:");
if(!curveSegments.isEmpty()){
sb.append("\n");
for(CurveSegment seg : curveSegments){
sb.append(seg.toString()).append("\n");
}
}
return sb.toString();
}
@Override
public boolean equals(final Object object) {
if (this == object)
return true;
if (object instanceof JTSCurve && super.equals(object)) {
JTSCurve that = (JTSCurve) object;
return Objects.equals(this.curveSegments, that.curveSegments);
}
return false;
}
@Override
public int hashCode() {
int hash = super.hashCode();
hash = 89 * hash + (this.curveSegments != null ? this.curveSegments.hashCode() : 0);
return hash;
}
}