/* Spatial Operations & Editing Tools for uDig * * Axios Engineering under a funding contract with: * Wien Government * * http://wien.gov.at * http://www.axios.es * * (C) 2010, Vienna City - Municipal Department of Automated Data Processing, * Information and Communications Technologies. * Vienna City agrees to license under Lesser General Public License (LGPL). * * 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 es.axios.lib.geometry.split; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.geom.MultiLineString; import com.vividsolutions.jts.geom.Point; /** * This strategy implement the method required to intersect the split line and the polygon to split * * @author Mauricio Pazos (www.axios.es) * @author Aritz Davila (www.axios.es) * @since 1.3.2 */ final class IntersectionStrategy { /** * * Maintains the intersection. It assure that the intersection state is consistent. * * @author Mauricio Pazos (www.axios.es) * @author Aritz Davila (www.axios.es) * @since 1.3.2 */ private static class IntersectMemento{ private Coordinate intersectionPoint = null; private int intersectionPosition = -1; public IntersectMemento() { } public void setIntersection(final int position, final Geometry point){ assert position >= 0 && point != null : "illegal intersection state"; //$NON-NLS-1$ this.intersectionPoint = point.getCoordinate(); this.intersectionPosition = position; } public Coordinate getIntersection() { return this.intersectionPoint; } public int getIntersectionPosition() { return this.intersectionPosition; } public boolean intersects(){ return this.intersectionPosition != -1; } } private IntersectMemento intersectState = null; /** * @return the intersection coordinate found in the last find intersection operation */ public Coordinate getIntersection() { return this.intersectState.getIntersection(); } /** * @return the intersection position found in the last find intersection operation */ public int getIntersectionPosition() { return this.intersectState.getIntersectionPosition(); } /** * @return true if the last operation has found an intersection */ public boolean foundIntersection(){ return this.intersectState.intersects(); } /** * <pre> * * Will find the first intersection between the split line and the boundary. * -Gets the intersection. * -if the result are more than 1 point, analyze it and return the closest one. * </pre> * * @param lineCoords Coordinates of the lineString. * @param geomFactory Geometry factory. * @param boundary Boundary to intersect with. * @return The coordinate where the split line intersects with the given boundary. */ public void findFirstIntersection( Coordinate[] lineCoords, Geometry boundary ) { assert boundary instanceof LinearRing || boundary instanceof LineString || boundary instanceof MultiLineString : "Boundary must be the linear ring."; //$NON-NLS-1$ this.intersectState = new IntersectMemento(); int numGeometries = 0; Geometry intersection = null; int i; for( i = 0; i < lineCoords.length - 1; i++ ) { intersection = SplitUtil.intersection(lineCoords, i, boundary, false); numGeometries = intersection.getNumGeometries(); if (numGeometries >= 1) { break;// found intersection } } // if the intersection is found, return; if (numGeometries == 1) { this.intersectState.setIntersection(i, intersection); } else if (numGeometries > 1) { Coordinate firstLineCoord = lineCoords[i]; Coordinate secondLineCoord = lineCoords[i + 1]; double minDistance = Double.MAX_VALUE; double distance; // find the closest one to coordinate[i] for( int j = 0; j < intersection.getNumGeometries(); j++ ) { Geometry pointToTest = intersection.getGeometryN(j); distance = SplitUtil.calculateDistanceFromFirst(pointToTest.getCoordinate(), firstLineCoord, secondLineCoord); if (Math.abs(distance) < minDistance) { this.intersectState.setIntersection(i, pointToTest); minDistance = Math.abs(distance); } } } } /** * <pre> * * Will find the last intersection between the split line and the boundary. * -Gets the intersection. * -if the result are more than 1 point, analyze it and return the closest one. * </pre> * * @param coordinates Line coordinates. * @param gf Geometry factory. * @param boundary A linear ring which will be the boundary of the polygon. * @return The coordinate where the split line intersects with the given boundary. */ public void findLastIntersection( final Coordinate[] coordinates, final Geometry boundary ) { assert boundary instanceof LinearRing || boundary instanceof LineString || boundary instanceof MultiLineString : "Boundary must be the linear ring."; //$NON-NLS-1$ this.intersectState = new IntersectMemento(); for( int i = coordinates.length - 1; 0 <= i; i-- ) { Geometry intersection = SplitUtil.intersection(coordinates, i, boundary, true); int numGeometries = intersection.getNumGeometries(); // if the intersection is found, return; if (numGeometries == 1) { this.intersectState.setIntersection(i, intersection); return; } else if (numGeometries > 1) { // find the closest one to coordinate[i] Coordinate firstLineCoord = coordinates[i]; Coordinate secondLineCoord = coordinates[i - 1]; double minDistance = Double.MAX_VALUE; double distance; for( int j = 0; j < intersection.getNumGeometries(); j++ ) { Geometry pointToTest = intersection.getGeometryN(j); distance = SplitUtil.calculateDistanceFromFirst(pointToTest.getCoordinate(), firstLineCoord, secondLineCoord); if (Math.abs(distance) < minDistance) { this.intersectState.setIntersection(i, pointToTest); minDistance = Math.abs(distance); } } return; } } } /** * Find last coordinate position that intersects with the boundary * * @param coordinates * @param boundary * @return -1 if not found or the position of last coordinate that intersects with the boundary */ public void findLastIntersectionPosition( final Coordinate[] coordinates, final Geometry boundary ) { assert boundary instanceof LinearRing || boundary instanceof LineString || boundary instanceof MultiLineString : "Boundary must be the linear ring."; //$NON-NLS-1$ this.intersectState = new IntersectMemento(); for( int i = coordinates.length - 1; 0 <= i; i-- ) { Geometry intersection = SplitUtil.intersection(coordinates, i, boundary, true); int numGeometries = intersection.getNumGeometries(); // if the intersection is found, return; if (numGeometries >= 1) { this.intersectState.setIntersection(i, intersection); return; } } } }