/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2011, 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.gml3.bindings; import javax.xml.namespace.QName; import org.geotools.gml3.GML; import org.geotools.xml.AbstractComplexBinding; import org.geotools.xml.ElementInstance; import org.geotools.xml.Node; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequenceFactory; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.geotools.gml3.ArcParameters; import org.geotools.gml3.Circle; /** * * @author Erik van de Pol. B3Partners BV. * * @source $URL: http://svn.osgeo.org/geotools/trunk/modules/extension/xsd/xsd-gml3/src/main/java/org/geotools/gml3/bindings/ArcTypeBinding.java $ */ public class ArcTypeBinding extends AbstractComplexBinding { GeometryFactory gFactory; CoordinateSequenceFactory csFactory; ArcParameters arcParameters; public ArcTypeBinding(GeometryFactory gFactory, CoordinateSequenceFactory csFactory, ArcParameters arcParameters) { this.gFactory = gFactory; this.csFactory = csFactory; this.arcParameters = arcParameters; } /** * @generated */ public QName getTarget() { return GML.ArcType; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * * @generated modifiable */ public Class getType() { return LineString.class; } @Override public int getExecutionMode() { return OVERRIDE; } /** * <!-- begin-user-doc --> * <!-- end-user-doc --> * * @generated modifiable */ @Override public Object parse(ElementInstance instance, Node node, Object value) throws Exception { LineString arcLineString = GML3ParsingUtils.lineString(node, gFactory, csFactory); Coordinate[] arcCoordinates = arcLineString.getCoordinates(); if (arcCoordinates.length != 3) { // maybe log this instead and return null throw new RuntimeException( "GML3 parser exception: The number of coordinates of an Arc should be 3. It currently is: " + arcCoordinates.length + "; " + arcLineString); } Coordinate c1 = arcCoordinates[0]; Coordinate c2 = arcCoordinates[1]; Coordinate c3 = arcCoordinates[2]; // determine whether we need to reverse our input. boolean mustReverse = laidOutClockwise(c1, c2, c3); if (mustReverse) { // swap coords 1 and 3 Coordinate cTemp = c1; c1 = c3; c3 = cTemp; } Circle circle = new Circle(c1, c2, c3); double tolerance = arcParameters.getLinearizationTolerance().getTolerance(circle); Coordinate[] resultCoordinates = circle.linearizeArc(c1, c2, c3, tolerance); if (mustReverse) { // reverse back List<Coordinate> reversingCoordinates = Arrays.asList(resultCoordinates); Collections.reverse(reversingCoordinates); resultCoordinates = (Coordinate[]) reversingCoordinates.toArray(new Coordinate[reversingCoordinates.size()]); } LineString resultLineString = gFactory.createLineString(resultCoordinates); return resultLineString; } /** * Returns whether the input coordinates are laid out clockwise on their corresponding circle. * Only works correctly if the Euclidean distance between c1 and c2 is equal to the Euclidean distance between c2 and c3. * @param c1 * @param c2 * @param c3 * @return true if input coordinates are laid out clockwise on their corresponding circle. false otherwise. */ protected boolean laidOutClockwise(Coordinate c1, Coordinate c2, Coordinate c3) { double x1 = c1.x; double y1 = c1.y; double x2 = c2.x; double y2 = c2.y; double x3 = c3.x; double y3 = c3.y; double midY = y1 - (y1 - y3) / 2; return (x1 < x3 && midY < y2) || (x1 > x3 && midY > y2) || (Double.compare(x1, x3) == 0 && ( (y1 < y3 && x1 > x2) || // x1 == x3 == midX in this case and the case below (y1 > y3 && x1 < x2) // Double.compare(y1, y3) == 0 degenerate case omitted )); } }