import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Point2D.Double; import java.util.ArrayList; import org.gvsig.andami.PluginServices; import org.gvsig.fmap.geom.Geometry; import org.gvsig.fmap.geom.GeometryLocator; import org.gvsig.fmap.geom.GeometryManager; import org.gvsig.fmap.mapcontrol.PrimitivesDrawer; import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.ISnapperVectorialSeguimiento; import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.impl.AbstractSnapper; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.LineSegment; /** * Este a clase implementa un snapper a las aristas de la geometria que ademas * permite recuperar la lista de puntos que hay dentro de la geometría desde el * último pulsado y el anterior * @author Jose Ignacio Lamas Fonte * Leticia Riestra Ainsua * */ public class SeguimientoNearestPointSnapper extends AbstractSnapper implements ISnapperVectorialSeguimiento { private ArrayList listaPuntos; private static GeometryManager manager = GeometryLocator.getGeometryManager(); public SeguimientoNearestPointSnapper() { } /** * Devuelve el punto, dentro de las aristas la geometría 'geom', más proximo al punto 'point' * siempre que la cercanía sea menor o igual a la toleracia 'tolerance'. * Ademas actualiza la lista de puntos que hay entre el 'lastPointEntered' y el punto * resultado. */ public Point2D getSnapPoint(Point2D point, Geometry geom, double tolerance, Point2D lastPointEntered) { Point2D resul = null; Coordinate cUltimo = null; Coordinate cPoint = new Coordinate(point.getX(), point.getY()); if(lastPointEntered!=null){ cUltimo = new Coordinate(lastPointEntered.getX(), lastPointEntered.getY()); } // aqui almacenaremos los indices del ultimo punto encontrado y del punto mas pequeño que forme // parte del segmento en el que esta el nuevo punto encontrado int indiceUltimoPunto=-1; int indicePuntoEncontrado=-1; // encontramos el punto mas cercano al puntero del raton dentro de la geometria // y ademas miramos si el ultimo punto esta tambien dentro de algun segmento PathIterator theIterator = geom.getPathIterator(null, manager.getFlatness()); //polyLine.getPathIterator(null, flatness); double[] theData = new double[6]; double minDist = tolerance; Coordinate from = null, first = null; // limpio la lista de puntos // listaPuntos = new ArrayList(); // añado esto para ver si consigo tratar de forma coherente las multigeometrias ArrayList listaPuntosAux = new ArrayList(); boolean puntoEncontrado = false; boolean multiGeometriaTerminada = false; // cons esta variable controlaremos que se este haciendo snapin sobre una liena abierta // o un poligono cerrado, ya que sobre la linea no podemos dar la vuelta a los puntos // para buscar el camino mas corto boolean geometriaCerrada = false; while ((!theIterator.isDone())&&(!multiGeometriaTerminada)) { //while not done int theType = theIterator.currentSegment(theData); switch (theType) { case PathIterator.SEG_MOVETO: from = new Coordinate(theData[0], theData[1]); first = from; if(!puntoEncontrado){ geometriaCerrada=false; listaPuntosAux = new ArrayList(); indiceUltimoPunto=-1; indicePuntoEncontrado=-1; listaPuntosAux.add(new Point2D.Double(theData[0], theData[1])); // ahora comprobamos que no sean los puntos el primero if(cPoint.distance(from)1){ Point2D primerPunto = (Point2D) listaPuntosAux.get(0); Point2D ultimoPunto = (Point2D) listaPuntosAux.get(listaPuntosAux.size()-1); if(primerPunto.equals(ultimoPunto)){ if(indicePuntoEncontrado==listaPuntosAux.size()-1){ indicePuntoEncontrado = 0; } if(indiceUltimoPunto == listaPuntosAux.size()-1){ indiceUltimoPunto = 0; } listaPuntosAux.remove(listaPuntosAux.size()-1); geometriaCerrada=true; } } if(resul!=null){ if(indiceUltimoPunto>=0 && indicePuntoEncontrado>=0 && indicePuntoEncontrado!=indiceUltimoPunto && Math.abs(indicePuntoEncontrado-indiceUltimoPunto)>1){ listaPuntos = new ArrayList(); if(indiceUltimoPunto>indicePuntoEncontrado){ if(((indiceUltimoPunto-indicePuntoEncontrado)<= (((listaPuntosAux.size()-1)-indiceUltimoPunto)+indicePuntoEncontrado))||!geometriaCerrada){ for(int i=indiceUltimoPunto-1;i>=indicePuntoEncontrado;i--){ listaPuntos.add((Point2D)listaPuntosAux.get(i)); } }else{ for(int i = indiceUltimoPunto+1; i=0;i--){ listaPuntos.add((Point2D)listaPuntosAux.get(i)); } for(int i = listaPuntosAux.size()-1 ; i>=indicePuntoEncontrado;i--){ listaPuntos.add((Point2D)listaPuntosAux.get(i)); } } } } } return resul; } public String getToolTipText() { return PluginServices.getText(this, "arista_seguimiento"); //return "Arista seguimiento"; } /* (non-Javadoc) * @see com.iver.cit.gvsig.gui.cad.snapping.ISnapper#draw(java.awt.Graphics, java.awt.geom.Point2D) */ public void draw(PrimitivesDrawer g, Point2D pPixels) { g.setColor(getColor()); int half = getSizePixels() / 2; int x1 = (int) (pPixels.getX() - half); int x2 = (int) (pPixels.getX() + half); int y1 = (int) (pPixels.getY() - half); int y2 = (int) (pPixels.getY() + half); g.drawLine(x1, y1, x2, y1); // abajo g.drawLine(x1, y2, x2, y2); // arriba g.drawLine(x1, y1, x2, y2); // abajo - arriba g.drawLine(x1, y2, x2, y1); // arriba - abajo } /* (non-Javadoc) * @see com.iver.cit.gvsig.gui.cad.snapping.ISnapper#getPriority() */ public int getPriority() { return 2; } /** * Devuelve la lista de puntos que hay entre el ultimo y el anterior pulsado dentro de la * geometria */ public ArrayList getSnappedPoints(){ ArrayList retorno = listaPuntos; listaPuntos = null; return retorno; } }