Statistics
| Revision:

root / trunk / extensions / extGraph / src / org / gvsig / graph / solvers / ServiceAreaExtractor.java @ 39203

History | View | Annotate | Download (14.9 KB)

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

    
42
// 18/09/2007 fjp
43
// @author: Fco. Jos? Pe?arrubia        fpenarru@gmail.com
44

    
45
package org.gvsig.graph.solvers;
46

    
47
import java.io.File;
48
import java.sql.Types;
49
import java.util.ArrayList;
50

    
51
import org.gvsig.exceptions.BaseException;
52
import org.gvsig.graph.core.EdgePair;
53
import org.gvsig.graph.core.GvEdge;
54
import org.gvsig.graph.core.GvNode;
55
import org.gvsig.graph.core.IGraph;
56
import org.gvsig.graph.core.Network;
57
import org.gvsig.graph.core.NetworkUtils;
58

    
59
import com.hardcode.gdbms.engine.values.Value;
60
import com.hardcode.gdbms.engine.values.ValueFactory;
61
import com.iver.cit.gvsig.exceptions.layers.LoadLayerException;
62
import com.iver.cit.gvsig.exceptions.visitors.ProcessWriterVisitorException;
63
import com.iver.cit.gvsig.fmap.core.DefaultFeature;
64
import com.iver.cit.gvsig.fmap.core.FShape;
65
import com.iver.cit.gvsig.fmap.core.IGeometry;
66
import com.iver.cit.gvsig.fmap.core.v02.FConverter;
67
import com.iver.cit.gvsig.fmap.drivers.FieldDescription;
68
import com.iver.cit.gvsig.fmap.drivers.SHPLayerDefinition;
69
import com.iver.cit.gvsig.fmap.edition.DefaultRowEdited;
70
import com.iver.cit.gvsig.fmap.edition.IRowEdited;
71
import com.iver.cit.gvsig.fmap.edition.writers.shp.ShpWriter;
72
import com.iver.cit.gvsig.fmap.layers.FLyrVect;
73
import com.iver.cit.gvsig.fmap.layers.LayerFactory;
74
import com.iver.cit.gvsig.fmap.layers.ReadableVectorial;
75
import com.vividsolutions.jts.geom.Geometry;
76
import com.vividsolutions.jts.geom.LineString;
77

    
78
/**
79
 * @author fjp
80
 * 
81
 * This class can label nodes with distances and costs to a flag
82
 * Use first doLabelling() with every source flag and call
83
 * doExtract() to obtain a new layer with fields
84
 * IdArc, IdEdge, CostOrig, DistOrig, CostEnd, DistEnd, IdFlag 
85
 *
86
 */
87
public class ServiceAreaExtractor {
88
        private static String tempDirectoryPath = System.getProperty("java.io.tmpdir");
89
        static FieldDescription[] fields = new FieldDescription[7];
90
        static {
91
                FieldDescription fieldDesc = new FieldDescription();
92
                fieldDesc.setFieldName("IDARC");
93
                fieldDesc.setFieldType(Types.INTEGER);
94
                fieldDesc.setFieldLength(20);
95
                fieldDesc.setFieldDecimalCount(0);
96
                fields[0] = fieldDesc;
97

    
98
                fieldDesc = new FieldDescription();
99
                fieldDesc.setFieldName("IDEDGE");
100
                fieldDesc.setFieldType(Types.INTEGER);
101
                fieldDesc.setFieldLength(20);
102
                fieldDesc.setFieldDecimalCount(0);
103
                fields[1] = fieldDesc;
104

    
105
                fieldDesc = new FieldDescription();
106
                fieldDesc.setFieldName("COSTORIG");
107
                fieldDesc.setFieldType(Types.DOUBLE);
108
                fieldDesc.setFieldLength(20);
109
                fieldDesc.setFieldDecimalCount(5);
110
                fields[2] = fieldDesc;
111
                
112
                fieldDesc = new FieldDescription();
113
                fieldDesc.setFieldName("DISTORIG");
114
                fieldDesc.setFieldType(Types.DOUBLE);
115
                fieldDesc.setFieldLength(20);
116
                fieldDesc.setFieldDecimalCount(5);
117
                fields[3] = fieldDesc;
118

    
119
                fieldDesc = new FieldDescription();
120
                fieldDesc.setFieldName("COSTEND");
121
                fieldDesc.setFieldType(Types.DOUBLE);
122
                fieldDesc.setFieldLength(20);
123
                fieldDesc.setFieldDecimalCount(5);
124
                fields[4] = fieldDesc;
125

    
126
                fieldDesc = new FieldDescription();
127
                fieldDesc.setFieldName("DISTEND");
128
                fieldDesc.setFieldType(Types.DOUBLE);
129
                fieldDesc.setFieldLength(20);
130
                fieldDesc.setFieldDecimalCount(5);
131
                fields[5] = fieldDesc;
132

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

    
140
        }
141
        static FieldDescription[] fieldsPol = new FieldDescription[2];
142
        static {
143
                FieldDescription fieldDesc = new FieldDescription();
144
                fieldDesc.setFieldName("COST");
145
                fieldDesc.setFieldType(Types.DOUBLE);
146
                fieldDesc.setFieldLength(20);
147
                fieldDesc.setFieldDecimalCount(5);
148
                fieldsPol[0] = fieldDesc;
149
                
150
                fieldDesc = new FieldDescription();
151
                fieldDesc.setFieldName("IDFLAG");
152
                fieldDesc.setFieldType(Types.INTEGER);
153
                fieldDesc.setFieldLength(20);
154
                fieldDesc.setFieldDecimalCount(5);
155
                fieldsPol[1] = fieldDesc;
156

    
157
        }
158

    
159
        
160
        private Network net;
161
        private ShpWriter shpWriter;
162
        private ShpWriter shpWriterPol;
163
        private File fTemp;
164
        private File fTempPol;
165
        private SHPLayerDefinition layerDef;
166
        private SHPLayerDefinition layerDefPol;
167
        private Geometry serviceArea = null;
168
        private ArrayList <Geometry> serviceAreaPolygons;
169

    
170
        public ServiceAreaExtractor(Network net) throws BaseException {
171
                this.net = net;
172
                int aux = (int)(Math.random() * 1000);
173
                String nameLine = "tmpServiceAreaLine" + aux + ".shp";
174
                String namePol = "tmpServiceAreaPol" + aux + ".shp";
175
                fTemp = new File(tempDirectoryPath + "/" + nameLine );
176
                fTempPol = new File(tempDirectoryPath + "/" + namePol );
177
                
178
                layerDef = new SHPLayerDefinition();
179
                layerDef.setFile(fTemp);
180
                layerDef.setName(nameLine);                
181
                layerDef.setFieldsDesc(fields);
182
                layerDef.setShapeType(FShape.LINE);
183

    
184
                layerDefPol = new SHPLayerDefinition();
185
                layerDefPol.setFile(fTempPol);
186
                layerDefPol.setName(namePol);                
187
                layerDefPol.setFieldsDesc(fieldsPol);
188
                layerDefPol.setShapeType(FShape.POLYGON);
189
                
190
                shpWriter = new ShpWriter();
191
                shpWriter.setFile(fTemp);
192
                shpWriter.initialize(layerDef);
193

    
194
                shpWriterPol = new ShpWriter();
195
                shpWriterPol.setFile(fTempPol);
196
                shpWriterPol.initialize(layerDefPol);
197
                shpWriter.preProcess();
198
                shpWriterPol.preProcess();
199
                
200
                
201
        }
202
        
203
        public void doExtract(int idFlag, double[] costs) {
204
//                if (maxCost == -1)
205
//                {
206
//                        throw new RuntimeException("ServiceAreaExtactor: You need to set maxCost.");
207
//                }
208
                double maxCost = costs[costs.length-1];
209
                serviceAreaPolygons = new ArrayList<Geometry>(costs.length);
210
                for (int i=0; i < costs.length-1; i++)
211
                        serviceAreaPolygons.add(null);
212
                FLyrVect lyr = net.getLayer();
213
                IGraph g = net.getGraph();
214
                ReadableVectorial adapter = lyr.getSource();
215
                try {
216
                        
217
                        adapter.start();
218
                
219
                        for (int i=0; i < adapter.getShapeCount(); i++)
220
                        {
221
                                IGeometry geom = adapter.getShape(i);
222
                                EdgePair edgePair = g.getEdgesByIdArc(i);
223
                                if (edgePair.getIdEdge() != -1)
224
                                {
225
                                        GvEdge edge = g.getEdgeByID(edgePair.getIdEdge());
226
                                        GvNode nodeEnd = g.getNodeByID(edge.getIdNodeEnd());
227
                                        GvNode nodeOrig = g.getNodeByID(edge.getIdNodeOrig());
228
                                        processEdgeForPolygon(edge, nodeOrig, nodeEnd, geom, costs);
229
                                        if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
230
                                        {                                                
231
                                                if (nodeEnd.getBestCost() < maxCost) {
232
                                                        // A ese tramo hemos llegado por completo
233
                                                        // Recuperamos su distancia y etiquetamos.
234
                                                        writeTotalEdge(i, geom, edge, nodeOrig, nodeEnd, idFlag);        
235
                                                }
236
                                                else
237
                                                {
238
                                                        if (nodeOrig.getBestCost() < maxCost) {
239
                                                                // A ese tramo hemos llegado parcialmente
240
                                                                // Recuperamos su distancia y etiquetamos.
241
                                                                writePartialEdge(i, geom, edge, nodeOrig, nodeEnd, idFlag, maxCost);        
242
                                                                
243
                                                        }
244
                                                } // else
245
                                        } // if nodeEnd > nodeOrig
246
                                }
247
                                if (edgePair.getIdInverseEdge() != -1)
248
                                {
249
                                        GvEdge inversedEdge = g.getEdgeByID(edgePair.getIdInverseEdge());
250
                                        GvNode nodeEnd = g.getNodeByID(inversedEdge.getIdNodeEnd());
251
                                        GvNode nodeOrig = g.getNodeByID(inversedEdge.getIdNodeOrig());
252
                                        processEdgeForPolygon(inversedEdge, nodeOrig, nodeEnd, geom, costs);
253
                                        if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
254
                                        {                                        
255
                                                if (nodeEnd.getBestCost() < maxCost) {
256
                                                        // A ese tramo hemos llegado por completo
257
                                                        // Recuperamos su distancia y etiquetamos.
258
                                                        writeTotalEdge(i, geom, inversedEdge, nodeOrig, nodeEnd, idFlag);        
259
                                                }
260
                                                else
261
                                                {
262
                                                        if (nodeOrig.getBestCost() < maxCost) {
263
                                                                // A ese tramo hemos llegado parcialmente
264
                                                                // Recuperamos su distancia y etiquetamos.
265
                                                                writePartialEdge(i, geom, inversedEdge, nodeOrig, nodeEnd, idFlag, maxCost);        
266
                                                                
267
                                                        }
268
                                                } // else
269
                                        } // if nodeEnd > nodeOrig 
270
                                }
271
                                
272
                        }
273
                        for (int j=serviceAreaPolygons.size()-1; j>=0; j--) {
274
                                Geometry jtsGeom = serviceAreaPolygons.get(j);
275
                                writePolygon(idFlag, costs[j], jtsGeom);
276
                        }
277
                        adapter.stop();
278
                } catch (BaseException e) {
279
                        // TODO Auto-generated catch block
280
                        e.printStackTrace();
281
                }
282
                
283

    
284
        }
285
        
286
        /**
287
         * Write data and close files.
288
         * @throws BaseException
289
         */
290
        public void endExtraction() throws BaseException {
291
                shpWriter.postProcess();                        
292
                shpWriterPol.postProcess();
293
        }
294

    
295
        /**
296
         * We process each edge and prepare a list of polygons, classified by
297
         * cost
298
         * @param edge
299
         * @param nodeOrig
300
         * @param nodeEnd
301
         * @param geom
302
         * @param costs
303
         */
304
        private void processEdgeForPolygon(GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, IGeometry geom, double[] costs) {
305
                if (nodeEnd.getBestCost() > nodeOrig.getBestCost())
306
                {                
307
                        // miramos en qu? pol?gono cae ese edge POR COMPLETO 
308
                        // El coste de su punto final es menor que uno de los costes.
309
                        int indexInterval = getCostInterval(nodeEnd.getBestCost(), costs);
310
                        // Un pol?gono por cada zona
311
                        Geometry jtsGeom = geom.toJTSGeometry();
312
                        if (indexInterval != -1)
313
                        {
314
                                for (int i=costs.length-1; i >= indexInterval; i--) {
315
                                        calculateConvexHull(jtsGeom, i);
316
                                }
317
                        }
318
                        double maxCost = costs[costs.length-1];
319
                        // Es -1 si caso l?mite externo
320
                        if (indexInterval < costs.length-1)
321
                        {
322
                                // Caso l?mite externo
323
                                if ((nodeEnd.getBestCost() > maxCost) &&                                                
324
                                                (nodeOrig.getBestCost() < maxCost))
325
                                {
326
                                        double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
327
                                        LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
328
                                        calculateConvexHull(partial, costs.length-1);
329
                                        return;
330
                                }
331
                                // Parcial interno
332
                                maxCost = costs[indexInterval+1];
333
                                if ((nodeOrig.getBestCost() < maxCost) &&
334
                                                (nodeEnd.getBestCost() > maxCost)) 
335
                                {
336
                                        // A ese tramo hemos llegado parcialmente
337
                                         
338
                                        double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
339
                                        try {
340
                                                LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
341
                                                calculateConvexHull(partial, indexInterval+1);                                                        
342
                                        }
343
                                        catch (Exception e)
344
                                        {
345
                                                e.printStackTrace();
346
                                        }
347
                                        
348
                                }
349
                        }
350
                } 
351

    
352
                
353
        }
354

    
355
        /**
356
         * @param jtsGeom
357
         * @param i
358
         */
359
        private void calculateConvexHull(Geometry jtsGeom, int i) {
360
                if (serviceAreaPolygons.size() <= i) { // se crea por primera vez
361
                        Geometry gIni = jtsGeom; 
362
                        serviceAreaPolygons.add(i, gIni);
363
                }
364
                else
365
                {
366
                        Geometry antG = serviceAreaPolygons.get(i);
367
                        if (antG == null)
368
                                antG = jtsGeom;
369
                        else
370
                        {
371
                                antG = antG.union(jtsGeom);                                
372
                        }
373
                        antG = antG.convexHull();
374
                        serviceAreaPolygons.set(i, antG);
375
                }
376
        }
377

    
378
        /**
379
         * Devuelve el ?ndice del intervalo m?s alto que contiene a ese valor.
380
         * @param bestCost
381
         * @param costs
382
         * @return
383
         */
384
        private int getCostInterval(double bestCost, double[] costs) {
385
                int ret = 0;
386
                if (bestCost > costs[costs.length-1])
387
                        return -1;
388
                for (int i=costs.length-1; i>=0; i--) {
389
                        if (bestCost > costs[i])
390
                        {
391
                                ret = i+1;
392
                                break;
393
                        }
394
                }
395
//                if (ret > 0)
396
//                        System.out.println(costs[ret-1] + " < " + bestCost + " < " + costs[ret]); 
397
                return ret;
398
        }
399

    
400
        private void writePartialEdge(int i, IGeometry geom, GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, int idFlag, double maxCost) throws ProcessWriterVisitorException {
401
                Geometry jtsGeom = geom.toJTSGeometry();
402
                double pct = (maxCost - nodeOrig.getBestCost())/ edge.getWeight();
403
                LineString partial = NetworkUtils.getPartialLineString(jtsGeom, pct, edge.getDirec());
404
                if (serviceArea == null)
405
                        serviceArea = partial;
406
                else
407
                {
408
                        serviceArea = serviceArea.union(partial);
409
                        serviceArea = serviceArea.convexHull();
410
                }
411
                
412
                IGeometry newGeom = FConverter.jts_to_igeometry(partial);
413

    
414
                Value[] values = new Value[7];
415
                values[0] = ValueFactory.createValue(i);
416
                values[1] = ValueFactory.createValue(edge.getIdEdge());
417
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
418
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
419
                values[4] = ValueFactory.createValue(maxCost);
420
                values[5] = ValueFactory.createValue(nodeOrig.getAccumulatedLength() + edge.getDistance()*pct);
421
                values[6] = ValueFactory.createValue(idFlag);
422
                
423
                
424
                DefaultFeature feat = new DefaultFeature(newGeom, values);
425
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, i);
426
                shpWriter.process(row);
427
                
428
        }
429
        
430
        private void writeTotalEdge(int i, IGeometry geom, GvEdge edge, GvNode nodeOrig, GvNode nodeEnd, int idFlag) throws ProcessWriterVisitorException {
431
                Geometry jtsGeom = geom.toJTSGeometry();
432
                if (serviceArea == null)
433
                        serviceArea = jtsGeom;
434
                else
435
                {
436
                        serviceArea = serviceArea.union(jtsGeom);
437
                        serviceArea = serviceArea.convexHull();
438
                }
439
                
440
                Value[] values = new Value[7];
441
                values[0] = ValueFactory.createValue(i);
442
                values[1] = ValueFactory.createValue(edge.getIdEdge());
443
                values[2] = ValueFactory.createValue(nodeOrig.getBestCost());
444
                values[3] = ValueFactory.createValue(nodeOrig.getAccumulatedLength());
445
                values[4] = ValueFactory.createValue(nodeEnd.getBestCost());
446
                values[5] = ValueFactory.createValue(nodeEnd.getAccumulatedLength());
447
                values[6] = ValueFactory.createValue(idFlag);
448
                
449
                
450
                DefaultFeature feat = new DefaultFeature(geom, values);
451
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, i);
452
                shpWriter.process(row);
453
        }
454

    
455
        private void writePolygon(int idFlag, double maxCost, Geometry jtsGeom) throws ProcessWriterVisitorException {
456
                Value[] values = new Value[2];
457
                values[0] = ValueFactory.createValue(maxCost);
458
                values[1] = ValueFactory.createValue(idFlag);
459
                
460
                IGeometry geom = FConverter.jts_to_igeometry(jtsGeom);
461
                DefaultFeature feat = new DefaultFeature(geom, values);
462
                IRowEdited row = new DefaultRowEdited(feat, DefaultRowEdited.STATUS_ADDED, idFlag);
463
                shpWriterPol.process(row);
464
        }
465

    
466
        public FLyrVect getPolygonLayer() throws LoadLayerException {
467
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDefPol.getName(), "gvSIG shp driver", 
468
                                layerDefPol.getFile(), null);
469
                return lyr;
470
        }
471

    
472
        public FLyrVect getLineLayer() throws LoadLayerException {
473
                FLyrVect lyr = (FLyrVect) LayerFactory.createLayer(layerDef.getName(), "gvSIG shp driver", 
474
                                layerDef.getFile(), null);
475
                return lyr;
476
        }
477

    
478
}