Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extGraph / src / org / gvsig / graph / solvers / ServiceAreaExtractor2.java @ 22687

History | View | Annotate | Download (26.9 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

    
42
// 18/09/2007 fjp
43
// @author: Fco. Jos? Pe?arrubia        fpenarru@gmail.com
44
package org.gvsig.graph.solvers;
45

    
46
import java.io.File;
47
import java.sql.Types;
48
import java.util.ArrayList;
49
import java.util.HashMap;
50
import java.util.HashSet;
51
import java.util.Hashtable;
52
import java.util.Iterator;
53
import java.util.Map;
54
import java.util.Set;
55

    
56
import org.gvsig.exceptions.BaseException;
57
import org.gvsig.fmap.algorithm.triangulation.PirolTriangulator;
58
import org.gvsig.fmap.algorithm.triangulation.TIN;
59
import org.gvsig.fmap.algorithm.triangulation.Triangle;
60
import org.gvsig.fmap.algorithm.triangulation.Vertex;
61
import org.gvsig.graph.core.EdgePair;
62
import org.gvsig.graph.core.GvEdge;
63
import org.gvsig.graph.core.GvNode;
64
import org.gvsig.graph.core.IGraph;
65
import org.gvsig.graph.core.Network;
66
import org.gvsig.graph.core.NetworkUtils;
67

    
68
import com.hardcode.gdbms.driver.exceptions.InitializeDriverException;
69
import com.hardcode.gdbms.driver.exceptions.InitializeWriterException;
70
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
71
import com.hardcode.gdbms.engine.values.Value;
72
import com.hardcode.gdbms.engine.values.ValueFactory;
73
import com.iver.cit.gvsig.exceptions.layers.LoadLayerException;
74
import com.iver.cit.gvsig.exceptions.visitors.ProcessWriterVisitorException;
75
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
76
import com.iver.cit.gvsig.fmap.core.FShape;
77
import com.iver.cit.gvsig.fmap.core.IGeometry;
78
import com.iver.cit.gvsig.fmap.core.ShapeFactory;
79
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
80
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
81
import com.iver.cit.gvsig.fmap.drivers.SHPLayerDefinition;
82
import com.iver.cit.gvsig.fmap.edition.DefaultRowEdited;
83
import com.iver.cit.gvsig.fmap.edition.IRowEdited;
84
import com.iver.cit.gvsig.fmap.edition.writers.shp.ShpWriter;
85
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
86
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
87
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
88
import com.vividsolutions.jts.algorithm.CGAlgorithms;
89
import com.vividsolutions.jts.geom.Coordinate;
90
import com.vividsolutions.jts.geom.Geometry;
91
import com.vividsolutions.jts.geom.GeometryFactory;
92
import com.vividsolutions.jts.geom.LineString;
93
import com.vividsolutions.jts.geom.LinearRing;
94
import com.vividsolutions.jts.geom.Polygon;
95

    
96
/**
97
 * @author fjp
98
 * 
99
 * This class can label nodes with distances and costs to a flag. You will
100
 * obtain a temp shp layer with fields IdArc, IdEdge, CostOrig, DistOrig,
101
 * CostEnd, DistEnd, IdFlag
102
 * 
103
 * La diferencia con ServiceAreaExtractor es que esta versi?n escucha al
104
 * algoritmo Dijkstra, y va montando el shp de l?neas conforme va siendo
105
 * explorada la red. La gran ventaja de hacerlo as? es que no dependes del
106
 * tama?o de la red. Solo recorres los tramos y nodos que exploras, de forma que
107
 * si limitas el ?rea de servicio a una distancia m?xima, la red solo se explora
108
 * hasta esa distancia / coste.
109
 * 
110
 */
111
public class ServiceAreaExtractor2 implements IDijkstraListener {
112
        private static String tempDirectoryPath = System
113
                        .getProperty("java.io.tmpdir");
114

    
115
        static FieldDescription[] fields = new FieldDescription[7];
116
        static {
117
                FieldDescription fieldDesc = new FieldDescription();
118
                fieldDesc.setFieldName("IDARC");
119
                fieldDesc.setFieldType(Types.INTEGER);
120
                fieldDesc.setFieldLength(20);
121
                fieldDesc.setFieldDecimalCount(0);
122
                fields[0] = fieldDesc;
123

    
124
                fieldDesc = new FieldDescription();
125
                fieldDesc.setFieldName("IDEDGE");
126
                fieldDesc.setFieldType(Types.INTEGER);
127
                fieldDesc.setFieldLength(20);
128
                fieldDesc.setFieldDecimalCount(0);
129
                fields[1] = fieldDesc;
130

    
131
                fieldDesc = new FieldDescription();
132
                fieldDesc.setFieldName("COSTORIG");
133
                fieldDesc.setFieldType(Types.DOUBLE);
134
                fieldDesc.setFieldLength(20);
135
                fieldDesc.setFieldDecimalCount(5);
136
                fields[2] = fieldDesc;
137

    
138
                fieldDesc = new FieldDescription();
139
                fieldDesc.setFieldName("DISTORIG");
140
                fieldDesc.setFieldType(Types.DOUBLE);
141
                fieldDesc.setFieldLength(20);
142
                fieldDesc.setFieldDecimalCount(5);
143
                fields[3] = fieldDesc;
144

    
145
                fieldDesc = new FieldDescription();
146
                fieldDesc.setFieldName("COSTEND");
147
                fieldDesc.setFieldType(Types.DOUBLE);
148
                fieldDesc.setFieldLength(20);
149
                fieldDesc.setFieldDecimalCount(5);
150
                fields[4] = fieldDesc;
151

    
152
                fieldDesc = new FieldDescription();
153
                fieldDesc.setFieldName("DISTEND");
154
                fieldDesc.setFieldType(Types.DOUBLE);
155
                fieldDesc.setFieldLength(20);
156
                fieldDesc.setFieldDecimalCount(5);
157
                fields[5] = fieldDesc;
158

    
159
                fieldDesc = new FieldDescription();
160
                fieldDesc.setFieldName("IDFLAG");
161
                fieldDesc.setFieldType(Types.INTEGER);
162
                fieldDesc.setFieldLength(20);
163
                fieldDesc.setFieldDecimalCount(5);
164
                fields[6] = fieldDesc;
165

    
166
        }
167
        
168
        static FieldDescription[] fieldsPol = new FieldDescription[2];
169
        static {
170
                FieldDescription fieldDesc = new FieldDescription();
171
                fieldDesc.setFieldName("COST");
172
                fieldDesc.setFieldType(Types.DOUBLE);
173
                fieldDesc.setFieldLength(20);
174
                fieldDesc.setFieldDecimalCount(5);
175
                fieldsPol[0] = fieldDesc;
176
                
177
                fieldDesc = new FieldDescription();
178
                fieldDesc.setFieldName("IDFLAG");
179
                fieldDesc.setFieldType(Types.INTEGER);
180
                fieldDesc.setFieldLength(20);
181
                fieldDesc.setFieldDecimalCount(5);
182
                fieldsPol[1] = fieldDesc;
183

    
184
        }
185
        
186
        static GeometryFactory gf = new GeometryFactory();
187

    
188
        private class VisitedEdge {
189
                private GvEdge edge;
190
                private double percentcost;
191
                public VisitedEdge(GvEdge edge) {
192
                        this.edge = edge;
193
                        IGraph g = net.getGraph();
194
                        GvNode nOrig = g.getNodeByID(edge.getIdNodeOrig());
195
                        double maxCost = costs[costs .length-1];
196
                        double costCalculated = nOrig.getBestCost() + edge.getWeight();
197
                        
198
                        if (costCalculated < maxCost)
199
                                percentcost = 1.0;
200
                        else
201
                        {
202
                                double percentCostCalculated = (maxCost - nOrig.getBestCost())/ edge.getWeight();
203
                                percentcost = percentCostCalculated;
204
                        }
205
                        
206
                }
207
                public GvEdge getEdge() {
208
                        return edge;
209
                }
210
                public double getPercentcost() {
211
                        return percentcost;
212
                }
213
                public void setPercentCost(double d) {
214
                        this.percentcost = d;
215
                        
216
                }
217
        }
218

    
219
        private Network net;
220

    
221
        private ShpWriter shpWriter;
222
        private ShpWriter shpWriterPol;
223
        private ShpWriter shpWriterTri;
224
        private File fTempPol;
225
        private File fTempTri;
226
        private SHPLayerDefinition layerDefPol;
227
        private SHPLayerDefinition layerDefTri;
228
        
229
        
230
        private HashMap<String, VisitedEdge> visitedEdges = new HashMap();
231

    
232
        private File fTemp;
233

    
234
        private SHPLayerDefinition layerDef;
235

    
236
        private int idFlag;
237

    
238
        private ReadableVectorial adapter;
239

    
240
//        private double maxCost;
241

    
242
        private Geometry serviceArea;
243
        private ArrayList <Geometry> serviceAreaPolygons;
244
        
245
        private Hashtable<Integer, EdgePair> smallSegments = new Hashtable();
246

    
247
        private double[] costs = null;        
248
        
249
        private boolean bDoCompactArea = false;
250
        
251
        private HashSet<Coordinate> borderCoords = new HashSet<Coordinate>();
252

    
253
        private HashSet<Coordinate> nodes;
254
//        DelaunayFast tri2;
255
//        DelaunayWatson tri2;
256
        PirolTriangulator pirolTriangulator = new PirolTriangulator();
257
        /**
258
         * @param net
259
         * @throws InitializeWriterException
260
         * @throws ReadDriverException
261
         * @throws InitializeDriverException
262
         */
263
        public ServiceAreaExtractor2(Network net) throws BaseException {
264
                this.net = net;
265
                int aux = (int) (Math.random() * 1000);
266
                
267
                nodes = new HashSet<Coordinate>();
268
                
269
                
270
                String nameLine = "tmpServiceAreaLine" + aux + ".shp";
271
                String namePol = "tmpServiceAreaPol" + aux + ".shp";
272
                String nameTri = "tmpTri" + aux + ".shp";
273
                fTemp = new File(tempDirectoryPath + "/" + nameLine );
274
                fTempPol = new File(tempDirectoryPath + "/" + namePol );
275
                fTempTri = new File(tempDirectoryPath + "/" + nameTri );
276
                
277
                layerDef = new SHPLayerDefinition();
278
                layerDef.setFile(fTemp);
279
                layerDef.setName(nameLine);                
280
                layerDef.setFieldsDesc(fields);
281
                layerDef.setShapeType(FShape.LINE);
282

    
283
                layerDefPol = new SHPLayerDefinition();
284
                layerDefPol.setFile(fTempPol);
285
                layerDefPol.setName(namePol);                
286
                layerDefPol.setFieldsDesc(fieldsPol);
287
                layerDefPol.setShapeType(FShape.POLYGON);
288

    
289
                layerDefTri = new SHPLayerDefinition();
290
                layerDefTri.setFile(fTempTri);
291
                layerDefTri.setName(nameTri);                
292
                layerDefTri.setFieldsDesc(fieldsPol);
293
                layerDefTri.setShapeType(FShape.POLYGON);
294
                
295
                shpWriter = new ShpWriter();
296
                shpWriter.setFile(fTemp);
297
                shpWriter.initialize(layerDef);
298

    
299
                shpWriterPol = new ShpWriter();
300
                shpWriterPol.setFile(fTempPol);
301
                shpWriterPol.initialize(layerDefPol);
302
                
303
                shpWriterTri = new ShpWriter();
304
                shpWriterTri.setFile(fTempTri);
305
                shpWriterTri.initialize(layerDefTri);
306
                
307
                shpWriter.preProcess();
308
                shpWriterPol.preProcess();
309
                shpWriterTri.preProcess();
310
                
311
                FLyrVect lyr = net.getLayer();
312
                adapter = lyr.getSource();
313
                adapter.start();
314
                
315
                serviceAreaPolygons = new ArrayList<Geometry>();
316

    
317
        }
318

    
319
        /**
320
         * Devuelve el ?ndice del intervalo m?s alto que contiene a ese valor.
321
         * @param bestCost
322
         * @param costs
323
         * @return
324
         */
325
        private int getCostInterval(double bestCost, double[] costs) {
326
                int ret = 0;
327
                if (bestCost > costs[costs.length-1])
328
                        return -1;
329
                for (int i=costs.length-1; i>=0; i--) {
330
                        if (bestCost > costs[i])
331
                        {
332
                                ret = i+1;
333
                                break;
334
                        }
335
                }
336
                return ret;
337
        }
338

    
339
        /**
340
         * We process each edge and prepare a list of polygons, classified by
341
         * cost
342
         * @param edge
343
         * @param nodeOrig
344
         * @param nodeEnd
345
         * @param geom
346
         * @param costs
347
         */
348
        private void processEdgeForPolygon(GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, IGeometry geom, double[] costs) {
349
                if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
350
                {                
351
                        // miramos en qu? pol?gono cae ese edge POR COMPLETO 
352
                        // El coste de su punto final es menor que uno de los costes.
353
                        int indexInterval = getCostInterval(nodeEnd.getBestCost(), costs);
354
                        // Un pol?gono por cada zona
355
                        Geometry jtsGeom = geom.toJTSGeometry();
356
                        if (indexInterval != -1)
357
                        {
358
                                for (int i=costs.length-1; i >= indexInterval; i--) {
359
                                        calculateConvexHull(jtsGeom, i);
360
                                }
361
                        }
362
                        double maxCost = costs[costs.length-1];
363
                        // Es -1 si caso l?mite externo
364
                        if (indexInterval < costs.length-1)
365
                        {
366
                                // Caso l?mite externo
367
                                if ((nodeEnd.getBestCost() > maxCost) &&                                                
368
                                                (nodeOrig.getBestCost() < maxCost))
369
                                {
370
                                        double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
371
                                        if (edge.getDirec() == 0) // Sentido inverso
372
                                                pct = 1-pct;
373
                                        
374
                                        LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
375
                                        calculateConvexHull(partial, costs.length-1);
376
                                        return;
377
                                }
378
                                // Parcial interno
379
                                maxCost = costs[indexInterval+1];
380
                                if ((nodeOrig.getBestCost() < maxCost) &&
381
                                                (nodeEnd.getBestCost() > maxCost)) 
382
                                {
383
                                        // A ese tramo hemos llegado parcialmente
384
                                         
385
                                        double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
386
                                        try {
387
                                                LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
388
                                                calculateConvexHull(partial, indexInterval+1);                                                        
389
                                        }
390
                                        catch (Exception e)
391
                                        {
392
                                                e.printStackTrace();
393
                                        }
394
                                        
395
                                }
396
                        }
397
                } 
398

    
399
                
400
        }
401

    
402
        /**
403
         * @param jtsGeom
404
         * @param i
405
         */
406
        private void calculateConvexHull(Geometry jtsGeom, int i) {
407
                if (serviceAreaPolygons.size() <= i) { // se crea por primera vez
408
                        Geometry gIni = jtsGeom; 
409
                        serviceAreaPolygons.add(i, gIni);
410
                }
411
                else
412
                {
413
                        Geometry antG = serviceAreaPolygons.get(i);
414
                        if (antG == null)
415
                                antG = jtsGeom;
416
                        else
417
                        {
418
                                antG = antG.union(jtsGeom);                                
419
                        }
420
                        antG = antG.convexHull();
421
                        serviceAreaPolygons.set(i, antG);
422
                }
423
        }
424

    
425

    
426
        private void writePartialEdge(int i, IGeometry geom, GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, int idFlag, double maxCost) throws ProcessWriterVisitorException {
427
                Geometry jtsGeom = geom.toJTSGeometry();
428
                double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
429
                if (edge.getDirec() == 0) // Sentido inverso
430
                        pct = 1-pct;
431
                LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
432
                if (serviceArea == null)
433
                        serviceArea = partial;
434
                else
435
                {
436
                        serviceArea = serviceArea.union(partial);
437
                        serviceArea = serviceArea.convexHull();
438
                }
439
                
440
                IGeometry newGeom = FConverter.jts_to_igeometry(partial);
441

    
442
                Value[] values = new Value[7];
443
                values[0] = ValueFactory.createValue(i);
444
                values[1] = ValueFactory.createValue(edge.getIdEdge());
445
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
446
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
447
                values[4] = ValueFactory.createValue(maxCost);
448
                values[5] = ValueFactory.createValue(nodeOrig.getAccumulatedLength() + edge.getDistance()*pct);
449
                values[6] = ValueFactory.createValue(idFlag);
450
                DefaultFeature feat = new DefaultFeature(newGeom, values);
451
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, i);
452
                shpWriter.process(row);
453
                
454
//                // TODO: TROZO DEL RESTO
455
//                int direc = 0;
456
//                pct = pct+0.02;
457
//                if (edge.getDirec() == 0)
458
//                {
459
//                        direc = 1;
460
//                        pct = pct - 0.04;
461
//                }
462
//                LineString partial2 = NetworkUtils.getPartialLineString(jtsGeom, pct, direc);                
463
//                IGeometry newGeom2 = FConverter.jts_to_igeometry(partial2);
464
//                values[6] = ValueFactory.createValue(-2);
465
//                DefaultFeature feat2 = new DefaultFeature(newGeom2, values);
466
//                IRowEdited row2 = new DefaultRowEdited(feat2, DefaultRowEdited.STATUS_ADDED, i);
467
//                shpWriter.process(row2);
468

    
469
                // before
470
                addUniqueNode(nodeOrig.getX(), nodeOrig.getY(), nodeOrig.getBestCost());
471
                // ON
472
                Coordinate cAux = null;
473
                if (edge.getDirec() == 0) // Sentido inverso
474
                        cAux = partial.getCoordinateN(0);
475
                else
476
                        cAux = partial.getCoordinateN(partial.getNumPoints()-1);
477
                addUniqueNode(cAux.x, cAux.y, maxCost);
478
                
479
                // after
480
//                addUniqueNode(nodeEnd.getX(), nodeEnd.getY(), nodeEnd.getBestCost());
481
                
482
                if (bDoCompactArea) {
483
//                        processCompact(partial);
484
                        Coordinate cLimit = null;
485
                        if (edge.getDirec() == 0) // Sentido inverso
486
                                cLimit = partial.getCoordinateN(0);
487
                        else
488
                                cLimit = partial.getCoordinateN(partial.getNumPoints()-1);
489
                        processCompact(cLimit.x, cLimit.y);
490
//                        processCompact(nodeEnd.getX(), nodeEnd.getY());
491
                }
492
                
493
        }
494
        
495
        private void addUniqueNode(double x, double y, double z) {
496
                Coordinate c = new Coordinate(x,y,z);
497
                if (!borderCoords.contains(c)) {
498
                        borderCoords.add(c);
499
                }
500
        }
501
        
502
        /**
503
         * FIXME: CHANGE THE NAME OF THIS METHOD. Now, it writes al nodes with cost < maxCost
504
         * @return
505
         * @throws BaseException
506
         */
507
        public FLyrVect getBorderPoints() throws BaseException {
508
                File fTempPoints = new File(tempDirectoryPath + "/borderPoints.shp");
509
                
510
                FieldDescription[] fieldsPoints = new FieldDescription[1];
511
                FieldDescription fieldDesc = new FieldDescription();
512
                fieldDesc.setFieldName("COST");
513
                fieldDesc.setFieldType(Types.DOUBLE);
514
                fieldDesc.setFieldLength(20);
515
                fieldDesc.setFieldDecimalCount(5);
516
                fieldsPoints[0] = fieldDesc;
517

    
518
                SHPLayerDefinition layerDef = new SHPLayerDefinition();
519
                layerDef.setFile(fTempPoints);
520
                layerDef.setName("BorderPoints");                
521
                layerDef.setFieldsDesc(fieldsPoints);
522
                layerDef.setShapeType(FShape.POINT);
523

    
524
                
525
                ShpWriter shpWriter = new ShpWriter();
526
                shpWriter.setFile(fTempPoints);
527
                shpWriter.initialize(layerDef);
528

    
529
                int i=0;
530
                shpWriter.preProcess();
531
                for (Iterator it = borderCoords.iterator(); it.hasNext();) {
532
                        Coordinate c = (Coordinate) it.next();
533
                        Value[] values = new Value[1];                        
534
                        values[0] = ValueFactory.createValue(c.z);
535
                        IGeometry geom = ShapeFactory.createPoint2D(c.x, c.y);
536
                        DefaultFeature feat = new DefaultFeature(geom, values);
537
                        IRowEdited row = new DefaultRowEdited(feat,
538
                                        DefaultRowEdited.STATUS_ADDED, i++);
539
                        shpWriter.process(row);
540
                        
541
                }
542
                shpWriter.postProcess();
543
                
544
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDef.getName(), "gvSIG shp driver", 
545
                                layerDef.getFile(), null);
546
                return lyr;
547

    
548
                
549
        }
550

    
551
        private void processCompact(LineString partial) {
552
                Coordinate cIni = partial.getCoordinateN(0);
553
                Coordinate cEnd = partial.getCoordinateN(partial.getNumPoints()-1);
554
//                System.out.println("PARTIAL c1=" + cIni + " cEnd=" + cEnd);
555
                processCompact(cIni.x, cIni.y);
556
                processCompact(cEnd.x, cEnd.y);
557
        }
558

    
559
        private void writeTotalEdge(int i, IGeometry geom, GvEdge edge,
560
                        GvNode nodeOrig, GvNode nodeEnd, int idFlag)
561
                        throws ProcessWriterVisitorException {
562
                Value[] values = new Value[7];
563
                values[0] = ValueFactory.createValue(i);
564
                values[1] = ValueFactory.createValue(edge.getIdEdge());
565
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
566
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
567
                values[4] = ValueFactory.createValue(nodeEnd.getBestCost());
568
                values[5] = ValueFactory.createValue(nodeEnd.getAccumulatedLength());
569
                values[6] = ValueFactory.createValue(idFlag);
570
                
571
                if (bDoCompactArea) {
572
                        // This code is necessary ONLY if you want to triangulate also with interior points
573
                        // (To draw a 3D view, for example.
574
                        // TODO: Use borderPoints in triangulation instead of "nodes"
575
                        // Origin
576
                        addUniqueNode(nodeOrig.getX(), nodeOrig.getY(), nodeOrig.getBestCost());
577
                        
578
                        // end
579
                        addUniqueNode(nodeEnd.getX(), nodeEnd.getY(), nodeEnd.getBestCost());
580
                        
581
//                        System.out.println(" c1=" + cIni + " cEnd=" + cEnd);
582
//                        processCompact(nodeOrig.getX(), nodeOrig.getY());
583
//                        processCompact(nodeEnd.getX(), nodeEnd.getY());
584
                }
585

    
586

    
587
                DefaultFeature feat = new DefaultFeature(geom, values);
588
                IRowEdited row = new DefaultRowEdited(feat,
589
                                DefaultRowEdited.STATUS_ADDED, i);
590
                shpWriter.process(row);
591
        }
592

    
593
        private void processCompact(double x, double y) {
594
//                FPoint2D p = new FPoint2D(x,y);
595
                Coordinate c = new Coordinate(x,y);
596
//                System.out.println("PARTIAL c1=" + cIni + " cEnd=" + cEnd);
597
                if (!nodes.contains(c))
598
                        nodes.add(c);
599
                else
600
                {
601
                        System.out.print("Nodo ya contenido");
602
                }
603
                
604
        }
605

    
606
        public boolean adjacentEdgeVisited(GvNode fromNode, GvEdge edge) {
607
                insertVisitedEdge(edge);
608
                
609
                return false;
610
        }
611

    
612
        /**
613
         * Si el coste m?nimo del edge > costemax, salimos del m?todo.
614
         * Miramos si edge est? ya en la lista.
615
         * Si no est?, lo a?adimos.
616
         * Si est?, hay que mirar el porcentaje recorrido sobre ese tramo.
617
         * Casos posibles:
618
         * EdgeA al 100 % => No se a?ade este.
619
         * EdgeA.percentCost < 1.0. 
620
         *                 Comprobamos el percent de el nuevo. Si entre los dos suman > 1.0
621
         *                 marcamos el antiguo al 1.0 para que se escriba el tramo completo.
622
         * 
623
         *                 Si no suman 1.0, hay que a?adir este nuevo Edge, con el porcentaje
624
         *                 correspondiente.
625
         * @param edge
626
         */
627
        private void insertVisitedEdge(GvEdge edge) {
628
                IGraph g = net.getGraph();
629
                GvNode n1 = g.getNodeByID(edge.getIdNodeOrig());
630
                double maxCost = costs[costs .length-1];
631
                if (n1.getBestCost() > maxCost)
632
                        return; // edge outside service area.
633
                
634
                String key = "" + edge.getIdArc();
635
                if (!visitedEdges.containsKey(key))        
636
                {
637
                        // En el constructor calculamos el porcentaje recorrido y lo guardamos
638
                        visitedEdges.put(key, new VisitedEdge(edge));
639
//                        System.out.println("idEdge adjacent= " + edge.getIdEdge());
640
                }
641
                else
642
                {
643
                        // Recuperamos el visiteEdge que hab?amos metido y miramos sus porcentajes
644
                        // recorridos. Si entre los dos porcentajes NO suman m?s de uno, quiere decir
645
                        // que ah? se queda un tramo central al que no llegamos ni desde un lado ni
646
                        // desde el otro. Por eso guardamos cada trocito al que hemos llegado por separado, 
647
                        // uno con la clave idArc y otro con la clave IdArc_.
648
                        VisitedEdge edgeAnt = visitedEdges.get(key);
649
//                        GvEdge savedEdge = edgeAnt.getEdge();
650
                        if (edgeAnt.getPercentcost() == 1.0)
651
                                return; // Ya est? completo, no a?adimos nada.
652
                        
653
                        double percentCostCalculated = (maxCost - n1.getBestCost())/ edge.getWeight();
654
                        if ((percentCostCalculated + edgeAnt.getPercentcost()) >= 1.0)
655
                                edgeAnt.setPercentCost(1.0);
656
                        else
657
                        {
658
                                visitedEdges.put(key + "_", new VisitedEdge(edge));
659
                        }
660

    
661
                }
662
        }
663

    
664
        public boolean minimumCostNodeSelected(GvNode node) {
665
//                IGraph g = net.getGraph();
666
//                int idEdge = node.getFromLink();
667
//                if (idEdge == -1) 
668
//                        return false;
669
//                GvEdge edge = g.getEdgeByID(idEdge);
670
//                insertVisitedEdge(edge);
671
                return false; // true if we want to stop Dijkstra
672
        }
673

    
674
        public void setIdFlag(int idFlag) {
675
                this.idFlag = idFlag;
676
        }
677
        
678
        /**
679
         * Write edges and polygons associated with active flag and costs
680
         * @param costs
681
         * @throws BaseException
682
         */
683
        public void writeServiceArea() throws BaseException {
684
                Set<Map.Entry<String, VisitedEdge>> keySet = visitedEdges.entrySet();
685
                
686
                GvEdge edge;
687
                IGraph g = net.getGraph();
688
//                Integer idEdge;
689
                double maxCost = costs[costs .length-1];
690
                serviceAreaPolygons = new ArrayList<Geometry>(costs.length);
691
                for (int i=0; i < costs.length-1; i++)
692
                        serviceAreaPolygons.add(null);
693
                
694
                for (Map.Entry<String, VisitedEdge> entry : keySet) {
695
//                        idEdge = entry.getKey();
696
                        VisitedEdge visitedEdge = entry.getValue(); 
697
                        edge = visitedEdge.getEdge();
698
                        GvNode nodeEnd = g.getNodeByID(edge.getIdNodeEnd());
699
                        GvNode nodeOrig = g.getNodeByID(edge.getIdNodeOrig());
700
                        IGeometry geom;
701
                        try {
702
                                geom = adapter.getShape(edge.getIdArc());
703
                                processEdgeForPolygon(edge, nodeOrig, nodeEnd, geom, costs);
704
                                double costAux = nodeOrig.getBestCost() + edge.getWeight();
705
//                                if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
706
                                {
707
                                        if (visitedEdge.getPercentcost() == 1.0) {
708
                                                // A ese tramo hemos llegado por completo
709
                                                // Recuperamos su distancia y etiquetamos.
710
                                                writeTotalEdge(edge.getIdArc(), geom, edge, nodeOrig, nodeEnd, idFlag);        
711
                                        }
712
                                        else
713
                                        {
714
                                                // El CASO EN EL QUE HAS LLEGADO POR LOS
715
                                                // 2 LADOS PERO HAY UN TRAMO INALCANZABLE ENMEDIO SE
716
                                                // SOLUCIONA EN writePartialEdge
717
                                                if (nodeOrig.getBestCost() < maxCost) { // FIXME: Creo que este if no tiene sentido.
718
                                                        // A ese tramo hemos llegado parcialmente 
719
                                                        // Recuperamos su distancia y etiquetamos.
720
                                                        writePartialEdge(edge.getIdArc(), geom, edge, nodeOrig, nodeEnd, idFlag, maxCost);        
721
                                                        
722
                                                }
723
                                        } // else
724
                                } // if nodeEnd > nodeOrig
725
                        
726
                        } catch (BaseException e) {
727
                                e.printStackTrace();
728
                                throw new RuntimeException(e);
729
                        }
730
                        
731
                } // for
732
                for (int j=serviceAreaPolygons.size()-1; j>=0; j--) {
733
                        Geometry jtsGeom = serviceAreaPolygons.get(j);
734
                        writePolygon(idFlag, costs[j], jtsGeom);
735
                }
736

    
737
                if (bDoCompactArea) {
738
                        calculateTriangulation();
739
                        getBorderPoints();
740
                }
741
                
742
        }
743

    
744
        private void calculateTriangulation() {
745
                
746
                int numPoints = nodes.size();
747
            Iterator it = nodes.iterator();
748
            for (int i=0; i<numPoints; i++) {
749
                    Coordinate node = (Coordinate) it.next();
750
                    Vertex v = new Vertex(node.x, node.y);
751
                    pirolTriangulator.addVertex(v);
752
            }
753

    
754
            TIN tin = pirolTriangulator.calculateTriangulation();
755
                System.out.println("Fin de trayecto. Num. tri?ngulos=" + tin.getTriangles().size());
756
                for (int i=0; i< tin.getTriangles().size(); i++) {
757
                      try {
758
                                writeTri(tin.getTriangles().get(i));
759
                        } catch (ProcessWriterVisitorException e) {
760
                                // TODO Auto-generated catch block
761
                                e.printStackTrace();
762
                        }
763
            }
764

    
765
                
766
        }
767
        private void writeTri(Triangle t) throws ProcessWriterVisitorException {
768
                Value[] values = new Value[2];
769
                values[0] = ValueFactory.createValue(2.0);
770
                values[1] = ValueFactory.createValue(1);
771
                
772
                Coordinate c1 = new Coordinate(t.getV1().getX(), t.getV1().getY());
773
                Coordinate c2 = new Coordinate(t.getV2().getX(), t.getV2().getY());
774
                Coordinate c3 = new Coordinate(t.getV3().getX(), t.getV3().getY());
775
                Coordinate[] c = new Coordinate[4];
776
                c[0] = c1;
777
                c[1] = c3;
778
                c[2] = c2;
779
                c[3] = c1;
780
                LinearRing linRing = null;
781
                if (CGAlgorithms.isCCW(c))
782
                {
783
                        Coordinate[] ccw = new Coordinate[4];
784
                        ccw[0] = c1;
785
                        ccw[1] = c2;
786
                        ccw[2] = c3;
787
                        ccw[3] = c1;
788
                        linRing = gf.createLinearRing(ccw);
789
                }
790
                else
791
                {
792
                        linRing = gf.createLinearRing(c);
793
//                        return;
794
                }
795
                 
796
                Polygon pol = gf.createPolygon(linRing, null);
797
                
798
                IGeometry geom = FConverter.jts_to_igeometry(pol);
799
                DefaultFeature feat = new DefaultFeature(geom, values);
800
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, idFlag);
801
//                shpWriterPol.process(row);
802
                shpWriterTri.process(row);
803
                
804
        }
805

    
806
        private void writePolygon(int idFlag, double maxCost, Geometry jtsGeom) throws ProcessWriterVisitorException {
807
                Value[] values = new Value[2];
808
                values[0] = ValueFactory.createValue(maxCost);
809
                values[1] = ValueFactory.createValue(idFlag);
810
                
811
                IGeometry geom = FConverter.jts_to_igeometry(jtsGeom);
812
                DefaultFeature feat = new DefaultFeature(geom, values);
813
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, idFlag);
814
                shpWriterPol.process(row);
815
        }
816

    
817
        /**
818
         * Close writers.
819
         * @throws BaseException
820
         */
821
        public void closeFiles() throws BaseException {
822
//                for (int j=serviceAreaPolygons.size()-1; j>=0; j--) {
823
//                        Geometry jtsGeom = serviceAreaPolygons.get(j);
824
//                        writePolygon(idFlag, costs[j], jtsGeom);
825
//                }
826

    
827
                shpWriter.postProcess();
828
                shpWriterPol.postProcess();
829
                shpWriterTri.postProcess();
830
                
831
                adapter.stop();
832
                
833
                
834

    
835
        }
836
        public double[] getCosts() {
837
                return costs;
838
        }
839

    
840
        public void setCosts(double[] costs) {
841
                this.costs = costs;
842
        }
843

    
844
        public FLyrVect getPolygonLayer() throws LoadLayerException {
845
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDefPol.getName(), "gvSIG shp driver", 
846
                                layerDefPol.getFile(), null);
847
                return lyr;
848
        }
849

    
850
        public FLyrVect getLineLayer() throws LoadLayerException {
851
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDef.getName(), "gvSIG shp driver", 
852
                                layerDef.getFile(), null);
853
                return lyr;
854
        }
855

    
856
        public boolean isDoCompactArea() {
857
                return bDoCompactArea;
858
        }
859

    
860
        public void setDoCompactArea(boolean doCompactArea) {
861
                bDoCompactArea = doCompactArea;
862
        }
863

    
864
}