Statistics
| Revision:

root / trunk / extensions / extGraph / src / com / iver / cit / gvsig / graph / solvers / ServiceAreaExtractor2.java @ 15509

History | View | Annotate | Download (16.3 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 com.iver.cit.gvsig.graph.solvers;
45

    
46
import java.io.File;
47
import java.sql.Types;
48
import java.util.ArrayList;
49
import java.util.HashMap;
50
import java.util.Map;
51
import java.util.Set;
52

    
53
import org.apache.commons.collections.set.CompositeSet.SetMutator;
54
import org.gvsig.exceptions.BaseException;
55

    
56
import com.hardcode.gdbms.driver.exceptions.InitializeDriverException;
57
import com.hardcode.gdbms.driver.exceptions.InitializeWriterException;
58
import com.hardcode.gdbms.driver.exceptions.ReadDriverException;
59
import com.hardcode.gdbms.engine.values.Value;
60
import com.hardcode.gdbms.engine.values.ValueFactory;
61
import com.iver.cit.gvsig.exceptions.expansionfile.ExpansionFileReadException;
62
import com.iver.cit.gvsig.exceptions.layers.LoadLayerException;
63
import com.iver.cit.gvsig.exceptions.visitors.ProcessWriterVisitorException;
64
import com.iver.cit.gvsig.exceptions.visitors.StopWriterVisitorException;
65
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
66
import com.iver.cit.gvsig.fmap.core.FShape;
67
import com.iver.cit.gvsig.fmap.core.IGeometry;
68
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
69
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
70
import com.iver.cit.gvsig.fmap.drivers.LayerDefinition;
71
import com.iver.cit.gvsig.fmap.drivers.SHPLayerDefinition;
72
import com.iver.cit.gvsig.fmap.edition.DefaultRowEdited;
73
import com.iver.cit.gvsig.fmap.edition.IRowEdited;
74
import com.iver.cit.gvsig.fmap.edition.writers.shp.ShpWriter;
75
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
76
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
77
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
78
import com.iver.cit.gvsig.graph.NetworkUtils;
79
import com.iver.cit.gvsig.graph.core.EdgePair;
80
import com.iver.cit.gvsig.graph.core.GvEdge;
81
import com.iver.cit.gvsig.graph.core.GvNode;
82
import com.iver.cit.gvsig.graph.core.IGraph;
83
import com.iver.cit.gvsig.graph.core.Network;
84
import com.vividsolutions.jts.geom.Geometry;
85
import com.vividsolutions.jts.geom.LineString;
86

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

    
106
        static FieldDescription[] fields = new FieldDescription[7];
107
        static {
108
                FieldDescription fieldDesc = new FieldDescription();
109
                fieldDesc.setFieldName("IDARC");
110
                fieldDesc.setFieldType(Types.INTEGER);
111
                fieldDesc.setFieldLength(20);
112
                fieldDesc.setFieldDecimalCount(0);
113
                fields[0] = fieldDesc;
114

    
115
                fieldDesc = new FieldDescription();
116
                fieldDesc.setFieldName("IDEDGE");
117
                fieldDesc.setFieldType(Types.INTEGER);
118
                fieldDesc.setFieldLength(20);
119
                fieldDesc.setFieldDecimalCount(0);
120
                fields[1] = fieldDesc;
121

    
122
                fieldDesc = new FieldDescription();
123
                fieldDesc.setFieldName("COSTORIG");
124
                fieldDesc.setFieldType(Types.DOUBLE);
125
                fieldDesc.setFieldLength(20);
126
                fieldDesc.setFieldDecimalCount(5);
127
                fields[2] = fieldDesc;
128

    
129
                fieldDesc = new FieldDescription();
130
                fieldDesc.setFieldName("DISTORIG");
131
                fieldDesc.setFieldType(Types.DOUBLE);
132
                fieldDesc.setFieldLength(20);
133
                fieldDesc.setFieldDecimalCount(5);
134
                fields[3] = fieldDesc;
135

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

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

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

    
157
        }
158
        
159
        static FieldDescription[] fieldsPol = new FieldDescription[2];
160
        static {
161
                FieldDescription fieldDesc = new FieldDescription();
162
                fieldDesc.setFieldName("COST");
163
                fieldDesc.setFieldType(Types.DOUBLE);
164
                fieldDesc.setFieldLength(20);
165
                fieldDesc.setFieldDecimalCount(5);
166
                fieldsPol[0] = fieldDesc;
167
                
168
                fieldDesc = new FieldDescription();
169
                fieldDesc.setFieldName("IDFLAG");
170
                fieldDesc.setFieldType(Types.INTEGER);
171
                fieldDesc.setFieldLength(20);
172
                fieldDesc.setFieldDecimalCount(5);
173
                fieldsPol[1] = fieldDesc;
174

    
175
        }
176

    
177

    
178
        private Network net;
179

    
180
        private ShpWriter shpWriter;
181
        private ShpWriter shpWriterPol;
182
        private File fTempPol;
183
        private SHPLayerDefinition layerDefPol;
184
        
185
        
186
        private HashMap<Integer, GvEdge> visitedEdges = new HashMap();
187

    
188
        private File fTemp;
189

    
190
        private SHPLayerDefinition layerDef;
191

    
192
        private int idFlag;
193

    
194
        private ReadableVectorial adapter;
195

    
196
//        private double maxCost;
197

    
198
        private Geometry serviceArea;
199
        private ArrayList <Geometry> serviceAreaPolygons;
200

    
201
        private double[] costs = null;        
202

    
203
        /**
204
         * @param net
205
         * @throws InitializeWriterException
206
         * @throws ReadDriverException
207
         * @throws InitializeDriverException
208
         */
209
        public ServiceAreaExtractor2(Network net) throws BaseException {
210
                this.net = net;
211
                int aux = (int) (Math.random() * 1000);
212
                
213
                
214
                String nameLine = "tmpServiceAreaLine" + aux + ".shp";
215
                String namePol = "tmpServiceAreaPol" + aux + ".shp";
216
                fTemp = new File(tempDirectoryPath + "/" + nameLine );
217
                fTempPol = new File(tempDirectoryPath + "/" + namePol );
218
                
219
                layerDef = new SHPLayerDefinition();
220
                layerDef.setFile(fTemp);
221
                layerDef.setName(nameLine);                
222
                layerDef.setFieldsDesc(fields);
223
                layerDef.setShapeType(FShape.LINE);
224

    
225
                layerDefPol = new SHPLayerDefinition();
226
                layerDefPol.setFile(fTempPol);
227
                layerDefPol.setName(namePol);                
228
                layerDefPol.setFieldsDesc(fieldsPol);
229
                layerDefPol.setShapeType(FShape.POLYGON);
230
                
231
                shpWriter = new ShpWriter();
232
                shpWriter.setFile(fTemp);
233
                shpWriter.initialize(layerDef);
234

    
235
                shpWriterPol = new ShpWriter();
236
                shpWriterPol.setFile(fTempPol);
237
                shpWriterPol.initialize(layerDefPol);
238
                shpWriter.preProcess();
239
                shpWriterPol.preProcess();
240
                FLyrVect lyr = net.getLayer();
241
                adapter = lyr.getSource();
242
                adapter.start();
243
                
244
                serviceAreaPolygons = new ArrayList<Geometry>();
245

    
246
        }
247

    
248
        /**
249
         * Devuelve el ?ndice del intervalo m?s alto que contiene a ese valor.
250
         * @param bestCost
251
         * @param costs
252
         * @return
253
         */
254
        private int getCostInterval(double bestCost, double[] costs) {
255
                int ret = 0;
256
                if (bestCost > costs[costs.length-1])
257
                        return -1;
258
                for (int i=costs.length-1; i>=0; i--) {
259
                        if (bestCost > costs[i])
260
                        {
261
                                ret = i+1;
262
                                break;
263
                        }
264
                }
265
                return ret;
266
        }
267

    
268
        /**
269
         * We process each edge and prepare a list of polygons, classified by
270
         * cost
271
         * @param edge
272
         * @param nodeOrig
273
         * @param nodeEnd
274
         * @param geom
275
         * @param costs
276
         */
277
        private void processEdgeForPolygon(GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, IGeometry geom, double[] costs) {
278
                if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
279
                {                
280
                        // miramos en qu? pol?gono cae ese edge POR COMPLETO 
281
                        // El coste de su punto final es menor que uno de los costes.
282
                        int indexInterval = getCostInterval(nodeEnd.getBestCost(), costs);
283
                        // Un pol?gono por cada zona
284
                        Geometry jtsGeom = geom.toJTSGeometry();
285
                        if (indexInterval != -1)
286
                        {
287
                                for (int i=costs.length-1; i >= indexInterval; i--) {
288
                                        calculateConvexHull(jtsGeom, i);
289
                                }
290
                        }
291
                        double maxCost = costs[costs.length-1];
292
                        // Es -1 si caso l?mite externo
293
                        if (indexInterval < costs.length-1)
294
                        {
295
                                // Caso l?mite externo
296
                                if ((nodeEnd.getBestCost() > maxCost) &&                                                
297
                                                (nodeOrig.getBestCost() < maxCost))
298
                                {
299
                                        double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
300
                                        LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
301
                                        calculateConvexHull(partial, costs.length-1);
302
                                        return;
303
                                }
304
                                // Parcial interno
305
                                maxCost = costs[indexInterval+1];
306
                                if ((nodeOrig.getBestCost() < maxCost) &&
307
                                                (nodeEnd.getBestCost() > maxCost)) 
308
                                {
309
                                        // A ese tramo hemos llegado parcialmente
310
                                         
311
                                        double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
312
                                        try {
313
                                                LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
314
                                                calculateConvexHull(partial, indexInterval+1);                                                        
315
                                        }
316
                                        catch (Exception e)
317
                                        {
318
                                                e.printStackTrace();
319
                                        }
320
                                        
321
                                }
322
                        }
323
                } 
324

    
325
                
326
        }
327

    
328
        /**
329
         * @param jtsGeom
330
         * @param i
331
         */
332
        private void calculateConvexHull(Geometry jtsGeom, int i) {
333
                if (serviceAreaPolygons.size() <= i) { // se crea por primera vez
334
                        Geometry gIni = jtsGeom; 
335
                        serviceAreaPolygons.add(i, gIni);
336
                }
337
                else
338
                {
339
                        Geometry antG = serviceAreaPolygons.get(i);
340
                        if (antG == null)
341
                                antG = jtsGeom;
342
                        else
343
                        {
344
                                antG = antG.union(jtsGeom);                                
345
                        }
346
                        antG = antG.convexHull();
347
                        serviceAreaPolygons.set(i, antG);
348
                }
349
        }
350

    
351

    
352
        private void writePartialEdge(int i, IGeometry geom, GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, int idFlag, double maxCost) throws ProcessWriterVisitorException {
353
                Geometry jtsGeom = geom.toJTSGeometry();
354
                double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
355
                LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
356
                if (serviceArea == null)
357
                        serviceArea = partial;
358
                else
359
                {
360
                        serviceArea = serviceArea.union(partial);
361
                        serviceArea = serviceArea.convexHull();
362
                }
363
                
364
                IGeometry newGeom = FConverter.jts_to_igeometry(partial);
365

    
366
                Value[] values = new Value[7];
367
                values[0] = ValueFactory.createValue(i);
368
                values[1] = ValueFactory.createValue(edge.getIdEdge());
369
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
370
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
371
                values[4] = ValueFactory.createValue(maxCost);
372
                values[5] = ValueFactory.createValue(nodeOrig.getAccumulatedLength() + edge.getDistance()*pct);
373
                values[6] = ValueFactory.createValue(idFlag);
374
                
375
                
376
                DefaultFeature feat = new DefaultFeature(newGeom, values);
377
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, i);
378
                shpWriter.process(row);
379
                
380
        }
381

    
382
        private void writeTotalEdge(int i, IGeometry geom, GvEdge edge,
383
                        GvNode nodeOrig, GvNode nodeEnd, int idFlag)
384
                        throws ProcessWriterVisitorException {
385
                Value[] values = new Value[7];
386
                values[0] = ValueFactory.createValue(i);
387
                values[1] = ValueFactory.createValue(edge.getIdEdge());
388
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
389
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
390
                values[4] = ValueFactory.createValue(nodeEnd.getBestCost());
391
                values[5] = ValueFactory.createValue(nodeEnd.getAccumulatedLength());
392
                values[6] = ValueFactory.createValue(idFlag);
393

    
394
                DefaultFeature feat = new DefaultFeature(geom, values);
395
                IRowEdited row = new DefaultRowEdited(feat,
396
                                DefaultRowEdited.STATUS_ADDED, i);
397
                shpWriter.process(row);
398
        }
399

    
400
        public boolean adjacentEdgeVisited(GvNode fromNode, GvEdge edge) {
401
                visitedEdges.put(edge.getIdEdge(), edge);
402
                
403
                return false;
404
        }
405

    
406
        public boolean minimumCostNodeSelected(GvNode node) {
407
                IGraph g = net.getGraph();
408
                int idEdge = node.getFromLink();
409
                if (idEdge == -1) 
410
                        return false;
411
                GvEdge edge = g.getEdgeByID(idEdge);
412
                visitedEdges.put(edge.getIdEdge(), edge);
413

    
414
                return false; // true if we want to stop Dijkstra
415
        }
416

    
417
        public int getIdFlag() {
418
                return idFlag;
419
        }
420

    
421
        public void setIdFlag(int idFlag) {
422
                this.idFlag = idFlag;
423
        }
424
        
425
        /**
426
         * Write edges and polygons associated with active flag and costs
427
         * @param costs
428
         * @throws BaseException
429
         */
430
        public void writeServiceArea() throws BaseException {
431
                Set<Map.Entry<Integer, GvEdge>> keySet = visitedEdges.entrySet();
432
                
433
                GvEdge edge;
434
                IGraph g = net.getGraph();
435
//                Integer idEdge;
436
                double maxCost = costs[costs .length-1];
437
                serviceAreaPolygons = new ArrayList<Geometry>(costs.length);
438
                for (int i=0; i < costs.length-1; i++)
439
                        serviceAreaPolygons.add(null);
440
                
441
                for (Map.Entry<Integer, GvEdge> entry : keySet) {
442
//                        idEdge = entry.getKey();
443
                        edge = entry.getValue();
444
                        GvNode nodeEnd = g.getNodeByID(edge.getIdNodeEnd());
445
                        GvNode nodeOrig = g.getNodeByID(edge.getIdNodeOrig());
446
                        IGeometry geom;
447
                        try {
448
                                geom = adapter.getShape(edge.getIdArc());
449
                                processEdgeForPolygon(edge, nodeOrig, nodeEnd, geom, costs);
450
                                if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
451
                                {
452
                                        if (nodeEnd.getBestCost() < maxCost) {
453
                                                // A ese tramo hemos llegado por completo
454
                                                // Recuperamos su distancia y etiquetamos.
455
                                                writeTotalEdge(edge.getIdArc(), geom, edge, nodeOrig, nodeEnd, idFlag);        
456
                                        }
457
                                        else
458
                                        {
459
                                                if (nodeOrig.getBestCost() < maxCost) {
460
                                                        // A ese tramo hemos llegado parcialmente
461
                                                        // Recuperamos su distancia y etiquetamos.
462
                                                        writePartialEdge(edge.getIdArc(), geom, edge, nodeOrig, nodeEnd, idFlag, maxCost);        
463
                                                        
464
                                                }
465
                                        } // else
466
                                } // if nodeEnd > nodeOrig
467
                        
468
                        } catch (BaseException e) {
469
                                e.printStackTrace();
470
                                throw new RuntimeException(e);
471
                        }
472
                        
473
                } // for
474
                for (int j=serviceAreaPolygons.size()-1; j>=0; j--) {
475
                        Geometry jtsGeom = serviceAreaPolygons.get(j);
476
                        writePolygon(idFlag, costs[j], jtsGeom);
477
                }
478

    
479
                
480
        }
481

    
482
        private void writePolygon(int idFlag, double maxCost, Geometry jtsGeom) throws ProcessWriterVisitorException {
483
                Value[] values = new Value[2];
484
                values[0] = ValueFactory.createValue(maxCost);
485
                values[1] = ValueFactory.createValue(idFlag);
486
                
487
                IGeometry geom = FConverter.jts_to_igeometry(jtsGeom);
488
                DefaultFeature feat = new DefaultFeature(geom, values);
489
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, idFlag);
490
                shpWriterPol.process(row);
491
        }
492

    
493
        /**
494
         * Close writers.
495
         * @throws BaseException
496
         */
497
        public void closeFiles() throws BaseException {
498
                for (int j=serviceAreaPolygons.size()-1; j>=0; j--) {
499
                        Geometry jtsGeom = serviceAreaPolygons.get(j);
500
                        writePolygon(idFlag, costs[j], jtsGeom);
501
                }
502

    
503
                shpWriter.postProcess();
504
                shpWriterPol.postProcess();
505
                
506
                adapter.stop();
507
                
508
                
509

    
510
        }
511
        public double[] getCosts() {
512
                return costs;
513
        }
514

    
515
        public void setCosts(double[] costs) {
516
                this.costs = costs;
517
        }
518

    
519
        public FLyrVect getPolygonLayer() throws LoadLayerException {
520
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDefPol.getName(), "gvSIG shp driver", 
521
                                layerDefPol.getFile(), null);
522
                return lyr;
523
        }
524

    
525
        public FLyrVect getLineLayer() throws LoadLayerException {
526
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDef.getName(), "gvSIG shp driver", 
527
                                layerDef.getFile(), null);
528
                return lyr;
529
        }
530

    
531
}