Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extGraph / src / com / iver / cit / gvsig / graph / solvers / ServiceAreaExtractor.java @ 14780

History | View | Annotate | Download (15 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 com.iver.cit.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

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

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

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

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

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

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

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

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

    
158
        }
159

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

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

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

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

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

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

    
353
                
354
        }
355

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

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

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

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

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

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

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

    
479
}