Statistics
| Revision:

root / trunk / extensions / extGraph / src / org / gvsig / graph / solvers / ServiceAreaExtractor2.java @ 31875

History | View | Annotate | Download (33.2 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.Hashtable;
55
import java.util.Iterator;
56
import java.util.Map;
57
import java.util.Set;
58

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

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

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

    
124
        static FieldDescription[] fields = new FieldDescription[7];
125
        static {
126
                FieldDescription fieldDesc = new FieldDescription();
127
                fieldDesc.setFieldName("IDARC");
128
                fieldDesc.setFieldType(Types.INTEGER);
129
                fieldDesc.setFieldLength(20);
130
                fieldDesc.setFieldDecimalCount(0);
131
                fields[0] = fieldDesc;
132

    
133
                fieldDesc = new FieldDescription();
134
                fieldDesc.setFieldName("IDEDGE");
135
                fieldDesc.setFieldType(Types.INTEGER);
136
                fieldDesc.setFieldLength(20);
137
                fieldDesc.setFieldDecimalCount(0);
138
                fields[1] = fieldDesc;
139

    
140
                fieldDesc = new FieldDescription();
141
                fieldDesc.setFieldName("COSTORIG");
142
                fieldDesc.setFieldType(Types.DOUBLE);
143
                fieldDesc.setFieldLength(20);
144
                fieldDesc.setFieldDecimalCount(5);
145
                fields[2] = fieldDesc;
146

    
147
                fieldDesc = new FieldDescription();
148
                fieldDesc.setFieldName("DISTORIG");
149
                fieldDesc.setFieldType(Types.DOUBLE);
150
                fieldDesc.setFieldLength(20);
151
                fieldDesc.setFieldDecimalCount(5);
152
                fields[3] = fieldDesc;
153

    
154
                fieldDesc = new FieldDescription();
155
                fieldDesc.setFieldName("COSTEND");
156
                fieldDesc.setFieldType(Types.DOUBLE);
157
                fieldDesc.setFieldLength(20);
158
                fieldDesc.setFieldDecimalCount(5);
159
                fields[4] = fieldDesc;
160

    
161
                fieldDesc = new FieldDescription();
162
                fieldDesc.setFieldName("DISTEND");
163
                fieldDesc.setFieldType(Types.DOUBLE);
164
                fieldDesc.setFieldLength(20);
165
                fieldDesc.setFieldDecimalCount(5);
166
                fields[5] = fieldDesc;
167

    
168
                fieldDesc = new FieldDescription();
169
                fieldDesc.setFieldName("IDFLAG");
170
                fieldDesc.setFieldType(Types.INTEGER);
171
                fieldDesc.setFieldLength(20);
172
                fieldDesc.setFieldDecimalCount(5);
173
                fields[6] = fieldDesc;
174

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

    
193
        }
194
        
195
        static GeometryFactory gf = new GeometryFactory();
196

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

    
228
        private Network net;
229

    
230
        private ShpWriter shpWriter;
231
        private ShpWriter shpWriterPol;
232
//        private ShpWriter shpWriterTri;
233
        private File fTempPol;
234
        private File fTempTri;
235
        private SHPLayerDefinition layerDefPol;
236
        private SHPLayerDefinition layerDefTri;
237
        
238
        
239
        private HashMap<String, VisitedEdge> visitedEdges = new HashMap();
240

    
241
        private File fTemp;
242

    
243
        private SHPLayerDefinition layerDef;
244

    
245
        private int idFlag;
246

    
247
        private ReadableVectorial adapter;
248

    
249
//        private double maxCost;
250

    
251
        private Geometry serviceArea;
252
        private ArrayList <Geometry> serviceAreaPolygons;
253
        
254
//        private Hashtable<Integer, EdgePair> smallSegments = new Hashtable();
255

    
256
        private double[] costs = null;        
257
        
258
        private boolean bDoCompactArea = false;
259
        
260
        private HashSet<Coordinate> borderCoords = new HashSet<Coordinate>();
261

    
262
//        private HashSet<Coordinate> nodes;
263
//        DelaunayFast tri2;
264
//        DelaunayWatson tri2;
265
//        PirolTriangulator triangulator = new PirolTriangulator();
266
//        Triangulator triangulator = new WatsonTriangulator();
267
        Triangulator triangulator = new OrbisGisTriangulator();
268

    
269
        private TIN tin;
270

    
271
        private Rectangle2D.Double fullExtent = null;
272

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

    
300
                layerDefPol = new SHPLayerDefinition();
301
                layerDefPol.setFile(fTempPol);
302
                layerDefPol.setName(namePol);                
303
                layerDefPol.setFieldsDesc(fieldsPol);
304
                layerDefPol.setShapeType(FShape.POLYGON);
305

    
306
                layerDefTri = new SHPLayerDefinition();
307
                layerDefTri.setFile(fTempTri);
308
                layerDefTri.setName(nameTri);                
309
                layerDefTri.setFieldsDesc(fieldsPol);
310
                layerDefTri.setShapeType(FShape.POLYGON);
311
                
312
                shpWriter = new ShpWriter();
313
                shpWriter.setFile(fTemp);
314
                shpWriter.initialize(layerDef);
315

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

    
335
        }
336

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

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

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

    
439
                
440
        }
441

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

    
465

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

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

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

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

    
539
                IGeometry newGeom = FConverter.jts_to_igeometry(jtsGeom);
540

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

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

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

    
611
                SHPLayerDefinition layerDef = new SHPLayerDefinition();
612
                layerDef.setFile(fTempPoints);
613
                layerDef.setName("BorderPoints");                
614
                layerDef.setFieldsDesc(fieldsPoints);
615
                layerDef.setShapeType(FShape.POINT);
616

    
617
                
618
                ShpWriter shpWriter = new ShpWriter();
619
                shpWriter.setFile(fTempPoints);
620
                shpWriter.initialize(layerDef);
621

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

    
641
                
642
        }
643
        
644
        public void reset() {
645
                borderCoords.clear();
646
                visitedEdges.clear();
647
                serviceAreaPolygons.clear();
648
                triangulator = new OrbisGisTriangulator();
649
                tin = new TIN();
650
                fullExtent = null;
651
        }
652

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

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

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

    
699

    
700
                DefaultFeature feat = new DefaultFeature(geom, values);
701
                IRowEdited row = new DefaultRowEdited(feat,
702
                                DefaultRowEdited.STATUS_ADDED, i);
703
                shpWriter.process(row);
704
        }
705

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

    
719
        public boolean adjacentEdgeVisited(GvNode fromNode, GvEdge edge) {
720
                insertVisitedEdge(edge);
721
                
722
                return false;
723
        }
724

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

    
775
                }
776
        }
777

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

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

    
888
                
889
        }
890

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

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

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

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

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

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

    
1006
                shpWriter.postProcess();
1007
                shpWriterPol.postProcess();
1008
//                shpWriterTri.postProcess();
1009
                
1010
                adapter.stop();
1011
                
1012
                
1013

    
1014
        }
1015
        public double[] getCosts() {
1016
                return costs;
1017
        }
1018

    
1019
        public void setCosts(double[] costs) {
1020
                this.costs = costs;
1021
        }
1022

    
1023
        public FLyrVect getPolygonLayer() throws LoadLayerException {
1024
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDefPol.getName(), "gvSIG shp driver", 
1025
                                layerDefPol.getFile(), null);
1026
                return lyr;
1027
        }
1028

    
1029
        public FLyrVect getLineLayer() throws LoadLayerException {
1030
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDef.getName(), "gvSIG shp driver", 
1031
                                layerDef.getFile(), null);
1032
                return lyr;
1033
        }
1034

    
1035
        public boolean isDoCompactArea() {
1036
                return bDoCompactArea;
1037
        }
1038

    
1039
        public void setDoCompactArea(boolean doCompactArea) {
1040
                bDoCompactArea = doCompactArea;
1041
        }
1042

    
1043
        public void setDistances(double[] distances) {
1044
                this.distances = distances;
1045
        }
1046

    
1047
}