1
|
import java.awt.geom.PathIterator;
|
2
|
import java.awt.geom.Point2D;
|
3
|
import java.awt.geom.Point2D.Double;
|
4
|
import java.util.ArrayList;
|
5
|
|
6
|
import org.gvsig.andami.PluginServices;
|
7
|
import org.gvsig.fmap.geom.Geometry;
|
8
|
import org.gvsig.fmap.geom.GeometryLocator;
|
9
|
import org.gvsig.fmap.geom.GeometryManager;
|
10
|
import org.gvsig.fmap.mapcontrol.PrimitivesDrawer;
|
11
|
import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.ISnapperVectorialSeguimiento;
|
12
|
import org.gvsig.fmap.mapcontrol.tools.snapping.snappers.impl.AbstractSnapper;
|
13
|
import com.vividsolutions.jts.geom.Coordinate;
|
14
|
import com.vividsolutions.jts.geom.LineSegment;
|
15
|
|
16
|
|
17
|
/**
|
18
|
* Este a clase implementa un snapper a las aristas de la geometria que ademas
|
19
|
* permite recuperar la lista de puntos que hay dentro de la geometr?a desde el
|
20
|
* ?ltimo pulsado y el anterior
|
21
|
* @author Jose Ignacio Lamas Fonte
|
22
|
* Leticia Riestra Ainsua
|
23
|
*
|
24
|
*/
|
25
|
public class SeguimientoNearestPointSnapper extends AbstractSnapper implements ISnapperVectorialSeguimiento {
|
26
|
|
27
|
private ArrayList<Point2D> listaPuntos;
|
28
|
|
29
|
private static GeometryManager manager = GeometryLocator.getGeometryManager();
|
30
|
|
31
|
public SeguimientoNearestPointSnapper() {
|
32
|
}
|
33
|
|
34
|
/**
|
35
|
* Devuelve el punto, dentro de las aristas la geometr?a 'geom', m?s proximo al punto 'point'
|
36
|
* siempre que la cercan?a sea menor o igual a la toleracia 'tolerance'.
|
37
|
* Ademas actualiza la lista de puntos que hay entre el 'lastPointEntered' y el punto
|
38
|
* resultado.
|
39
|
*/
|
40
|
public Point2D getSnapPoint(Point2D point, Geometry geom, double tolerance, Point2D lastPointEntered) {
|
41
|
|
42
|
Point2D resul = null;
|
43
|
|
44
|
Coordinate cUltimo = null;
|
45
|
Coordinate cPoint = new Coordinate(point.getX(), point.getY());
|
46
|
if(lastPointEntered!=null){
|
47
|
cUltimo = new Coordinate(lastPointEntered.getX(), lastPointEntered.getY());
|
48
|
}
|
49
|
|
50
|
// aqui almacenaremos los indices del ultimo punto encontrado y del punto mas peque?o que forme
|
51
|
// parte del segmento en el que esta el nuevo punto encontrado
|
52
|
int indiceUltimoPunto=-1;
|
53
|
int indicePuntoEncontrado=-1;
|
54
|
|
55
|
// encontramos el punto mas cercano al puntero del raton dentro de la geometria
|
56
|
// y ademas miramos si el ultimo punto esta tambien dentro de algun segmento
|
57
|
PathIterator theIterator = geom.getPathIterator(null, manager.getFlatness()); //polyLine.getPathIterator(null, flatness);
|
58
|
double[] theData = new double[6];
|
59
|
double minDist = tolerance;
|
60
|
Coordinate from = null, first = null;
|
61
|
|
62
|
// limpio la lista de puntos
|
63
|
// listaPuntos = new ArrayList();
|
64
|
|
65
|
|
66
|
// a?ado esto para ver si consigo tratar de forma coherente las multigeometrias
|
67
|
ArrayList<Double> listaPuntosAux = new ArrayList<Double>();
|
68
|
boolean puntoEncontrado = false;
|
69
|
boolean multiGeometriaTerminada = false;
|
70
|
|
71
|
// cons esta variable controlaremos que se este haciendo snapin sobre una liena abierta
|
72
|
// o un poligono cerrado, ya que sobre la linea no podemos dar la vuelta a los puntos
|
73
|
// para buscar el camino mas corto
|
74
|
boolean geometriaCerrada = false;
|
75
|
|
76
|
while ((!theIterator.isDone())&&(!multiGeometriaTerminada)) {
|
77
|
//while not done
|
78
|
int theType = theIterator.currentSegment(theData);
|
79
|
|
80
|
switch (theType) {
|
81
|
case PathIterator.SEG_MOVETO:
|
82
|
from = new Coordinate(theData[0], theData[1]);
|
83
|
first = from;
|
84
|
if(!puntoEncontrado){
|
85
|
geometriaCerrada=false;
|
86
|
listaPuntosAux = new ArrayList<Double>();
|
87
|
indiceUltimoPunto=-1;
|
88
|
indicePuntoEncontrado=-1;
|
89
|
listaPuntosAux.add(new Point2D.Double(theData[0], theData[1]));
|
90
|
// ahora comprobamos que no sean los puntos el primero
|
91
|
if(cPoint.distance(from)<minDist){
|
92
|
indicePuntoEncontrado = listaPuntosAux.size()-1;
|
93
|
resul = new Point2D.Double(theData[0], theData[1]);
|
94
|
puntoEncontrado = true;
|
95
|
}
|
96
|
if(cUltimo!=null){
|
97
|
if(cUltimo.equals(from)){
|
98
|
indiceUltimoPunto = listaPuntosAux.size()-1;
|
99
|
}
|
100
|
}
|
101
|
}else{
|
102
|
multiGeometriaTerminada = true;
|
103
|
}
|
104
|
break;
|
105
|
|
106
|
case PathIterator.SEG_LINETO:
|
107
|
|
108
|
// System.out.println("SEG_LINETO");
|
109
|
Coordinate to = new Coordinate(theData[0], theData[1]);
|
110
|
LineSegment line = new LineSegment(from, to);
|
111
|
Coordinate ultimoPuntoCercano = null;
|
112
|
|
113
|
|
114
|
// comprobamos que el ultimo punto este dentro de la linea de este tramo
|
115
|
if(cUltimo!=null){
|
116
|
if(!cUltimo.equals(to)){
|
117
|
// metemos primero esto por si a?ade un nuevo punto
|
118
|
ultimoPuntoCercano = line.closestPoint(cUltimo);
|
119
|
if((cUltimo.distance(ultimoPuntoCercano)<0.000001)&&(!cUltimo.equals(from))){
|
120
|
// a?adimos el punto extra a la lista de puntos
|
121
|
listaPuntosAux.add(new Point2D.Double(ultimoPuntoCercano.x,ultimoPuntoCercano.y));
|
122
|
indiceUltimoPunto = listaPuntosAux.size()-1;
|
123
|
}
|
124
|
}
|
125
|
}
|
126
|
// ahora debamos comprobar que el punto encontrado este dentro de la linea de este tramo
|
127
|
if((!(cPoint.distance(to)<minDist))&&(!(cPoint.distance(from)<minDist))){
|
128
|
ultimoPuntoCercano = line.closestPoint(cPoint);
|
129
|
if((cPoint.distance(ultimoPuntoCercano)<minDist)){
|
130
|
listaPuntosAux.add(new Point2D.Double(ultimoPuntoCercano.x,ultimoPuntoCercano.y));
|
131
|
indicePuntoEncontrado = listaPuntosAux.size()-1;
|
132
|
resul = new Point2D.Double(ultimoPuntoCercano.x,ultimoPuntoCercano.y);
|
133
|
puntoEncontrado = true;
|
134
|
}
|
135
|
}
|
136
|
|
137
|
// ahora pasamos a comprobar si los puntos estan en los vertices
|
138
|
if(cPoint.distance(to)<minDist){
|
139
|
// le ponemos el indice como un numero mas ya que a?adiremos luego el punto
|
140
|
indicePuntoEncontrado = listaPuntosAux.size();
|
141
|
resul = new Point2D.Double(theData[0], theData[1]);
|
142
|
puntoEncontrado = true;
|
143
|
}
|
144
|
if(cUltimo!=null&&cUltimo.equals(to)){
|
145
|
// le ponemos el indice como un numero mas ya que a?adiremos luego el punto
|
146
|
indiceUltimoPunto = listaPuntosAux.size();
|
147
|
}
|
148
|
listaPuntosAux.add(new Point2D.Double(theData[0], theData[1]));
|
149
|
|
150
|
from = to;
|
151
|
break;
|
152
|
case PathIterator.SEG_CLOSE:
|
153
|
line = new LineSegment(from, first);
|
154
|
geometriaCerrada=true;
|
155
|
// metemos primero esto por si a?ade un nuevo punto
|
156
|
if(cUltimo!=null){
|
157
|
// metemos primero esto por si a?ade un nuevo punto
|
158
|
ultimoPuntoCercano = line.closestPoint(cUltimo);
|
159
|
if((cUltimo.distance(ultimoPuntoCercano)<0.000001)&&(!cUltimo.equals(from))){
|
160
|
// a?adimos el punto extra a la lista de puntos
|
161
|
listaPuntosAux.add(new Point2D.Double(ultimoPuntoCercano.x,ultimoPuntoCercano.y));
|
162
|
indiceUltimoPunto = listaPuntosAux.size()-1;
|
163
|
}
|
164
|
}
|
165
|
// ahora debamos comprobar que el punto encontrado este dentro de la linea de este tramo
|
166
|
if(!(cPoint.distance(from)<minDist)){
|
167
|
ultimoPuntoCercano = line.closestPoint(cPoint);
|
168
|
if((cPoint.distance(ultimoPuntoCercano)<minDist)){
|
169
|
listaPuntosAux.add(new Point2D.Double(ultimoPuntoCercano.x,ultimoPuntoCercano.y));
|
170
|
indicePuntoEncontrado = listaPuntosAux.size()-1;
|
171
|
resul = new Point2D.Double(ultimoPuntoCercano.x,ultimoPuntoCercano.y);
|
172
|
puntoEncontrado = true;
|
173
|
}
|
174
|
}
|
175
|
from = first;
|
176
|
break;
|
177
|
|
178
|
} //end switch
|
179
|
|
180
|
theIterator.next();
|
181
|
}
|
182
|
|
183
|
// ahora comprobaremos si el primer y el ultimo punto son el mismo
|
184
|
// en cuyo caso borraremos el ultimo y actualizaremos los indices que correspondan
|
185
|
if(listaPuntosAux!=null && listaPuntosAux.size()>1){
|
186
|
Point2D primerPunto = (Point2D) listaPuntosAux.get(0);
|
187
|
Point2D ultimoPunto = (Point2D) listaPuntosAux.get(listaPuntosAux.size()-1);
|
188
|
if(primerPunto.equals(ultimoPunto)){
|
189
|
if(indicePuntoEncontrado==listaPuntosAux.size()-1){
|
190
|
indicePuntoEncontrado = 0;
|
191
|
}
|
192
|
if(indiceUltimoPunto == listaPuntosAux.size()-1){
|
193
|
indiceUltimoPunto = 0;
|
194
|
}
|
195
|
listaPuntosAux.remove(listaPuntosAux.size()-1);
|
196
|
geometriaCerrada=true;
|
197
|
}
|
198
|
}
|
199
|
|
200
|
|
201
|
if(resul!=null){
|
202
|
if(indiceUltimoPunto>=0 && indicePuntoEncontrado>=0 && indicePuntoEncontrado!=indiceUltimoPunto && Math.abs(indicePuntoEncontrado-indiceUltimoPunto)>1){
|
203
|
listaPuntos = new ArrayList<Point2D>();
|
204
|
if(indiceUltimoPunto>indicePuntoEncontrado){
|
205
|
if(((indiceUltimoPunto-indicePuntoEncontrado)<=
|
206
|
(((listaPuntosAux.size()-1)-indiceUltimoPunto)+indicePuntoEncontrado))||!geometriaCerrada){
|
207
|
for(int i=indiceUltimoPunto-1;i>=indicePuntoEncontrado;i--){
|
208
|
listaPuntos.add((Point2D)listaPuntosAux.get(i));
|
209
|
}
|
210
|
}else{
|
211
|
for(int i = indiceUltimoPunto+1; i<listaPuntosAux.size() ;i++){
|
212
|
listaPuntos.add((Point2D)listaPuntosAux.get(i));
|
213
|
}
|
214
|
for(int i = 0 ; i<=indicePuntoEncontrado;i++){
|
215
|
listaPuntos.add((Point2D)listaPuntosAux.get(i));
|
216
|
}
|
217
|
}
|
218
|
}else{
|
219
|
if(((indicePuntoEncontrado-indiceUltimoPunto)<=
|
220
|
(((listaPuntosAux.size()-1)-indicePuntoEncontrado)+indiceUltimoPunto))||!geometriaCerrada){
|
221
|
for(int i=indiceUltimoPunto+1;i<=indicePuntoEncontrado;i++){
|
222
|
listaPuntos.add((Point2D)listaPuntosAux.get(i));
|
223
|
}
|
224
|
}else{
|
225
|
for(int i = indiceUltimoPunto-1; i>=0;i--){
|
226
|
listaPuntos.add((Point2D)listaPuntosAux.get(i));
|
227
|
}
|
228
|
for(int i = listaPuntosAux.size()-1 ; i>=indicePuntoEncontrado;i--){
|
229
|
listaPuntos.add((Point2D)listaPuntosAux.get(i));
|
230
|
}
|
231
|
}
|
232
|
}
|
233
|
}
|
234
|
}
|
235
|
return resul;
|
236
|
}
|
237
|
|
238
|
public String getToolTipText() {
|
239
|
return PluginServices.getText(this, "arista_seguimiento");
|
240
|
//return "Arista seguimiento";
|
241
|
}
|
242
|
|
243
|
/* (non-Javadoc)
|
244
|
* @see com.iver.cit.gvsig.gui.cad.snapping.ISnapper#draw(java.awt.Graphics, java.awt.geom.Point2D)
|
245
|
*/
|
246
|
public void draw(PrimitivesDrawer g, Point2D pPixels) {
|
247
|
g.setColor(getColor());
|
248
|
|
249
|
int half = getSizePixels() / 2;
|
250
|
int x1 = (int) (pPixels.getX() - half);
|
251
|
int x2 = (int) (pPixels.getX() + half);
|
252
|
int y1 = (int) (pPixels.getY() - half);
|
253
|
int y2 = (int) (pPixels.getY() + half);
|
254
|
|
255
|
g.drawLine(x1, y1, x2, y1); // abajo
|
256
|
g.drawLine(x1, y2, x2, y2); // arriba
|
257
|
g.drawLine(x1, y1, x2, y2); // abajo - arriba
|
258
|
g.drawLine(x1, y2, x2, y1); // arriba - abajo
|
259
|
|
260
|
}
|
261
|
|
262
|
/* (non-Javadoc)
|
263
|
* @see com.iver.cit.gvsig.gui.cad.snapping.ISnapper#getPriority()
|
264
|
*/
|
265
|
public int getPriority()
|
266
|
{
|
267
|
return 2;
|
268
|
}
|
269
|
|
270
|
/**
|
271
|
* Devuelve la lista de puntos que hay entre el ultimo y el anterior pulsado dentro de la
|
272
|
* geometria
|
273
|
*/
|
274
|
public ArrayList<Point2D> getSnappedPoints(){
|
275
|
ArrayList<Point2D> retorno = listaPuntos;
|
276
|
listaPuntos = null;
|
277
|
|
278
|
return retorno;
|
279
|
}
|
280
|
|
281
|
}
|