Statistics
| Revision:

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

History | View | Annotate | Download (33 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.awt.geom.Point2D;
47
import java.awt.geom.Rectangle2D;
48
import java.io.File;
49
import java.sql.Types;
50
import java.util.ArrayList;
51
import java.util.Collection;
52
import java.util.HashMap;
53
import java.util.HashSet;
54
import java.util.Iterator;
55
import java.util.Map;
56
import java.util.Set;
57

    
58
import org.gvsig.exceptions.BaseException;
59
import org.gvsig.fmap.algorithm.contouring.ContourCalculator;
60
import org.gvsig.fmap.algorithm.triangulation.OrbisGisTriangulator;
61
import org.gvsig.fmap.algorithm.triangulation.TIN;
62
import org.gvsig.fmap.algorithm.triangulation.Triangle;
63
import org.gvsig.fmap.algorithm.triangulation.Triangulator;
64
import org.gvsig.fmap.algorithm.triangulation.Vertex;
65
import org.gvsig.graph.core.GvEdge;
66
import org.gvsig.graph.core.GvFlag;
67
import org.gvsig.graph.core.GvNode;
68
import org.gvsig.graph.core.IGraph;
69
import org.gvsig.graph.core.Network;
70
import org.gvsig.graph.core.NetworkUtils;
71

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

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

    
120
        static FieldDescription[] fields = new FieldDescription[7];
121
        static {
122
                FieldDescription fieldDesc = new FieldDescription();
123
                fieldDesc.setFieldName("IDARC");
124
                fieldDesc.setFieldType(Types.INTEGER);
125
                fieldDesc.setFieldLength(20);
126
                fieldDesc.setFieldDecimalCount(0);
127
                fields[0] = fieldDesc;
128

    
129
                fieldDesc = new FieldDescription();
130
                fieldDesc.setFieldName("IDEDGE");
131
                fieldDesc.setFieldType(Types.INTEGER);
132
                fieldDesc.setFieldLength(20);
133
                fieldDesc.setFieldDecimalCount(0);
134
                fields[1] = fieldDesc;
135

    
136
                fieldDesc = new FieldDescription();
137
                fieldDesc.setFieldName("COSTORIG");
138
                fieldDesc.setFieldType(Types.DOUBLE);
139
                fieldDesc.setFieldLength(20);
140
                fieldDesc.setFieldDecimalCount(5);
141
                fields[2] = fieldDesc;
142

    
143
                fieldDesc = new FieldDescription();
144
                fieldDesc.setFieldName("DISTORIG");
145
                fieldDesc.setFieldType(Types.DOUBLE);
146
                fieldDesc.setFieldLength(20);
147
                fieldDesc.setFieldDecimalCount(5);
148
                fields[3] = fieldDesc;
149

    
150
                fieldDesc = new FieldDescription();
151
                fieldDesc.setFieldName("COSTEND");
152
                fieldDesc.setFieldType(Types.DOUBLE);
153
                fieldDesc.setFieldLength(20);
154
                fieldDesc.setFieldDecimalCount(5);
155
                fields[4] = fieldDesc;
156

    
157
                fieldDesc = new FieldDescription();
158
                fieldDesc.setFieldName("DISTEND");
159
                fieldDesc.setFieldType(Types.DOUBLE);
160
                fieldDesc.setFieldLength(20);
161
                fieldDesc.setFieldDecimalCount(5);
162
                fields[5] = fieldDesc;
163

    
164
                fieldDesc = new FieldDescription();
165
                fieldDesc.setFieldName("IDFLAG");
166
                fieldDesc.setFieldType(Types.INTEGER);
167
                fieldDesc.setFieldLength(20);
168
                fieldDesc.setFieldDecimalCount(5);
169
                fields[6] = fieldDesc;
170

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

    
189
        }
190
        
191
        static GeometryFactory gf = new GeometryFactory();
192

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

    
224
        private Network net;
225

    
226
        private ShpWriter shpWriter;
227
        private ShpWriter shpWriterPol;
228
//        private ShpWriter shpWriterTri;
229
        private File fTempPol;
230
        private File fTempTri;
231
        private SHPLayerDefinition layerDefPol;
232
        private SHPLayerDefinition layerDefTri;
233
        
234
        
235
        private HashMap<String, VisitedEdge> visitedEdges = new HashMap();
236

    
237
        private File fTemp;
238

    
239
        private SHPLayerDefinition layerDef;
240

    
241
        private int idFlag;
242

    
243
        private ReadableVectorial adapter;
244

    
245
//        private double maxCost;
246

    
247
        private Geometry serviceArea;
248
        private ArrayList <Geometry> serviceAreaPolygons;
249
        
250
//        private Hashtable<Integer, EdgePair> smallSegments = new Hashtable();
251

    
252
        private double[] costs = null;        
253
        
254
        private boolean bDoCompactArea = false;
255
        
256
        private HashSet<Coordinate> borderCoords = new HashSet<Coordinate>();
257

    
258
//        private HashSet<Coordinate> nodes;
259
//        DelaunayFast tri2;
260
//        DelaunayWatson tri2;
261
//        PirolTriangulator triangulator = new PirolTriangulator();
262
//        Triangulator triangulator = new WatsonTriangulator();
263
        Triangulator triangulator = new OrbisGisTriangulator();
264

    
265
        private TIN tin;
266

    
267
        private Rectangle2D.Double fullExtent = null;
268

    
269
        private double[] distances;
270
        /**
271
         * @param net
272
         * @throws InitializeWriterException
273
         * @throws ReadDriverException
274
         * @throws InitializeDriverException
275
         */
276
        public ServiceAreaExtractor2(Network net) throws BaseException {
277
                this.net = net;
278
                int aux = (int) (Math.random() * 1000);
279
                
280
//                nodes = new HashSet<Coordinate>();
281
                
282
                
283
                String nameLine = "tmpServiceAreaLine" + aux + ".shp";
284
                String namePol = "tmpServiceAreaPol" + aux + ".shp";
285
                String nameTri = "tmpTri" + aux + ".shp";
286
                fTemp = new File(tempDirectoryPath + "/" + nameLine );
287
                fTempPol = new File(tempDirectoryPath + "/" + namePol );
288
                fTempTri = new File(tempDirectoryPath + "/" + nameTri );
289
                
290
                layerDef = new SHPLayerDefinition();
291
                layerDef.setFile(fTemp);
292
                layerDef.setName(nameLine);                
293
                layerDef.setFieldsDesc(fields);
294
                layerDef.setShapeType(FShape.LINE);
295

    
296
                layerDefPol = new SHPLayerDefinition();
297
                layerDefPol.setFile(fTempPol);
298
                layerDefPol.setName(namePol);                
299
                layerDefPol.setFieldsDesc(fieldsPol);
300
                layerDefPol.setShapeType(FShape.POLYGON);
301

    
302
                layerDefTri = new SHPLayerDefinition();
303
                layerDefTri.setFile(fTempTri);
304
                layerDefTri.setName(nameTri);                
305
                layerDefTri.setFieldsDesc(fieldsPol);
306
                layerDefTri.setShapeType(FShape.POLYGON);
307
                
308
                shpWriter = new ShpWriter();
309
                shpWriter.setFile(fTemp);
310
                shpWriter.initialize(layerDef);
311

    
312
                shpWriterPol = new ShpWriter();
313
                shpWriterPol.setFile(fTempPol);
314
                shpWriterPol.initialize(layerDefPol);
315
                
316
//                shpWriterTri = new ShpWriter();
317
//                shpWriterTri.setFile(fTempTri);
318
//                shpWriterTri.initialize(layerDefTri);
319
//                shpWriterTri.preProcess();
320
                
321
                shpWriter.preProcess();
322
                shpWriterPol.preProcess();
323
                
324
                
325
                FLyrVect lyr = net.getLayer();
326
                adapter = lyr.getSource();
327
                adapter.start();
328
                
329
                serviceAreaPolygons = new ArrayList<Geometry>();
330

    
331
        }
332

    
333
        /**
334
         * Devuelve el ?ndice del intervalo m?s alto que contiene a ese valor.
335
         * @param bestCost
336
         * @param costs
337
         * @return
338
         */
339
        private int getCostInterval(double bestCost, double[] costs) {
340
                int ret = 0;
341
                if (bestCost > costs[costs.length-1])
342
                        return -1;
343
                for (int i=costs.length-1; i>=0; i--) {
344
                        if (bestCost > costs[i])
345
                        {
346
                                ret = i+1;
347
                                break;
348
                        }
349
                }
350
                return ret;
351
        }
352

    
353
        /**
354
         * We process each edge and prepare a list of polygons, classified by
355
         * cost
356
         * @param edge
357
         * @param nodeOrig
358
         * @param nodeEnd
359
         * @param geom
360
         * @param costs
361
         * @throws ProcessWriterVisitorException 
362
         */
363
        private void processEdgeForPolygon(GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, IGeometry geom, double[] costs) throws ProcessWriterVisitorException {
364
                if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
365
                {                
366
                        // miramos en qu? pol?gono cae ese edge POR COMPLETO 
367
                        // El coste de su punto final es menor que uno de los costes.
368
                        double costAux = nodeOrig.getBestCost() + edge.getWeight();
369
                        int indexInterval = getCostInterval(costAux, costs);
370
                        // Un pol?gono por cada zona
371
                        Geometry jtsGeom = geom.toJTSGeometry();
372
                        if (indexInterval != -1)
373
                        {
374
                                for (int i=costs.length-1; i >= indexInterval; i--) {
375
                                        calculateConvexHull(jtsGeom, i);
376
                                }
377
                                writeTotalEdge(edge.getIdArc(), geom, edge, nodeOrig, nodeEnd, idFlag);
378
                        }
379
                        double maxCost = costs[costs.length-1];
380
                        // Es -1 si caso l?mite externo
381
                        if (indexInterval < costs.length-1)
382
                        {
383
                                // Caso l?mite externo
384
                                if ((costAux > maxCost) &&                                                
385
                                                (nodeOrig.getBestCost() < maxCost))
386
                                {
387
                                        double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
388
                                        if (edge.getDirec() == 0) // Sentido inverso
389
                                                pct = 1-pct;
390
                                        
391
                                        LineString partial = null;
392
                                        if (nodeOrig.getBestCost() == 0) {
393
                                                // Caso particular: empezamos en un tramo y terminamos en ese mismo tramo
394
                                                if (edge.getDirec() == 0) // ponemos el pct como estaba. En el nuevo getPartialString ya lo tiene en cuenta
395
                                                        pct = 1-pct;
396

    
397
                                                GvFlag f = net.getFlags()[idFlag];
398
                                                double pct1 = f.getPct();
399
                                                double Ltotal = jtsGeom.getLength();
400
                                                double Lb = pct * edge.getDistance();
401
                                                double pct2 = Lb / Ltotal; 
402
                                                partial = NetworkUtils.getPartialLineString(jtsGeom, pct1, pct2, edge.getDirec());
403
                                                writePartialEdge2(edge.getIdArc(), partial, edge, nodeOrig, nodeEnd, idFlag, maxCost);
404
                                        }
405
                                        else {
406
                                                partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
407
                                                writePartialEdge(edge.getIdArc(), partial, edge, nodeOrig, nodeEnd, idFlag, maxCost);        
408
                                        }                                        
409
                                        calculateConvexHull(partial, costs.length-1);
410
                                        return;
411
                                }
412
                                // Parcial interno
413
                                maxCost = costs[indexInterval+1];
414
                                if ((nodeOrig.getBestCost() < maxCost) &&
415
                                                (costAux > maxCost)) 
416
                                {
417
                                        // A ese tramo hemos llegado parcialmente
418
                                         
419
                                        double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
420
                                        try {
421
                                                LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
422
                                                writePartialEdge(edge.getIdArc(), partial, edge, nodeOrig, nodeEnd, idFlag, maxCost);        
423
                                                
424
                                                calculateConvexHull(partial, indexInterval+1);                                                        
425
                                        }
426
                                        catch (Exception e)
427
                                        {
428
                                                e.printStackTrace();
429
                                        }
430
                                        
431
                                }
432
                        }
433
                } 
434

    
435
                
436
        }
437

    
438
        /**
439
         * @param jtsGeom
440
         * @param i
441
         */
442
        private void calculateConvexHull(Geometry jtsGeom, int i) {
443
                if (serviceAreaPolygons.size() <= i) { // se crea por primera vez
444
                        Geometry gIni = jtsGeom.convexHull(); 
445
                        serviceAreaPolygons.add(i, gIni);
446
                }
447
                else
448
                {
449
                        Geometry antG = serviceAreaPolygons.get(i);
450
                        if (antG == null)
451
                                antG = jtsGeom.convexHull();
452
                        else
453
                        {
454
                                antG = antG.union(jtsGeom.convexHull());                                
455
                        }
456
                        antG = antG.convexHull();
457
                        serviceAreaPolygons.set(i, antG);
458
                }
459
        }
460

    
461

    
462
        private void writePartialEdge(int i, LineString partial, GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, int idFlag, double maxCost) throws ProcessWriterVisitorException {
463
//                Geometry jtsGeom = geom.toJTSGeometry();
464
                double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
465
                if (edge.getDirec() == 0) // Sentido inverso
466
                        pct = 1-pct;
467
//                LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
468
//                if (serviceArea == null)
469
//                        serviceArea = partial;
470
//                else
471
//                {
472
//                        serviceArea = serviceArea.union(partial);
473
//                        serviceArea = serviceArea.convexHull();
474
//                }
475
                
476
                IGeometry newGeom = FConverter.jts_to_igeometry(partial);
477

    
478
                Value[] values = new Value[7];
479
                values[0] = ValueFactory.createValue(i);
480
                values[1] = ValueFactory.createValue(edge.getIdEdge());
481
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
482
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
483
                values[4] = ValueFactory.createValue(maxCost);
484
                values[5] = ValueFactory.createValue(nodeOrig.getAccumulatedLength() + edge.getDistance()*pct);
485
                values[6] = ValueFactory.createValue(idFlag);
486
                DefaultFeature feat = new DefaultFeature(newGeom, values);
487
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, i);
488
                shpWriter.process(row);
489
                
490
//                // TODO: TROZO DEL RESTO
491
//                int direc = 0;
492
//                pct = pct+0.02;
493
//                if (edge.getDirec() == 0)
494
//                {
495
//                        direc = 1;
496
//                        pct = pct - 0.04;
497
//                }
498
//                LineString partial2 = NetworkUtils.getPartialLineString(jtsGeom, pct, direc);                
499
//                IGeometry newGeom2 = FConverter.jts_to_igeometry(partial2);
500
//                values[6] = ValueFactory.createValue(-2);
501
//                DefaultFeature feat2 = new DefaultFeature(newGeom2, values);
502
//                IRowEdited row2 = new DefaultRowEdited(feat2, DefaultRowEdited.STATUS_ADDED, i);
503
//                shpWriter.process(row2);
504

    
505
                // before
506
                addUniqueNode(nodeOrig.getX(), nodeOrig.getY(), nodeOrig.getBestCost());
507
                // ON
508
                Coordinate cAux = null;
509
                if (edge.getDirec() == 0) // Sentido inverso
510
                        cAux = partial.getCoordinateN(0);
511
                else
512
                        cAux = partial.getCoordinateN(partial.getNumPoints()-1);
513
                addUniqueNode(cAux.x, cAux.y, maxCost);
514
                
515
                // after
516
                addUniqueNode(nodeEnd.getX(), nodeEnd.getY(), nodeEnd.getBestCost());
517
                
518
//                if (bDoCompactArea) {
519
//                        Coordinate cLimit = null;
520
//                        if (edge.getDirec() == 0) // Sentido inverso
521
//                                cLimit = partial.getCoordinateN(0);
522
//                        else
523
//                                cLimit = partial.getCoordinateN(partial.getNumPoints()-1);
524
//                        processCompact(cLimit.x, cLimit.y);
525
//                }
526
                
527
        }
528

    
529
        private void writePartialEdge2(int i, LineString jtsGeom, GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, int idFlag, double maxCost) throws ProcessWriterVisitorException {
530
                
531
                double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
532
                if (edge.getDirec() == 0) // Sentido inverso
533
                        pct = 1-pct;
534

    
535
                IGeometry newGeom = FConverter.jts_to_igeometry(jtsGeom);
536

    
537
                Value[] values = new Value[7];
538
                values[0] = ValueFactory.createValue(i);
539
                values[1] = ValueFactory.createValue(edge.getIdEdge());
540
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
541
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
542
                values[4] = ValueFactory.createValue(maxCost);
543
                values[5] = ValueFactory.createValue(nodeOrig.getAccumulatedLength() + edge.getDistance()*pct);
544
                values[6] = ValueFactory.createValue(idFlag);
545
                DefaultFeature feat = new DefaultFeature(newGeom, values);
546
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, i);
547
                shpWriter.process(row);
548
                
549

    
550
                // before
551
                addUniqueNode(nodeOrig.getX(), nodeOrig.getY(), nodeOrig.getBestCost());
552
                // ON
553
                Coordinate cAux = null;
554
                if (edge.getDirec() == 0) // Sentido inverso
555
                        cAux = jtsGeom.getCoordinateN(0);
556
                else
557
                        cAux = jtsGeom.getCoordinateN(jtsGeom.getNumPoints()-1);
558
                addUniqueNode(cAux.x, cAux.y, maxCost);
559
                
560
                // after
561
                addUniqueNode(nodeEnd.getX(), nodeEnd.getY(), nodeEnd.getBestCost());
562
                
563
                
564
        }
565

    
566
        private void addUniqueNode(double x, double y, double z) {
567
                Coordinate c = new Coordinate(x,y,z);
568
                if (!borderCoords.contains(c)) {
569
                        borderCoords.add(c);
570
                        if (borderCoords.size() == 2) {
571
                                Iterator<Coordinate> it = borderCoords.iterator();
572
                                int i=0;
573
                                Coordinate cAuxF1 = null;
574
                                Coordinate cAuxF2 = null;
575
                                while (it.hasNext()) {
576
                                        if (i==0)
577
                                                cAuxF1 = it.next();
578
                                        else
579
                                                cAuxF2 = it.next();
580
                                        i++;
581
                                }
582
                                fullExtent = new Rectangle2D.Double();
583
                                fullExtent.setFrameFromDiagonal(cAuxF1.x,cAuxF1.y, cAuxF2.x, cAuxF2.y);
584
                        }
585
                        else
586
                                if (fullExtent != null)
587
                                        fullExtent.add(new Point2D.Double(x,y));
588
                }
589
        }
590
        
591
        /**
592
         * FIXME: CHANGE THE NAME OF THIS METHOD. Now, it writes al nodes with cost < maxCost
593
         * @return
594
         * @throws BaseException
595
         */
596
        public FLyrVect getBorderPoints() throws BaseException {
597
                File fTempPoints = new File(tempDirectoryPath + "/borderPoints.shp");
598
                
599
                FieldDescription[] fieldsPoints = new FieldDescription[1];
600
                FieldDescription fieldDesc = new FieldDescription();
601
                fieldDesc.setFieldName("COST");
602
                fieldDesc.setFieldType(Types.DOUBLE);
603
                fieldDesc.setFieldLength(20);
604
                fieldDesc.setFieldDecimalCount(5);
605
                fieldsPoints[0] = fieldDesc;
606

    
607
                SHPLayerDefinition layerDef = new SHPLayerDefinition();
608
                layerDef.setFile(fTempPoints);
609
                layerDef.setName("BorderPoints");                
610
                layerDef.setFieldsDesc(fieldsPoints);
611
                layerDef.setShapeType(FShape.POINT);
612

    
613
                
614
                ShpWriter shpWriter = new ShpWriter();
615
                shpWriter.setFile(fTempPoints);
616
                shpWriter.initialize(layerDef);
617

    
618
                int i=0;
619
                shpWriter.preProcess();
620
                for (Iterator it = borderCoords.iterator(); it.hasNext();) {
621
                        Coordinate c = (Coordinate) it.next();
622
                        Value[] values = new Value[1];                        
623
                        values[0] = ValueFactory.createValue(c.z);
624
                        IGeometry geom = ShapeFactory.createPoint2D(c.x, c.y);
625
                        DefaultFeature feat = new DefaultFeature(geom, values);
626
                        IRowEdited row = new DefaultRowEdited(feat,
627
                                        DefaultRowEdited.STATUS_ADDED, i++);
628
                        shpWriter.process(row);
629
                        
630
                }
631
                shpWriter.postProcess();
632
                
633
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDef.getName(), "gvSIG shp driver", 
634
                                layerDef.getFile(), null);
635
                return lyr;
636

    
637
                
638
        }
639
        
640
        public void reset() {
641
                borderCoords.clear();
642
                visitedEdges.clear();
643
                serviceAreaPolygons.clear();
644
                triangulator = new OrbisGisTriangulator();
645
                tin = new TIN();
646
                fullExtent = null;
647
        }
648

    
649
//        private void processCompact(LineString partial) {
650
//                Coordinate cIni = partial.getCoordinateN(0);
651
//                Coordinate cEnd = partial.getCoordinateN(partial.getNumPoints()-1);
652
////                System.out.println("PARTIAL c1=" + cIni + " cEnd=" + cEnd);
653
//                processCompact(cIni.x, cIni.y);
654
//                processCompact(cEnd.x, cEnd.y);
655
//        }
656

    
657
        private void writeTotalEdge(int i, IGeometry geom, GvEdge edge,
658
                        GvNode nodeOrig, GvNode nodeEnd, int idFlag)
659
                        throws ProcessWriterVisitorException {
660
                
661
                Geometry jtsGeom = geom.toJTSGeometry();
662
                if (serviceArea == null)
663
                        serviceArea = jtsGeom;
664
                else
665
                {
666
                        serviceArea = serviceArea.union(jtsGeom);
667
                        serviceArea = serviceArea.convexHull();
668
                }
669

    
670
                
671
                Value[] values = new Value[7];
672
                values[0] = ValueFactory.createValue(i);
673
                values[1] = ValueFactory.createValue(edge.getIdEdge());
674
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
675
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
676
                values[4] = ValueFactory.createValue(nodeOrig.getBestCost() + edge.getWeight());
677
                values[5] = ValueFactory.createValue(nodeOrig.getAccumulatedLength() + edge.getDistance());
678
                values[6] = ValueFactory.createValue(idFlag);
679
                
680
                if (bDoCompactArea) {
681
                        // This code is necessary ONLY if you want to triangulate also with interior points
682
                        // (To draw a 3D view, for example.
683
                        // TODO: Use borderPoints in triangulation instead of "nodes"
684
                        // Origin
685
                        addUniqueNode(nodeOrig.getX(), nodeOrig.getY(), nodeOrig.getBestCost());
686
                        
687
                        // end
688
                        addUniqueNode(nodeEnd.getX(), nodeEnd.getY(), nodeEnd.getBestCost());
689
                        
690
//                        System.out.println(" c1=" + cIni + " cEnd=" + cEnd);
691
//                        processCompact(nodeOrig.getX(), nodeOrig.getY());
692
//                        processCompact(nodeEnd.getX(), nodeEnd.getY());
693
                }
694

    
695

    
696
                DefaultFeature feat = new DefaultFeature(geom, values);
697
                IRowEdited row = new DefaultRowEdited(feat,
698
                                DefaultRowEdited.STATUS_ADDED, i);
699
                shpWriter.process(row);
700
        }
701

    
702
//        private void processCompact(double x, double y) {
703
////                FPoint2D p = new FPoint2D(x,y);
704
//                Coordinate c = new Coordinate(x,y);
705
////                System.out.println("PARTIAL c1=" + cIni + " cEnd=" + cEnd);
706
//                if (!nodes.contains(c))
707
//                        nodes.add(c);
708
//                else
709
//                {
710
//                        System.out.print("Nodo ya contenido");
711
//                }
712
//                
713
//        }
714

    
715
        public boolean adjacentEdgeVisited(GvNode fromNode, GvEdge edge) {
716
                insertVisitedEdge(edge);
717
                
718
                return false;
719
        }
720

    
721
        /**
722
         * Si el coste m?nimo del edge > costemax, salimos del m?todo.
723
         * Miramos si edge est? ya en la lista.
724
         * Si no est?, lo a?adimos.
725
         * Si est?, hay que mirar el porcentaje recorrido sobre ese tramo.
726
         * Casos posibles:
727
         * EdgeA al 100 % => No se a?ade este.
728
         * EdgeA.percentCost < 1.0. 
729
         *                 Comprobamos el percent de el nuevo. Si entre los dos suman > 1.0
730
         *                 marcamos el antiguo al 1.0 para que se escriba el tramo completo.
731
         * 
732
         *                 Si no suman 1.0, hay que a?adir este nuevo Edge, con el porcentaje
733
         *                 correspondiente.
734
         * @param edge
735
         */
736
        private void insertVisitedEdge(GvEdge edge) {
737
                IGraph g = net.getGraph();
738
                GvNode n1 = g.getNodeByID(edge.getIdNodeOrig());
739
                GvNode n2 = g.getNodeByID(edge.getIdNodeEnd());
740
                double maxCost = costs[costs .length-1]*1.2;
741
                if (Math.min(n1.getBestCost(), n2.getBestCost()) > maxCost)
742
                        return; // edge outside service area.
743
                
744
                String key = "" + edge.getIdArc();
745
                if (!visitedEdges.containsKey(key))        
746
                {
747
                        // En el constructor calculamos el porcentaje recorrido y lo guardamos
748
                        visitedEdges.put(key, new VisitedEdge(edge));
749
//                        System.out.println("idEdge adjacent= " + edge.getIdEdge());
750
                }
751
                else
752
                {
753
                        // Recuperamos el visiteEdge que hab?amos metido y miramos sus porcentajes
754
                        // recorridos. Si entre los dos porcentajes NO suman m?s de uno, quiere decir
755
                        // que ah? se queda un tramo central al que no llegamos ni desde un lado ni
756
                        // desde el otro. Por eso guardamos cada trocito al que hemos llegado por separado, 
757
                        // uno con la clave idArc y otro con la clave IdArc_.
758
                        VisitedEdge edgeAnt = visitedEdges.get(key);
759
//                        GvEdge savedEdge = edgeAnt.getEdge();
760
                        if (edgeAnt.getPercentcost() == 1.0)
761
                                return; // Ya est? completo, no a?adimos nada.
762
                        
763
                        double percentCostCalculated = (maxCost - n1.getBestCost())/ edge.getWeight();
764
                        if ((percentCostCalculated + edgeAnt.getPercentcost()) >= 1.0)
765
                                edgeAnt.setPercentCost(1.0);
766
                        else
767
                        {
768
                                visitedEdges.put(key + "_", new VisitedEdge(edge));
769
                        }
770

    
771
                }
772
        }
773

    
774
        public boolean minimumCostNodeSelected(GvNode node) {
775
//                IGraph g = net.getGraph();
776
//                int idEdge = node.getFromLink();
777
//                if (idEdge == -1) 
778
//                        return false;
779
//                GvEdge edge = g.getEdgeByID(idEdge);
780
//                insertVisitedEdge(edge);
781
                return false; // true if we want to stop Dijkstra
782
        }
783

    
784
        public void setIdFlag(int idFlag) {
785
                this.idFlag = idFlag;
786
        }
787
        
788
        /**
789
         * Write edges and polygons associated with active flag and costs
790
         * @param costs
791
         * @throws BaseException
792
         */
793
        public void writeServiceArea() throws BaseException {
794
                Set<Map.Entry<String, VisitedEdge>> keySet = visitedEdges.entrySet();
795
                
796
                GvEdge edge;
797
                IGraph g = net.getGraph();
798
//                Integer idEdge;
799
                double maxCost = costs[costs .length-1];
800
                serviceAreaPolygons = new ArrayList<Geometry>(costs.length);
801
                for (int i=0; i < costs.length-1; i++)
802
                        serviceAreaPolygons.add(null);
803
                
804
                for (Map.Entry<String, VisitedEdge> entry : keySet) {
805
//                        idEdge = entry.getKey();
806
                        VisitedEdge visitedEdge = entry.getValue(); 
807
                        edge = visitedEdge.getEdge();
808
                        GvNode nodeEnd = g.getNodeByID(edge.getIdNodeEnd());
809
                        GvNode nodeOrig = g.getNodeByID(edge.getIdNodeOrig());
810
                        IGeometry geom;
811
                        try {
812
                                geom = adapter.getShape(edge.getIdArc());
813
                                FLyrVect lyr = net.getLayer();
814
                            if (lyr.getCoordTrans() != null) {
815
                                    if (!lyr.getProjection().getAbrev().equals(lyr.getMapContext().getViewPort().getProjection().getAbrev())){
816
                                            geom.reProject(lyr.getCoordTrans());
817
                                    }
818
                            }                        
819
                                
820
                                processEdgeForPolygon(edge, nodeOrig, nodeEnd, geom, costs);
821
//                                double costAux = nodeOrig.getBestCost() + edge.getWeight();
822
////                                if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
823
//                                {
824
//                                        if (visitedEdge.getPercentcost() == 1.0) {
825
//                                                // A ese tramo hemos llegado por completo
826
//                                                // Recuperamos su distancia y etiquetamos.
827
//                                                writeTotalEdge(edge.getIdArc(), geom, edge, nodeOrig, nodeEnd, idFlag);        
828
//                                        }
829
//                                        else
830
//                                        {
831
//                                                // El CASO EN EL QUE HAS LLEGADO POR LOS
832
//                                                // 2 LADOS PERO HAY UN TRAMO INALCANZABLE ENMEDIO SE
833
//                                                // SOLUCIONA EN writePartialEdge
834
//                                                if (nodeOrig.getBestCost() < maxCost) { // FIXME: Creo que este if no tiene sentido.
835
//                                                        // A ese tramo hemos llegado parcialmente 
836
//                                                        // Recuperamos su distancia y etiquetamos.
837
//                                                        writePartialEdge(edge.getIdArc(), geom, edge, nodeOrig, nodeEnd, idFlag, maxCost);        
838
//                                                        
839
//                                                }
840
//                                        } // else
841
//                                } // if nodeEnd > nodeOrig
842
                        
843
                        } catch (BaseException e) {
844
                                e.printStackTrace();
845
                                throw new RuntimeException(e);
846
                        }
847
                        
848
                } // for
849
                if (bDoCompactArea) {
850
                        addExteriorPoints();
851
                        calculateTriangulation();
852
                        getBorderPoints();
853
                }
854
                for (int j=serviceAreaPolygons.size()-1; j>=0; j--) {
855
                        Geometry jtsGeom = null;
856
                        if (bDoCompactArea) {
857
                                ContourCalculator contourCalculator = new ContourCalculator(tin);
858
                                Polygonizer pol = new Polygonizer();
859
                                pol.add(contourCalculator.getContour(costs[j]+0.1));
860
                                Collection<Polygon> polygons = pol.getPolygons();
861
                                Iterator<Polygon> it = polygons.iterator();
862
                                double maxArea = 0;
863
                                double area;
864
                                while (it.hasNext()) {
865
                                        Polygon auxPol = it.next();
866
                                        area = auxPol.getArea(); 
867
                                        if ( area > maxArea) {                                                
868
                                                jtsGeom = auxPol;
869
                                                maxArea = area;
870
                                        } // if
871
                                } // while
872
                                // TODO: Optimizar este pol?gono. Quitar bucles y comprobar smallSegments,
873
                                // insideLines y outsideLines
874
                                
875
                        }
876
                        else
877
                        {
878
                                jtsGeom = serviceAreaPolygons.get(j);
879
                        }
880
                        if (jtsGeom != null)
881
                                writePolygon(idFlag, costs[j], jtsGeom);
882
                }
883

    
884
                
885
        }
886

    
887
        /**
888
         * We add points from fullExtent to allow better contour calculations 
889
         */
890
        private void addExteriorPoints() {
891
                int numSteps = 30; // por ejemplo, 30 puntos por cada lado del rect?ngulo
892
                double stepX = fullExtent.width / numSteps;
893
                double stepY = fullExtent.height / numSteps;
894
                for (int i=0; i < numSteps; i++) {
895
                        double x = fullExtent.getMinX() + stepX*i;
896
                        double y = fullExtent.getMinY() + stepY*i;
897
                        
898
                        Coordinate cUp = new Coordinate(x, fullExtent.getMaxY() + 10.0, Double.MAX_VALUE);
899
                        Coordinate cDown = new Coordinate(x, fullExtent.getMinY() - 10.0, Double.MAX_VALUE);
900
                        Coordinate cLeft = new Coordinate(fullExtent.getMinX() - 10.0, y, Double.MAX_VALUE);
901
                        Coordinate cRight = new Coordinate(fullExtent.getMaxX() + 10.0, y, Double.MAX_VALUE);
902
                        
903
                        borderCoords.add(cUp);
904
                        borderCoords.add(cDown);
905
                        borderCoords.add(cLeft);
906
                        borderCoords.add(cRight);
907
                }
908
                
909
                
910
        }
911

    
912
        /**
913
         * @param d 
914
         * 
915
         */
916
        private void calculateTriangulation() {
917
                
918
                int numPoints = borderCoords.size();
919
            Iterator it = borderCoords.iterator();
920
            for (int i=0; i<numPoints; i++) {
921
                    Coordinate node = (Coordinate) it.next();
922
                    Vertex v = new Vertex(node.x, node.y, node.z);
923
                    triangulator.addVertex(v);
924
            }
925

    
926
            tin = triangulator.calculateTriangulation();
927
                System.out.println("Fin de trayecto. Num. tri?ngulos=" + tin.getTriangles().size());
928
                
929
                // ========= ONLY TO DEBUG
930
//                for (int i=0; i< tin.getTriangles().size(); i++) {
931
//                      try {
932
//                                writeTri(tin.getTriangles().get(i));
933
//                        } catch (ProcessWriterVisitorException e) {
934
//                                // TODO Auto-generated catch block
935
//                                e.printStackTrace();
936
//                        }
937
//            }
938
                // ==========
939

    
940
                
941
        }
942
        private void writeTri(Triangle t) throws ProcessWriterVisitorException {
943
                Value[] values = new Value[2];
944
                values[0] = ValueFactory.createValue(2.0);
945
                values[1] = ValueFactory.createValue(1);
946
                
947
                Coordinate c1 = new Coordinate(t.getV1().getX(), t.getV1().getY());
948
                Coordinate c2 = new Coordinate(t.getV2().getX(), t.getV2().getY());
949
                Coordinate c3 = new Coordinate(t.getV3().getX(), t.getV3().getY());
950
                Coordinate[] c = new Coordinate[4];
951
                c[0] = c1;
952
                c[1] = c3;
953
                c[2] = c2;
954
                c[3] = c1;
955
                LinearRing linRing = null;
956
                if (CGAlgorithms.isCCW(c))
957
                {
958
                        Coordinate[] ccw = new Coordinate[4];
959
                        ccw[0] = c1;
960
                        ccw[1] = c2;
961
                        ccw[2] = c3;
962
                        ccw[3] = c1;
963
                        linRing = gf.createLinearRing(ccw);
964
                }
965
                else
966
                {
967
                        linRing = gf.createLinearRing(c);
968
//                        return;
969
                }
970
                 
971
                Polygon pol = gf.createPolygon(linRing, null);
972
                
973
                IGeometry geom = FConverter.jts_to_igeometry(pol);
974
                DefaultFeature feat = new DefaultFeature(geom, values);
975
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, idFlag);
976
//                shpWriterPol.process(row);
977
//                shpWriterTri.process(row);
978
                
979
        }
980

    
981
        private void writePolygon(int idFlag, double maxCost, Geometry jtsGeom) throws ProcessWriterVisitorException {
982
                Value[] values = new Value[2];
983
                values[0] = ValueFactory.createValue(maxCost);
984
                values[1] = ValueFactory.createValue(idFlag);
985
                
986
                IGeometry geom = FConverter.jts_to_igeometry(jtsGeom);
987
                DefaultFeature feat = new DefaultFeature(geom, values);
988
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, idFlag);
989
                shpWriterPol.process(row);
990
        }
991

    
992
        /**
993
         * Close writers.
994
         * @throws BaseException
995
         */
996
        public void closeFiles() throws BaseException {
997
//                for (int j=serviceAreaPolygons.size()-1; j>=0; j--) {
998
//                        Geometry jtsGeom = serviceAreaPolygons.get(j);
999
//                        writePolygon(idFlag, costs[j], jtsGeom);
1000
//                }
1001

    
1002
                shpWriter.postProcess();
1003
                shpWriterPol.postProcess();
1004
//                shpWriterTri.postProcess();
1005
                
1006
                adapter.stop();
1007
                
1008
                
1009

    
1010
        }
1011
        public double[] getCosts() {
1012
                return costs;
1013
        }
1014

    
1015
        public void setCosts(double[] costs) {
1016
                this.costs = costs;
1017
        }
1018

    
1019
        public FLyrVect getPolygonLayer() throws LoadLayerException {
1020
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDefPol.getName(), "gvSIG shp driver", 
1021
                                layerDefPol.getFile(), null);
1022
                return lyr;
1023
        }
1024

    
1025
        public FLyrVect getLineLayer() throws LoadLayerException {
1026
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDef.getName(), "gvSIG shp driver", 
1027
                                layerDef.getFile(), null);
1028
                return lyr;
1029
        }
1030

    
1031
        public boolean isDoCompactArea() {
1032
                return bDoCompactArea;
1033
        }
1034

    
1035
        public void setDoCompactArea(boolean doCompactArea) {
1036
                bDoCompactArea = doCompactArea;
1037
        }
1038

    
1039
        public void setDistances(double[] distances) {
1040
                this.distances = distances;
1041
        }
1042

    
1043
}