Statistics
| Revision:

root / trunk / extensions / extGraph / src / org / gvsig / graph / core / Network.java @ 25339

History | View | Annotate | Download (30.6 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2004 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41
package org.gvsig.graph.core;
42

    
43
import java.awt.geom.PathIterator;
44
import java.awt.geom.Point2D;
45
import java.util.ArrayList;
46
import java.util.Hashtable;
47
import java.util.Iterator;
48
import java.util.Map;
49
import java.util.TreeMap;
50

    
51
import org.gvsig.exceptions.BaseException;
52

    
53
import com.iver.cit.gvsig.fmap.core.IGeometry;
54
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
55
import com.iver.cit.gvsig.fmap.drivers.DriverIOException;
56
import com.iver.cit.gvsig.fmap.layers.CancelationException;
57
import com.iver.cit.gvsig.fmap.layers.FBitSet;
58
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
59
import com.iver.cit.gvsig.fmap.layers.VectorialAdapter;
60
import com.vividsolutions.jts.geom.Coordinate;
61
import com.vividsolutions.jts.geom.LineSegment;
62
import com.vividsolutions.jts.geom.MultiLineString;
63

    
64
import edu.uci.ics.jung.algorithms.connectivity.BFSDistanceLabeler;
65

    
66
public class Network {
67
        protected FLyrVect lyrVect;
68

    
69
        protected IGraph graph;
70

    
71
        protected ArrayList flags = new ArrayList();
72

    
73
        protected int numOriginalEdges;
74

    
75
        protected int numOriginalNodes;
76

    
77
        private ArrayList modifiedCosts = new ArrayList();
78
        private ArrayList flagListeners = new ArrayList();
79
        private boolean dispatching = true;
80

    
81
        private Hashtable velocities = null;
82

    
83
        private ArrayList<GvTurn> turnCosts = new ArrayList();
84

    
85
        public void reconstruyeTramo(int idArc) {
86
                GvNode pN1, pN2;
87
                int i;
88
                
89
                // Si encontramos un enlace con idEdge >= numOriginalEdges, lo cambiamos.
90
                // Y CON ESE IDarc!!
91
                // Si hay varios, no pasa nada, volvemos a llamar a esta funci?n con IdTramo
92

    
93
                EdgePair edgePair = graph.getEdgesByIdArc(idArc);
94
                if (edgePair.getIdEdge() != -1)
95
                {
96
                        // Restauramos los enlaces de los nodos de ese tramo.
97
//                        pN1 = &Nodos[Arcos[IndiceArcos[idTramo].idArco].idNodo1];
98
//                        pN2 = &Nodos[Arcos[IndiceArcos[idTramo].idArco].idNodo2];
99
                        GvEdge edge = graph.getEdgeByID(edgePair.getIdEdge());
100
                        pN1 = graph.getNodeByID(edge.getIdNodeOrig());
101
                        pN2 = graph.getNodeByID(edge.getIdNodeEnd());
102

    
103
                        // Metemos idArco en los enlaces de Nodo1
104
//                        for (i=0; i< pN1.getOutputLinks().size(); i++)
105
//                        {
106
//                                GvEdge auxEdge = (GvEdge) pN1.getOutputLinks().get(i);
107
//                                if (auxEdge.getIdArc() == idArc)
108
//                                {
109
//                                        if (auxEdge.getIdEdge() >= numOriginalEdges) 
110
//                                        {
111
//                                                pN1.getOutputLinks().set(i, graph.getEdgeByID(edgePair.getIdEdge()));
112
//                                                break;
113
//                                        }
114
//                                }
115
//                        }
116
                        restoreConnectors(edge);
117
                        
118
                }
119

    
120
                if (edgePair.idInverseEdge != -1)
121
                {
122
//                        pN1 = &Nodos[Arcos[IndiceArcos[idTramo].idContraArco].idNodo1];
123
//                        pN2 = &Nodos[Arcos[IndiceArcos[idTramo].idContraArco].idNodo2];
124
                        GvEdge edge = graph.getEdgeByID(edgePair.getIdInverseEdge());
125
                        pN1 = graph.getNodeByID(edge.getIdNodeOrig());
126

    
127
//                        for (i=0; i< pN1.getOutputLinks().size(); i++)
128
//                        {
129
//                                if (edge.getIdArc() == idArc)
130
//                                {
131
//                                        GvEdge auxEdge = (GvEdge) pN1.getOutputLinks().get(i);
132
//                                        if (auxEdge.getIdEdge() >= numOriginalEdges) 
133
//                                        {
134
//                                                pN1.getOutputLinks().set(i, graph.getEdgeByID(edgePair.getIdInverseEdge()));
135
//                                                break;
136
//                                        }
137
//                                }                                                                
138
//                        }
139
                        restoreConnectors(edge);
140
                }
141

    
142
                int numEdges = graph.numEdges();
143
                int numNodes = graph.numVertices();
144
                for (int idEdge = numEdges-1; idEdge >= numOriginalEdges; idEdge--)
145
                {
146
                        graph.removeEdge(idEdge);
147
                }
148
                for (int idNode = numNodes-1; idNode >= numOriginalNodes; idNode--)
149
                {
150
                        graph.removeNode(idNode);
151
                }
152

    
153
        }
154

    
155
        private void restoreConnectors(GvEdge edge) {
156
                GvNode pN1 = graph.getNodeByID(edge.getIdNodeOrig());
157
                GvNode pN2 = graph.getNodeByID(edge.getIdNodeEnd());
158
                for (int iCon = 0; iCon < pN1.getConnectors().size(); iCon++) {
159
                        GvConnector c = pN1.getConnectors().get(iCon);
160
                        if (c.getEdgeOut() != null) {
161
                                if ((c.getEdgeOut().getIdEdge() >= numOriginalEdges) && (c.getEdgeOut().getIdArc() == edge.getIdArc())) {
162
                                        c.setEdgeOut(edge);
163
                                }
164
                        }
165
                }
166
                for (int iCon = 0; iCon < pN2.getConnectors().size(); iCon++) {
167
                        GvConnector c = pN2.getConnectors().get(iCon);
168
                        if (c.getEdgeIn() != null) {
169
                                if ((c.getEdgeIn().getIdEdge() >= numOriginalEdges) && (c.getEdgeOut().getIdArc() == edge.getIdArc())) {
170
                                        c.setEdgeIn(edge);
171
                                }
172
                        }
173
                }
174
        }
175

    
176
        /**
177
         * Closest ID to this point. -1 if out from tolerance.
178
         * @param x
179
         * @param y
180
         * @param tolerance
181
         * @param nearest. Point to receive the nearest point ON arc.
182
         * @return
183
         */
184
        public int findClosestArc(double x, double y, double tolerance, Point2D nearestPoint) {
185
                Point2D p = new Point2D.Double(x, y);
186
                FBitSet bitSet;
187
                try {
188
                        bitSet = lyrVect.queryByPoint(p, tolerance);
189
                        VectorialAdapter va = (VectorialAdapter) lyrVect.getSource();
190
                        va.start();
191
                        double minDist = tolerance;
192
                        int foundGeom = -1;
193
                        for (int i = bitSet.nextSetBit(0); i >= 0; i = bitSet
194
                                        .nextSetBit(i + 1)) {
195
                                IGeometry geom;
196
                                geom = va.getShape(i);
197
                                Point2D nearest = getNearestPoint(p, geom, tolerance);
198
                                if (nearest != null) {
199
                                        double dist = nearest.distance(p);
200
                                        if (dist < minDist) {
201
                                                minDist = dist;
202
                                                foundGeom = i;
203
                                                nearestPoint.setLocation(nearest);
204
                                        }
205
                                }
206
                        }
207
                        va.stop();
208
                        return foundGeom;
209
                } catch (BaseException e1) {
210
                        // TODO Auto-generated catch block
211
                        e1.printStackTrace();
212
                }
213
                return -1;
214

    
215
        }
216

    
217
        protected Point2D getNearestPoint(Point2D point, IGeometry geom,
218
                        double tolerance) {
219
                Point2D resul = null;
220
                Coordinate c = new Coordinate(point.getX(), point.getY());
221

    
222
                PathIterator theIterator = geom.getPathIterator(null,
223
                                FConverter.FLATNESS); // polyLine.getPathIterator(null,
224
                                                                                // flatness);
225
                double[] theData = new double[6];
226
                double minDist = tolerance;
227
                Coordinate from = null, first = null;
228
                while (!theIterator.isDone()) {
229
                        // while not done
230
                        int theType = theIterator.currentSegment(theData);
231

    
232
                        switch (theType) {
233
                        case PathIterator.SEG_MOVETO:
234
                                from = new Coordinate(theData[0], theData[1]);
235
                                first = from;
236
                                break;
237

    
238
                        case PathIterator.SEG_LINETO:
239

    
240
                                // System.out.println("SEG_LINETO");
241
                                Coordinate to = new Coordinate(theData[0], theData[1]);
242
                                LineSegment line = new LineSegment(from, to);
243
                                Coordinate closestPoint = line.closestPoint(c);
244
                                double dist = c.distance(closestPoint);
245
                                if ((dist < minDist)) {
246
                                        resul = new Point2D.Double(closestPoint.x, closestPoint.y);
247
                                        minDist = dist;
248
                                }
249

    
250
                                from = to;
251
                                break;
252
                        case PathIterator.SEG_CLOSE:
253
                                line = new LineSegment(from, first);
254
                                closestPoint = line.closestPoint(c);
255
                                dist = c.distance(closestPoint);
256
                                if ((dist < minDist)) {
257
                                        resul = new Point2D.Double(closestPoint.x, closestPoint.y);
258
                                        minDist = dist;
259
                                }
260

    
261
                                from = first;
262
                                break;
263

    
264
                        } // end switch
265

    
266
                        theIterator.next();
267
                }
268

    
269
                return resul;
270
        }
271

    
272
        /**
273
         * TODO: POR TERMINAR!!!
274
         * 
275
         * @param flag
276
         * @return
277
         */
278
        public int creaArcosVirtuales(GvFlag flag) {
279
                // Devuelve el idNodo del nodo virtual creado.
280
                /*
281
                 * 0.- Creamos el nuevo Nodo virtual. 1.- Recorremos los arcos nuevos
282
                 * mirando su idTramo. 2.- Si existe ese idtramo=> Ya hemos partido
283
                 * antes ese idTramo. Buscamos el arco virtual que contiene ese nodo y
284
                 * lo partimos. Ojo, recorrer hasta el final los tramos para asegurarnos
285
                 * de que es el trozo m?s peque?o. 3.- Si NO existe, utilizamos el
286
                 * IndiceArcos para coger los arcos que toca y partirlos.
287
                 * 
288
                 * 4.- OJO: Si el porcentaje es 0 ? 100, no partimos el arco, devolvemos
289
                 * el id del nodo que toca.
290
                 */
291
                // NUEVO: 20/7/2004:
292
                // Cuando trabajamos con sentidos, al partir un arco no podemos insertar
293
                // 2 nuevos sin mirar
294
                // si es o no de un ?nico sentido.) (Mirar idArco. Si es -1, no partimos
295
                // el arco).
296
                // FIN NUEVO
297
                int idNodo1, idNodo2;
298
                int idArco, elIdArco, elIdContraArco;
299
                boolean encontrado;
300
                GvNode newNode;
301

    
302
                // Sacamos los idNodos del tramo
303
                EdgePair edgePair = graph.getEdgesByIdArc(flag.getIdArc());
304
                if (edgePair.getIdEdge() != -1) {
305
                        // idNodo1 = Arcos[IndiceArcos[idTramo].idArco].idNodo1;
306
                        // idNodo2 = Arcos[IndiceArcos[idTramo].idArco].idNodo2;
307
                        idNodo1 = graph.getEdgeByID(edgePair.getIdEdge()).getIdNodeOrig();
308
                        idNodo2 = graph.getEdgeByID(edgePair.getIdEdge()).getIdNodeEnd();
309

    
310
                } else {
311
                        // idNodo2 = Arcos[IndiceArcos[idTramo].idContraArco].idNodo1;
312
                        // idNodo1 = Arcos[IndiceArcos[idTramo].idContraArco].idNodo2;
313
                        idNodo2 = graph.getEdgeByID(edgePair.getIdInverseEdge())
314
                                        .getIdNodeOrig();
315
                        idNodo1 = graph.getEdgeByID(edgePair.getIdInverseEdge())
316
                                        .getIdNodeEnd();
317

    
318
                }
319

    
320
                if (flag.getPct() == 0)
321
                        return idNodo1;
322
                if (flag.getPct() == 1)
323
                        return idNodo2;
324

    
325
                // Creamos el nodo de enmedio
326

    
327
                // if (numNodos == maxNodos) // La jodimos, T?rtola, hay que usar
328
                // reallocate
329
                // {
330
                // // NOTA: ESTO EN DEBUG HACE QUE FALLE AL USAR DESPUES EnlacesSTL. ES
331
                // POR NO S? QU? HISTORIA
332
                // // DEL HEAP. EN RELEASE NO FALLA. (TAMPOCO S? SI FASTIDIA ALGO).
333
                // Nodos = (CNode *) realloc(Nodos,(numNodos + MAX_RESERVA_NODOS) *
334
                // sizeof(CNode)); // Deber?amos chequear que devuelve algo correcto
335
                // maxNodos = numNodos + MAX_RESERVA_NODOS;
336
                // }
337

    
338
                newNode = new GvNode();
339
                // Nodo = &Nodos[numNodos];
340

    
341
                // pNuevoNodo->idNodo = numNodos;
342
                newNode.setIdNode(graph.numVertices());
343

    
344
                // OJO: Las coordenadas estas puede que no tengan que ver con la
345
                // realidad. Algo m?s correcto
346
                // ser?a tener en cuenta el shape de verdad, pero creo que no influye en
347
                // el resultado final.
348
                // pNuevoNodo->x = Nodos[idNodo1].x + (Nodos[idNodo2].x -
349
                // Nodos[idNodo1].x) * Porcentaje;
350
                // pNuevoNodo->y = Nodos[idNodo1].y + (Nodos[idNodo2].y -
351
                // Nodos[idNodo1].y) * Porcentaje;
352
                GvNode node1 = graph.getNodeByID(idNodo1);
353
                GvNode node2 = graph.getNodeByID(idNodo2);
354
                newNode.setX(node1.getX() + (node2.getX() - node1.getX())
355
                                * flag.getPct());
356
                newNode.setY(node1.getY() + (node2.getY() - node1.getY())
357
                                * flag.getPct());
358
                graph.addNode(newNode);
359
                Coordinate newC = new Coordinate(newNode.getX(), newNode.getY());
360

    
361
                encontrado = false;
362

    
363
                elIdArco = -1;
364
                elIdContraArco = -1;
365

    
366
                boolean bIdTramoYaPartido = false;
367

    
368
                // TODO: POR AQUI VOY
369
                for (idArco = numOriginalEdges; idArco < graph.numEdges(); idArco++) {
370
                        GvEdge addedEdge = graph.getEdgeByID(idArco);
371
                        if (addedEdge.getIdArc() == flag.getIdArc()) {
372
                                bIdTramoYaPartido = true;
373

    
374
                                idNodo1 = addedEdge.getIdNodeOrig();
375
                                idNodo2 = addedEdge.getIdNodeEnd();
376

    
377
                                // Comprobamos si est? enmedio
378
                                GvNode n1 = graph.getNodeByID(idNodo1);
379
                                GvNode n2 = graph.getNodeByID(idNodo2);
380
                                Coordinate c1 = new Coordinate(n1.getX(), n1.getY());
381
                                Coordinate c2 = new Coordinate(n2.getX(), n2.getY());
382
                                LineSegment line = new LineSegment(c1, c2);
383
                                double t = line.projectionFactor(newC);
384

    
385
                                // Si la proyecci?n es positiva y menor que la magnitud d, est?
386
                                // en medio
387
                                if ((t >= 0) && (t <= 1)) {
388
                                        encontrado = true;
389
                                        if (t == 0)
390
                                                return idNodo1; // No partimos
391
                                        if (t == 1)
392
                                                return idNodo2; // Tampoco partimos
393

    
394
                                        if (addedEdge.getDirec() == 1)
395
                                                elIdArco = idArco;
396
                                        else
397
                                                elIdContraArco = idArco;
398

    
399
                                } // if est? enmedio
400
                        } // if idTramo encontrado
401
                } // for idArco
402
                if (bIdTramoYaPartido && (!encontrado))
403
                        throw new RuntimeException(
404
                                        "Algo va mal con lo del producto escalar");
405

    
406
                if (encontrado) {
407
                        // sprintf(Mensaje,"Voy a partir el idTramo= %ld (idArco
408
                        // %ld)",idTramo,elIdArco);
409
                        // MessageBox(NULL,Mensaje,"",MB_OK);
410
                        if (elIdArco != -1)
411
                                PartirArco(elIdArco, newNode.getIdNode());
412

    
413
                        if (elIdContraArco != -1)
414
                                PartirArco(elIdContraArco, newNode.getIdNode());
415
                } else {
416
                        // Creamos 2 Arcos por cada arco que ten?amos antes.
417
                        if (edgePair.getIdEdge() != -1)
418
                                PartirArco(edgePair.getIdEdge(), newNode.getIdNode());
419

    
420
                        if (edgePair.getIdInverseEdge() != -1)
421
                                PartirArco(edgePair.getIdInverseEdge(), newNode.getIdNode());
422

    
423
                } // else encontrado
424

    
425
                return newNode.getIdNode();
426

    
427
        }
428

    
429
        /**
430
         * Cogemos el nodo m?s cercano y ponemos el pct a ese flag.
431
         * 
432
         * @param flag
433
         * @return
434
         */
435
        public int getClosestIdNode(GvFlag flag) {
436
                EdgePair pair = graph.getEdgesByIdArc(flag.getIdArc());
437
                if (pair.getIdEdge() != -1) {
438
                        GvEdge edge = graph.getEdgeByID(pair.getIdEdge());
439
                        GvNode from = graph.getNodeByID(edge.getIdNodeOrig());
440
                        GvNode to = graph.getNodeByID(edge.getIdNodeEnd());
441

    
442
                        double dist1 = flag.getOriginalPoint().distance(from.getX(),
443
                                        from.getY());
444
                        double dist2 = flag.getOriginalPoint().distance(to.getX(),
445
                                        to.getY());
446
                        if (dist1 < dist2) {
447
                                flag.setPct(0);
448
                                return from.getIdNode();
449
                        }
450
                        else
451
                        {
452
                                flag.setPct(1.0);
453
                                return to.getIdNode();
454
                        }
455
                } else {
456
                        GvEdge edge = graph.getEdgeByID(pair.getIdInverseEdge());
457
                        GvNode from = graph.getNodeByID(edge.getIdNodeOrig());
458
                        GvNode to = graph.getNodeByID(edge.getIdNodeEnd());
459

    
460
                        double dist1 = flag.getOriginalPoint().distance(from.getX(),
461
                                        from.getY());
462
                        double dist2 = flag.getOriginalPoint().distance(to.getX(),
463
                                        to.getY());
464
                        if (dist1 < dist2)
465
                        {
466
                                flag.setPct(0);
467
                                return from.getIdNode();
468
                        }
469
                        else
470
                        {
471
                                flag.setPct(1.0);
472
                                return to.getIdNode();
473
                        }
474
                        // if (flag.getPct() < 0.5)
475
                        // return to.getIdNode();
476
                        // else
477
                        // return from.getIdNode();
478
                }
479
        }
480

    
481
        /**
482
         * @param idArc
483
         * @param x
484
         * @param y
485
         * @return entre 0.0 y 1.0
486
         * @throws DriverIOException
487
         */
488
        private double percentAlong(int idArc, double x, double y)
489
                        throws BaseException {
490
                // Le pasamos el idTramo, la coordenada X de donde hemos pulsado y la
491
                // coordenada Y
492
                // Primero calculamos la longitud total del shape.
493
                // Luego calculamos el punto m?s cercano y su distancia para cada
494
                // segmento del shape.
495
                // Nos quedamos con el que est? m?s cerca y luego recorremos hasta ?l
496
                // acumulando distancia.
497
                // Finalmente, dividimos esa distancia por la longitud total.
498
                lyrVect.getSource().start();
499
                IGeometry geom = lyrVect.getSource().getShape(idArc);
500
                MultiLineString jtsGeom = (MultiLineString) geom.toJTSGeometry();
501

    
502
                Coordinate[] coords = jtsGeom.getCoordinates();
503

    
504
                Coordinate userCoord = new Coordinate(x, y);
505

    
506
                double longReal = 0;
507
                // Le pegamos una primera pasada para saber su longitud real.
508
                // OJO, NO TRABAJAMOS CON SHAPES MULTIPARTE, NO TIENE SENTIDO CON LAS
509
                // REDES (CREO)
510
                // POR ESO SUPONEMOS UNA ?NICA PARTE (L?NEA CONT?NUA)
511
                // A la vez calculamos el punto m?s cercano y su distancia para cada
512
                // segmento.
513
                double minDist = Double.MAX_VALUE;
514
                double distTo = 0;
515
                double dist = 0;
516
                Coordinate cOrig = null;
517
                Coordinate closestPoint = null;
518
                for (int j = 0; j < coords.length - 1; j++) {
519
                        Coordinate c1 = coords[j];
520
                        Coordinate c2 = coords[j + 1];
521
                        LineSegment line = new LineSegment(c1, c2);
522

    
523
                        Coordinate auxPoint = line.closestPoint(userCoord);
524
                        dist = userCoord.distance(auxPoint);
525
                        if ((dist < minDist)) {
526
                                minDist = dist;
527
                                cOrig = c1;
528
                                closestPoint = auxPoint;
529
                                distTo = longReal;
530
                        }
531
                        longReal += line.getLength();
532
                }
533
                lyrVect.getSource().stop();
534
                dist = cOrig.distance(closestPoint);
535
                double longBuscada = distTo + dist;
536

    
537
                double pct;
538
                if (longReal > 0)
539
                        pct = longBuscada / longReal;
540
                else
541
                        pct = 0.0;
542

    
543
                return pct;
544
        }
545

    
546
        /**
547
         * Adds a flag on a network. flagDirection set if the flag must be on left
548
         * or right edge.
549
         * 
550
         * @param x
551
         * @param y
552
         * @param flagDirection
553
         * @param tol
554
         *            tolerance in map units
555
         * @return null if there is no place to add flag. You can increase the
556
         *         tolerance, then.
557
         * @throws GraphException
558
         */
559
        public GvFlag addFlag(double x, double y, int flagDirection, double tol)
560
                        throws GraphException {
561
                try {
562
                        Point2D nearestPoint = new Point2D.Double();
563
                        int idArc = findClosestArc(x, y, tol, nearestPoint);
564
                        if (idArc == -1)
565
                                return null;
566
                        GvFlag flag = new GvFlag(x, y);
567
                        flag.setIdArc(idArc);
568

    
569
                        flag.setPct(percentAlong(idArc, x, y));
570
                        flag.setDirec(flagDirection);
571
                        flag.setIdFlag(flags.size());
572
                        callFlagsChanged(IFlagListener.FLAG_ADDED);
573
                        return flag;
574
                } catch (BaseException e) {
575
                        e.printStackTrace();
576
                        throw new GraphException(e);
577
                }
578

    
579
        }
580

    
581
        /**
582
         * Adds 2 flags on a network. (On both sides of an arc)
583
         * 
584
         * @param x
585
         * @param y
586
         * @param tol
587
         *            tolerance in map units
588
         * @return null if there is no place to add flag. You can increase the
589
         *         tolerance, then.
590
         * @throws GraphException 
591
         */
592
        public GvFlag addFlag(double x, double y, double tol) throws GraphException {
593
                try {
594
                        Point2D nearestPoint = new Point2D.Double();
595
                        int idArc = findClosestArc(x, y, tol, nearestPoint);
596
                        if (idArc == -1)
597
                                return null;
598

    
599
                        GvFlag flag = new GvFlag(x, y);
600
                        flag.setIdArc(idArc);
601
                        EdgePair edgePair = graph.getEdgesByIdArc(idArc);
602
                        flag.setDirec(GvFlag.BOTH_DIRECTIONS);
603

    
604
                        flag.setPct(percentAlong(idArc, x, y));
605
                        flag.setIdFlag(flags.size());
606
                        flags.add(flag);
607
                        callFlagsChanged(IFlagListener.FLAG_ADDED);
608
                        return flag;
609
                } catch (BaseException e) {
610
                        e.printStackTrace();
611
                        throw new GraphException(e);
612
                }
613

    
614
        }
615

    
616
        /**
617
         * Create a flag in both directions, but NOT add it to the Network.
618
         * We use it on onetomany solver
619
         * @param x
620
         * @param y
621
         * @param tol
622
         * @return
623
         * @throws GraphException
624
         */
625
        public GvFlag createFlag(double x, double y, double tol) throws GraphException {
626
                try {
627
                        Point2D nearestPoint = new Point2D.Double();
628
                        int idArc = findClosestArc(x, y, tol, nearestPoint);
629
                        if (idArc == -1)
630
                                return null;
631

    
632
                        GvFlag flag = new GvFlag(x, y);
633
                        flag.setIdArc(idArc);
634
//                        EdgePair edgePair = graph.getEdgesByIdArc(idArc);
635
                        flag.setDirec(GvFlag.BOTH_DIRECTIONS);
636

    
637
                        flag.setPct(percentAlong(idArc, x, y));
638
                        flag.setIdFlag(flags.size());
639
                        return flag;
640
                } catch (BaseException e) {
641
                        e.printStackTrace();
642
                        throw new GraphException(e);
643
                }
644

    
645
        }
646

    
647
        public GvFlag addFlagToNode(double x, double y, double tol) throws GraphException {
648
                Point2D nearestPoint = new Point2D.Double();
649
                int idArc = findClosestArc(x, y, tol, nearestPoint);
650
                if (idArc == -1)
651
                        return null;
652

    
653
                GvFlag flag = new GvFlag(x, y);
654
                flag.setIdArc(idArc);
655
                flag.setDirec(GvFlag.BOTH_DIRECTIONS);
656
                int idNode = getClosestIdNode(flag);
657
                
658
                GvNode node = graph.getNodeByID(idNode);
659
                flag.setOriginalPoint(node.getX(), node.getY());
660
                flag.setIdFlag(flags.size());
661
                flags.add(flag);
662
                callFlagsChanged(IFlagListener.FLAG_ADDED);
663
                return flag;
664

    
665
        }
666

    
667

    
668
        public void addFlag(GvFlag flag) {
669
                flags.add(flag);
670
                callFlagsChanged(IFlagListener.FLAG_ADDED);
671
        }
672

    
673
        public GvFlag[] getFlags() {
674
                ArrayList aux = new ArrayList();
675
                for (int i=0; i < getOriginaFlags().size(); i++)
676
                {
677
                        GvFlag flag = (GvFlag) getOriginaFlags().get(i);
678
                        if (flag.isEnabled()) aux.add(flag);
679
                }
680

    
681
                return (GvFlag[]) aux.toArray(new GvFlag[0]);
682
        }
683
        
684
        public int getFlagsCount(){
685
                return this.getOriginaFlags().size();
686
        }
687
        
688
        /**
689
         * Suitable to change directly the flags collection
690
         * @return
691
         */
692
        public ArrayList getOriginaFlags() {
693
                return flags;
694
        }
695

    
696

    
697
        public void setFlags(ArrayList flags) {
698
                this.flags = flags;
699
        }
700

    
701
        public IGraph getGraph() {
702
                return graph;
703
        }
704

    
705
        public void setGraph(IGraph graph) {
706
                this.graph = graph;
707
                numOriginalEdges = graph.numEdges();
708
                numOriginalNodes = graph.numVertices();
709
        }
710

    
711
        public FLyrVect getLayer() {
712
                return lyrVect;
713
        }
714

    
715
        public void setLayer(FLyrVect lyr) {
716
                this.lyrVect = lyr;
717
        }
718

    
719
        public void removeFlags() {
720
                flags = new ArrayList();
721
                callFlagsChanged(IFlagListener.FLAG_REMOVED);
722
        }
723
        
724
        public void removeFlag(GvFlag flag){
725
                flags.remove(flag);
726
                callFlagsChanged(IFlagListener.FLAG_REMOVED);
727
        }
728

    
729
        void PartirArco(int idEdge, int idNode) {
730
                // Se supone que el nuevo Nodo YA est? creado. Aqui dentro se coge el
731
                // arco viejo y se le pega un tajo.
732
                // (Se modifican los enlaces de los nodos de ese arco y se crean los
733
                // arcos nuevos, fijando sus costes).
734
                // Para sacar el porcentaje nos aprovechamos de que el nuevo nodo est?
735
                // puesto en base a ese porcentaje
736
                // en distancia de los extremos.
737
                GvEdge oldEdge;
738
                GvNode pN1, pN2;
739
                double pct;
740

    
741
                oldEdge = graph.getEdgeByID(idEdge);
742

    
743
                // OJO, controlando los ceros por si acaso la recta es horizontal o
744
                // vertical (Y si mide cero???)
745

    
746
                // pN1 = &Nodos[Arcos[idArco].idNodo1];
747
                // pN2 = &Nodos[Arcos[idArco].idNodo2];
748
                pN1 = graph.getNodeByID(graph.getEdgeByID(idEdge).getIdNodeOrig());
749
                pN2 = graph.getNodeByID(graph.getEdgeByID(idEdge).getIdNodeEnd());
750
                GvNode newNode = graph.getNodeByID(idNode);
751

    
752
                if (newNode.getX() != pN1.getX())
753
                        pct = Math.abs((newNode.getX() - pN1.getX())
754
                                        / (pN2.getX() - pN1.getX()));
755
                else
756
                        pct = Math.abs((newNode.getY() - pN1.getY())
757
                                        / (pN2.getY() - pN1.getY()));
758

    
759
                GvEdge first = new GvEdge();
760
                first.setIdEdge(graph.numEdges());
761
                first.setIdArc(oldEdge.getIdArc());
762
                first.setDistance(oldEdge.getDistance() * pct);
763
                first.setWeight(oldEdge.getWeight() * pct);
764

    
765
                first.setDirec(oldEdge.getDirec());
766
                first.setIdNodeOrig(oldEdge.getIdNodeOrig());
767
                first.setType(oldEdge.getType());
768
                first.setIdNodeEnd(idNode);
769
                graph.addEdge(first);
770

    
771
                GvEdge second = new GvEdge();
772
                second.setIdEdge(graph.numEdges());
773
                second.setDistance(oldEdge.getDistance() * (1.0 - pct));
774
                second.setWeight(oldEdge.getWeight() * (1.0 - pct));
775
                second.setIdArc(oldEdge.getIdArc());
776
                second.setDirec(oldEdge.getDirec());
777
                second.setType(oldEdge.getType());
778
                second.setIdNodeOrig(idNode);
779
                second.setIdNodeEnd(oldEdge.getIdNodeEnd());
780
                graph.addEdge(second);
781

    
782
                // ////////////////////////////////////////////////////
783
                // Ahora retocamos los enlaces que salen de cada nodo
784
                // ////////////////////////////////////////////////////
785
                int i;
786
                // boolean encontrado = false;
787
//                for (i = 0; i < pN1.getOutputLinks().size(); i++) {
788
//                        GvEdge aux = (GvEdge) pN1.getOutputLinks().get(i);
789
//                        if (aux.getIdEdge() == idEdge) {
790
//                                pN1.getOutputLinks().set(i, first);
791
//                                // encontrado = true;
792
//                                break;
793
//                        }
794
//                } // for
795
                for (i = 0; i < pN1.getConnectors().size(); i++) {
796
                        GvConnector c = pN1.getConnectors().get(i);
797
                        if ((c.getEdgeOut() != null) && (c.getEdgeOut().getIdEdge()== idEdge)) {
798
                                c.setEdgeOut(first);
799
                                // encontrado = true;
800
                                break;
801
                        }
802
                } // for
803

    
804
                // Conector de entrada 
805
                GvConnector newCon = new GvConnector();
806
                newCon.setEdgeIn(first);
807
                newNode.getConnectors().add(newCon);
808

    
809
                // Conector de salida 
810
                GvConnector conOut = new GvConnector();
811
                newCon.setEdgeOut(second);
812
                newNode.getConnectors().add(conOut);
813
                
814
                // Y hacemos que el conector de entrada del idNodo2 tenga el arco nuevo
815
                // log("Y hacemos que el conector de entrada del idNodo2 tenga el arco nuevo");
816
                for (i = 0; i < pN2.getConnectors().size(); i++) {
817
                        GvConnector c = pN2.getConnectors().get(i);
818
                        if ((c.getEdgeIn() != null) && (c.getEdgeIn().getIdEdge()== idEdge)) {
819
                                c.setEdgeIn(second);
820
                                // encontrado = true;
821
                                break;
822
                        }
823
                } // for
824
        }
825

    
826
        public ArrayList getModifiedCosts() {
827
                return modifiedCosts;
828
                
829
        }
830
        
831
        private int[] BuscaNodosDeTramo(EdgePair pair) {
832
                int[] resul = new int[2];
833
                if ((pair.idEdge == -1) && (pair.idInverseEdge == -1))
834
                {
835
                        return null; // Error: No existen esos arcos.
836
                }
837

    
838
                if (pair.idEdge != -1)
839
                {
840
                        resul[0] = graph.getEdgeByID(pair.idEdge).getIdNodeOrig();
841
                        resul[1]= graph.getEdgeByID(pair.idEdge).getIdNodeEnd();
842
                }
843
                else
844
                {
845
                        resul[0] = graph.getEdgeByID(pair.idInverseEdge).getIdNodeOrig();
846
                        resul[1]= graph.getEdgeByID(pair.idInverseEdge).getIdNodeEnd();
847
                }
848
                return resul;
849

    
850
        }
851

    
852
        public int addTurnCost(int idArcOrigin, int idArcDestination, double newCost) {
853
                GvTurn turnCost = new GvTurn(idArcOrigin, idArcDestination, newCost);
854
                turnCosts.add(turnCost); //useful to remove them one by one without iterating the whole graph.
855
                EdgePair edgePairFrom = getGraph().getEdgesByIdArc(idArcOrigin);
856
                EdgePair edgePairTo = getGraph().getEdgesByIdArc(idArcDestination);
857
                
858
                // We found the node that connects these arcs, 
859
                // and add the new turnCost to its list of turnCosts.
860
                GvNode searchedNode;
861
                int idNa1, idNa2, idNb1, idNb2, idNodoBuscado;
862
                int[] A, B;
863

    
864
                A = BuscaNodosDeTramo(edgePairFrom);
865
                if (A == null) return -1; // No existen arcos para ese idTramo
866
                
867

    
868
                B = BuscaNodosDeTramo(edgePairTo);
869
                if (B == null) return -1; // No existen arcos para ese idTramo
870

    
871
                idNa1 = A[0]; idNa2 = A[1];
872
                idNb1 = B[0]; idNb2 = B[1];
873

    
874
                // Buscamos el nodo que est? entre fromIdTramo y toIdTramo
875
                // y el arco. Al arco hay que cambiarle el destino
876
                if (idNa1 == idNb1)
877
                        idNodoBuscado = idNa1;
878
                else
879
                        if (idNa1 == idNb2)
880
                                idNodoBuscado = idNa1;
881
                        else
882
                                if (idNa2 == idNb1)
883
                                        idNodoBuscado = idNa2;
884
                                else
885
                                        if (idNa2 == idNb2)
886
                                                idNodoBuscado = idNa2;
887
                                        else // ERROR
888
                                                return -2; // esos tramos no conectan.
889

    
890
                // Podemos funcionar con idTramo en lugar de idArco porque cada CLink lleva dentro
891
                // el idTramo que lo origin?, y en el algoritmo podemos mirarlo.
892

    
893
                searchedNode = graph.getNodeByID(idNodoBuscado);
894
                searchedNode.addTurnCost(turnCost);                        
895

    
896
                
897
                return 0; // everything is fine
898
        }
899
        /**
900
         * Create, add and apply a new modified cost to the graph. 
901
         * @param idArc where the cost will be applied.
902
         * @param newCost. -1 if you want tu put a BARRIER.
903
         * @param direction. 1-> edge of digitalized direction. 2-> inverse edge. 3-> Both directions
904
         */
905
        public GvModifiedCost addModifiedCost(int idArc, double newCost, int direction) {
906
                GvModifiedCost modifiedCost = new GvModifiedCost(idArc, newCost, direction);
907
                EdgePair edgePair = getGraph().getEdgesByIdArc(idArc);
908
                modifiedCost.setIdEdge(edgePair.idEdge);
909
                modifiedCost.setIdInverseEdge(edgePair.idInverseEdge);
910
                if (direction == 3)
911
                {
912
                        if (edgePair.getIdEdge() != -1)
913
                        {
914
                                GvEdge edge = getGraph().getEdgeByID(edgePair.getIdEdge());
915
                                modifiedCost.setOldCost(edge.getWeight());
916
                                edge.setWeight(-1.0);
917
                        }
918
                        if (edgePair.getIdInverseEdge() != -1)
919
                        {
920
                                GvEdge inverseEdge = getGraph().getEdgeByID(edgePair.getIdInverseEdge());
921
                                modifiedCost.setOldInverseCost(inverseEdge.getWeight());
922
                                inverseEdge.setWeight(-1.0);
923
                        }
924
                }
925
                if (direction == 1)
926
                {
927
                        if (edgePair.getIdEdge() != -1)
928
                        {
929
                                GvEdge edge = getGraph().getEdgeByID(edgePair.getIdEdge());
930
                                modifiedCost.setOldCost(edge.getWeight());
931
                                edge.setWeight(-1.0);
932
                        }
933
                }
934
                if (direction == 2)
935
                {
936
                        if (edgePair.getIdInverseEdge() != -1)
937
                        {
938
                                GvEdge inverseEdge = getGraph().getEdgeByID(edgePair.getIdInverseEdge());
939
                                modifiedCost.setOldInverseCost(inverseEdge.getWeight());
940
                                inverseEdge.setWeight(-1.0);
941
                        }
942
                }
943
                modifiedCosts.add(modifiedCost);
944
                modifiedCost.setApplied(true);
945
                return modifiedCost;
946
        }
947
        
948
        /**
949
         * Remove ALL turn costs
950
         */
951
        public void removeTurnCosts() {
952
                for (int i=0; i < turnCosts.size(); i++) {
953
                        GvTurn turn = turnCosts.get(i);
954
//                        turn.getNode().getTurnCosts().remove(turn);
955
                        turn.getNode().removeTurnCosts();
956
                }
957
                turnCosts = new ArrayList<GvTurn>();
958
        }
959

    
960
        /**
961
         * Be careful about the ORDER!!!!
962
         * @param modifiedCost
963
         */
964
        public boolean removeModifiedCost(GvModifiedCost modifiedCost) {
965
                if (!modifiedCosts.remove(modifiedCost))
966
                        return false;
967
                int idArc = modifiedCost.getIdArc();
968
                int direction = modifiedCost.getDirection();
969
                EdgePair edgePair = getGraph().getEdgesByIdArc(idArc);
970
                if (direction == 3)
971
                {
972
                        if (edgePair.getIdEdge() != -1)
973
                        {
974
                                GvEdge edge = getGraph().getEdgeByID(edgePair.getIdEdge());
975
                                edge.setWeight(modifiedCost.getOldCost());
976
                        }
977
                        if (edgePair.getIdInverseEdge() != -1)
978
                        {
979
                                GvEdge inverseEdge = getGraph().getEdgeByID(edgePair.getIdInverseEdge());
980
                                inverseEdge.setWeight(modifiedCost.getOldInverseCost());
981
                        }
982
                }
983
                if (direction == 1)
984
                {
985
                        if (edgePair.getIdEdge() != -1)
986
                        {
987
                                GvEdge edge = getGraph().getEdgeByID(edgePair.getIdEdge());
988
                                edge.setWeight(modifiedCost.getOldCost());
989
                        }
990
                }
991
                if (direction == 2)
992
                {
993
                        if (edgePair.getIdInverseEdge() != -1)
994
                        {
995
                                GvEdge inverseEdge = getGraph().getEdgeByID(edgePair.getIdInverseEdge());
996
                                inverseEdge.setWeight(modifiedCost.getOldInverseCost());
997
                        }
998
                }
999
                return true;
1000
        }
1001

    
1002
        public void addFlagListener(IFlagListener listener) {
1003
                if (!flagListeners.contains(listener)) {
1004
                        flagListeners.add(listener);
1005
                }
1006
        }
1007
        
1008
        public void removeFlagListener(IFlagListener listener){
1009
                flagListeners.remove(listener);
1010
        }
1011
        
1012
        private void callFlagsChanged(int reason) {
1013
                if (dispatching) {
1014
                        for (int i=0; i < flagListeners.size(); i++)
1015
                        {
1016
                                IFlagListener listener = (IFlagListener) flagListeners.get(i);
1017
                                listener.flagsChanged(reason);
1018
                        }
1019
                }
1020
        }
1021
        
1022
        /**
1023
         * Useful to do batch modifies. (For example, add lot of flags
1024
         * and when finished (endModifying), throw event.
1025
         */
1026
        public void beginModifyingFlags() {
1027
                dispatching = false;
1028
        }
1029

    
1030
        public void endModifyingFlags() {
1031
                dispatching = true;
1032
                callFlagsChanged(IFlagListener.FLAG_MANY_CHANGES);
1033
        }
1034
        /**
1035
         * Mueve un flag de la posici?n from a la posici?n to.
1036
         *
1037
         * @param from origen.
1038
         * @param to destino.
1039
         * 
1040
         */
1041
        public void moveTo(int from, int to) throws CancelationException {
1042
                int newfrom=flags.size()-from-1;
1043
                int newto=flags.size()-to-1;
1044
                if ( newfrom < 0 || newfrom >=flags.size() || newto < 0 || newto >= flags.size()) return;
1045
                GvFlag aux = (GvFlag) flags.get(newfrom);
1046
                flags.remove(newfrom);
1047
                flags.add(newto, aux);
1048
                callFlagsChanged(IFlagListener.FLAG_REORDER);
1049
        }
1050

    
1051
        public ArrayList getEdgeTypes() {
1052
                // TODO: Tener esto precalculado
1053
                TreeMap map = new TreeMap();
1054
                ArrayList ret = new ArrayList();
1055
                for (int i = 0; i < graph.numEdges(); i++)
1056
                {
1057
                        GvEdge edge = graph.getEdgeByID(i);
1058
                        Integer type = new Integer(edge.getType());
1059
                        if (!map.containsKey(type))
1060
                        {
1061
                                map.put(type, type);                                
1062
                        }
1063
                }
1064
                Iterator it = map.entrySet().iterator();
1065
                while (it.hasNext())
1066
                {
1067
                        Map.Entry entry = (Map.Entry) it.next();
1068
                        Integer type = (Integer) entry.getKey();
1069
                        ret.add(type);
1070
                }
1071
                return ret;
1072
        }
1073

    
1074
        public Hashtable getVelocities() {
1075
                return velocities ;
1076
        }
1077

    
1078
        public void setVelocities(Hashtable veloMeters) {
1079
                for (int i=0; i < getGraph().numEdges(); i++)
1080
                {
1081
                        GvEdge edge = getGraph().getEdgeByID(i);
1082
                        
1083
                        Integer key = new Integer(edge.getType());
1084
                        Double vel = (Double) veloMeters.get(key);
1085
                        edge.setWeight(edge.getDistance() / vel.doubleValue()); // segundos
1086
                }
1087
                this.velocities = veloMeters;
1088

    
1089
                
1090
        }
1091

    
1092
}