/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2015 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/
package org.geomajas.gwt.client.spatial.snapping;
import java.util.ArrayList;
import java.util.List;
import org.geomajas.configuration.SnappingRuleInfo;
import org.geomajas.configuration.SnappingRuleInfo.SnappingType;
import org.geomajas.geometry.Coordinate;
import org.geomajas.gwt.client.map.feature.Feature;
import org.geomajas.gwt.client.spatial.Mathlib;
import org.geomajas.gwt.client.spatial.geometry.Geometry;
import org.geomajas.gwt.client.spatial.geometry.MultiLineString;
import org.geomajas.gwt.client.spatial.geometry.MultiPoint;
import org.geomajas.gwt.client.spatial.geometry.MultiPolygon;
/**
* <p>
* Implementation of the <code>SnappingHandler</code> that gives priority to geometries that intersect the original
* coordinate that is to be snapped. If no such geometry is found, then it continues the normal way: trying to snap to
* any geometry.
* </p>
* <p>
* When the {@link Snapper} uses <code>mode = SnapMode.PRIORITY_TO_INTERSECTING_GEOMETRIES</code> then this
* implementation of the <code>SnappingHandler</code> is used.
* </p>
*
* @author Pieter De Graef
*/
public class IntersectPriorityMode extends SnappingMode {
/**
* The snapping distance found on intersecting geometries only.
*/
private double intersectDistance;
/**
* The snapped coordinate found when using intersecting geometries only.
*/
private Coordinate intersectSnappedCoordinate;
//-------------------------------------------------------------------------
// Constructor:
//-------------------------------------------------------------------------
protected IntersectPriorityMode(SnappingRuleInfo rule) {
super(rule);
}
public void execute(List<Feature> features) {
List<Geometry> geometries = new ArrayList<Geometry>();
for (Feature feature : features) {
Geometry geometry = feature.getGeometry();
// For multipolygons and multilinestrings, we calculate bounds intersection
// for each partial geometry. This way we can send parts of the complex
// geometries to the snapping list, and not always the entire geometry.(=faster)
List<Geometry> currentGeometries = new ArrayList<Geometry>();
if (geometry instanceof MultiLineString || geometry instanceof MultiPoint
|| geometry instanceof MultiPolygon) {
for (int n = 0; n < geometry.getNumGeometries(); n++) {
Geometry geometryN = geometry.getGeometryN(n);
if (geometryN.getBounds().intersects(bounds)) {
currentGeometries.add(geometryN);
}
}
} else {
if (geometry.getBounds().intersects(bounds)) {
currentGeometries.add(geometry);
}
}
if (currentGeometries.size() != 0) {
if (Mathlib.isWithin(geometry, coordinate)) {
SnappingAlgorithm algorithm;
if (rule.getType() == SnappingType.CLOSEST_ENDPOINT) {
algorithm = new ClosestPointAlgorithm(currentGeometries, rule.getDistance());
} else {
algorithm = new NearestAlgorithm(currentGeometries, rule.getDistance());
}
Coordinate snapPointIfFound = algorithm.getSnappingPoint(coordinate, intersectDistance);
if (snapPointIfFound != null) {
snappedCoordinate = snapPointIfFound;
intersectSnappedCoordinate = snappedCoordinate;
intersectDistance = algorithm.getMinimumDistance();
}
} else {
geometries.addAll(currentGeometries);
}
}
}
if (intersectSnappedCoordinate == null && !geometries.isEmpty()) {
SnappingAlgorithm algorithm;
if (rule.getType() == SnappingType.CLOSEST_ENDPOINT) {
algorithm = new ClosestPointAlgorithm(geometries, rule.getDistance());
} else {
algorithm = new NearestAlgorithm(geometries, rule.getDistance());
}
Coordinate snapPointIfFound = algorithm.getSnappingPoint(coordinate, intersectDistance);
if (snapPointIfFound != null) {
snappedCoordinate = snapPointIfFound;
distance = algorithm.getMinimumDistance();
}
}
}
public void setCoordinate(Coordinate coordinate) {
super.setCoordinate(coordinate);
intersectDistance = Double.MAX_VALUE;
intersectSnappedCoordinate = null;
}
}