Statistics
| Revision:

svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libGeocoding / src / org / gvsig / geocoding / geommatches / MatcherUtils.java @ 27215

History | View | Annotate | Download (14.4 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2008 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 * 
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 2
9
 * of the License, or (at your option) any later version.
10
 * 
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 * 
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
19
 * MA  02110-1301, USA.
20
 * 
21
 */
22

    
23
/*
24
 * AUTHORS (In addition to CIT):
25
 * 2008 Prodevelop S.L. main development
26
 */
27

    
28
package org.gvsig.geocoding.geommatches;
29

    
30
import java.awt.geom.PathIterator;
31
import java.util.ArrayList;
32
import java.util.HashMap;
33
import java.util.Iterator;
34
import java.util.LinkedList;
35
import java.util.List;
36

    
37
import org.gvsig.fmap.dal.exception.DataException;
38
import org.gvsig.fmap.dal.feature.Feature;
39
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
40
import org.gvsig.fmap.geom.Geometry;
41
import org.gvsig.fmap.geom.primitive.Curve2D;
42
import org.gvsig.fmap.geom.primitive.Point2D;
43
import org.gvsig.fmap.geom.util.Converter;
44
import org.gvsig.fmap.geom.util.UtilFunctions;
45
import org.gvsig.geocoding.result.DissolveResult;
46
import org.gvsig.geocoding.result.ScoredFeature;
47
import org.slf4j.Logger;
48
import org.slf4j.LoggerFactory;
49

    
50
import com.vividsolutions.jts.geom.Coordinate;
51
import com.vividsolutions.jts.linearref.LengthIndexedLine;
52
import com.vividsolutions.jts.operation.overlay.OverlayOp;
53

    
54
/**
55
 * This class has the utilities to work with geometries and search th geocoding
56
 * point
57
 * 
58
 * @author <a href="mailto:jsanz@prodevelop.es"> Jorge Gaspar Sanz Salinas</a>
59
 * @author <a href="mailto:vsanjaime@prodevelop.es"> Vicente Sanjaime Calvet</a>
60
 */
61

    
62
public class MatcherUtils {
63

    
64
        private static final Logger log = LoggerFactory
65
                        .getLogger(MatcherUtils.class);
66
        
67
        public static final String LINES = "LINES";
68
        public static final String POLYS = "POLYS";
69

    
70
        /**
71
         * Get internal point from one geometry (polygon)
72
         * 
73
         * @param geomGV
74
         * @return
75
         */
76
        public static Point2D internalPointGeometry(Geometry geomGV) {
77

    
78
                if (geomGV != null) {
79
                        com.vividsolutions.jts.geom.Geometry geomJTS = parseGeomGVToJTS(geomGV);
80
                        if (geomJTS != null) {
81
                                com.vividsolutions.jts.geom.Point pto = geomJTS
82
                                                .getInteriorPoint();
83
                                if (pto != null) {
84
                                        return new Point2D(pto.getX(), pto.getY());
85
                                }
86
                        }
87
                }
88
                return null;
89
        }
90

    
91
        /**
92
         * parse geometries of gvSIG model to JTS model
93
         * 
94
         * @param geoms
95
         *            list of gvSIG geometries
96
         * @return list of JTS geometries
97
         */
98
        public static List<com.vividsolutions.jts.geom.Geometry> parseGeomsGVToJTS(
99
                        List<Geometry> geoms) {
100

    
101
                List<com.vividsolutions.jts.geom.Geometry> list = new ArrayList<com.vividsolutions.jts.geom.Geometry>();
102

    
103
                if (geoms != null && geoms.size() > 0) {
104
                        com.vividsolutions.jts.geom.Geometry ge = null;
105
                        for (Geometry geometry : geoms) {
106
                                ge = Converter.geometryToJts(geometry);
107
                                list.add(ge);
108
                        }
109
                }
110
                return list;
111
        }
112

    
113
        /**
114
         * Parse one gvSIG geomerty to JTS geometry
115
         * 
116
         * @param geom
117
         *            gvSIG geometry
118
         * @return JTS geometry
119
         */
120
        public static com.vividsolutions.jts.geom.Geometry parseGeomGVToJTS(
121
                        Geometry geom) {
122

    
123
                if (geom != null) {
124
                        return Converter.geometryToJts(geom);
125
                }
126
                return null;
127
        }
128

    
129
        /**
130
         * parse a list of gvSIG geometries to JTS geometries
131
         * 
132
         * @param geoms
133
         *            list gvSIG geometries to JTS geometries
134
         * @return
135
         */
136
        public static List<Geometry> parseGeomsJTSToGV(
137
                        List<com.vividsolutions.jts.geom.Geometry> geoms) {
138

    
139
                List<Geometry> list = new ArrayList<Geometry>();
140

    
141
                if (geoms != null && geoms.size() > 0) {
142
                        for (com.vividsolutions.jts.geom.Geometry geometry : geoms) {
143
                                list.add(Converter.jtsToGeometry(geometry));
144
                        }
145
                }
146
                return list;
147
        }
148

    
149
        /**
150
         * Parse a gvSIG geometry to JTS geometry
151
         * 
152
         * @param geom
153
         *            gvSIg geometry
154
         * @return JTS geometry
155
         */
156
        public static Geometry parseGeomJTSToGV(
157
                        com.vividsolutions.jts.geom.Geometry geom) {
158
                if (geom != null) {
159
                        return Converter.jtsToGeometry(geom);
160
                }
161
                return null;
162
        }
163

    
164
        /**
165
         * This method intersect two lines and return the intersection point. If
166
         * result is null, two lines doesn't intersect
167
         * 
168
         * @param geom1Jts
169
         * @param geom2Jts
170
         * @return
171
         */
172
        public static Point2D intersectTwoLinesJTS(
173
                        com.vividsolutions.jts.geom.Geometry geom1Jts,
174
                        com.vividsolutions.jts.geom.Geometry geom2Jts) {
175

    
176
                com.vividsolutions.jts.geom.Geometry interBBoxJTS = null;
177
                com.vividsolutions.jts.geom.Geometry geomPointJTS = null;
178

    
179
                if (geom1Jts != null && geom2Jts != null) {
180

    
181
                        interBBoxJTS = OverlayOp.overlayOp(geom1Jts.getEnvelope(), geom2Jts
182
                                        .getEnvelope(), OverlayOp.INTERSECTION);
183
                        if (interBBoxJTS.getGeometryType().compareTo("LineString") == 0
184
                                        || interBBoxJTS.getGeometryType().compareTo("Polygon") == 0) {
185
                                log.debug("Intersect: Intersect two BBOX");
186
                                geomPointJTS = OverlayOp.overlayOp(geom1Jts, geom2Jts,
187
                                                OverlayOp.INTERSECTION);
188

    
189
                                if (geomPointJTS.getGeometryType().compareTo("Point") == 0) {
190
                                        log.debug("Intersect: Intersect in the point X= "
191
                                                        + geomPointJTS.getCoordinate().x + " Y= "
192
                                                        + geomPointJTS.getCoordinate().y);
193
                                        Point2D pto = new Point2D(geomPointJTS.getCoordinate().x,
194
                                                        geomPointJTS.getCoordinate().y);
195
                                        return pto;
196
                                } else {
197
                                        log.debug("Intersect: Two lines don't intersect");
198
                                        return null;
199
                                }
200
                        } else {
201
                                log.debug("Intersect: Two BBOX don't intersect");
202
                                return null;
203
                        }
204
                }
205
                log.debug("Some Geometries are NULL  ......");
206
                return null;
207
        }
208

    
209
        /**
210
         * This method does the union the geometries (Features) with a
211
         * attribute common
212
         * 
213
         * @param sFeats
214
         * @param geomType LINES, POLYS
215
         * @return
216
         * @throws DataException
217
         */
218
        public static List<DissolveResult> dissolveGeomsJTS(
219
                        List<ScoredFeature> sFeats, String geomType) throws DataException {
220

    
221
                List<DissolveResult> results = new ArrayList<DissolveResult>();
222

    
223
                // None elements
224
                if (sFeats.size() == 0) {
225
                        return results;
226
                }
227

    
228
                // Only one element
229
                else if (sFeats.size() == 1) {
230
                        DissolveResult result = new DissolveResult();
231
                        Feature feat = null;
232
                        try {
233
                                feat = sFeats.get(0).getFeature();
234
                                result.setGeom(feat.getDefaultGeometry());
235
                                List<ScoredFeature> list = new ArrayList<ScoredFeature>();
236
                                list.add(sFeats.get(0));
237
                                result.setScoredFeatures(list);
238
                                results.add(result);
239
                        } catch (DataException e) {
240
                                log.debug("Error getting the feature", e);
241
                        }
242
                        return results;
243
                }
244

    
245
                // more elements
246
                else {
247

    
248
                        LinkedList<ScoredFeature> list = new LinkedList<ScoredFeature>();
249
                        com.vividsolutions.jts.geom.Geometry geo1, geo2;
250

    
251
                        for (ScoredFeature scoredFeature : sFeats) {
252
                                list.add(scoredFeature);
253
                        }
254

    
255
                        // Iterate over the linked list
256
                        while (list.size() > 0) {
257
                                // Remove the first element of the list
258
                                ScoredFeature sFeat = list.poll();
259

    
260
                                // create first dissolve result and add it to the list
261
                                DissolveResult result = new DissolveResult();
262
                                ArrayList<ScoredFeature> dissolveList = new ArrayList<ScoredFeature>();
263
                                dissolveList.add(sFeat);
264

    
265
                                geo1 = MatcherUtils.parseGeomGVToJTS(sFeat.getFeature()
266
                                                .getDefaultGeometry());
267
                                
268
                                ScoredFeature touchingSFeat = null;
269
                                // LINES
270
                                
271
                                if (geomType.compareTo(LINES)==0) {
272
                                        touchingSFeat = getFirstLineTouchingSF(geo1, list);
273
                                }
274
                                // POLYS
275
                                if (geomType.compareTo(POLYS)==0) {
276
                                        touchingSFeat = getFirstPolyTouchingSF(geo1, list);
277
                                }                                
278

    
279
                                while (touchingSFeat != null) {
280
                                        list.remove(touchingSFeat);
281
                                        geo2 = MatcherUtils.parseGeomGVToJTS(touchingSFeat
282
                                                        .getFeature().getDefaultGeometry());
283

    
284
                                        geo1 = OverlayOp.overlayOp(geo1, geo2, OverlayOp.UNION);
285

    
286
                                        dissolveList.add(touchingSFeat);
287

    
288
                                        touchingSFeat = getFirstLineTouchingSF(geo1, list);
289
                                }
290
                                result.setJTSGeom(geo1);
291
                                result.setScoredFeatures(dissolveList);
292
                                results.add(result);
293
                        }                        
294
                }                
295
                return results;
296
        }
297

    
298
        /**
299
         * Get first line of the list that it is touching the in geometry
300
         * @param geometry
301
         * @param list
302
         * @return
303
         * @throws DataException
304
         */
305
        private static ScoredFeature getFirstLineTouchingSF(
306
                        com.vividsolutions.jts.geom.Geometry geometry,
307
                        LinkedList<ScoredFeature> list) throws DataException {
308

    
309
                com.vividsolutions.jts.geom.Geometry geo2;
310
                for (ScoredFeature listedSF : list) {
311
                        geo2 = MatcherUtils.parseGeomGVToJTS(listedSF.getFeature()
312
                                        .getDefaultGeometry());
313
                        if (geometry.touches(geo2))
314
                                return listedSF;
315
                }
316
                return null;
317
        }
318

    
319
        /**
320
         * Get first poly of the list that it is touching the in geometry
321
         * @param geometry
322
         * @param list
323
         * @return
324
         * @throws DataException
325
         */
326
        private static ScoredFeature getFirstPolyTouchingSF(
327
                        com.vividsolutions.jts.geom.Geometry geometry,
328
                        LinkedList<ScoredFeature> list) throws DataException {
329

    
330
                com.vividsolutions.jts.geom.Geometry geo2;
331
                com.vividsolutions.jts.geom.Geometry geo3;
332
                for (ScoredFeature listedSF : list) {
333
                        geo2 = MatcherUtils.parseGeomGVToJTS(listedSF.getFeature()
334
                                        .getDefaultGeometry());
335
                        geo3 = geometry.intersection(geo2);
336
                        for (int i = 0; i < geo3.getNumGeometries(); i++) {
337
                                int dim = geo3.getGeometryN(i).getDimension();
338
                                if (dim == 1) {
339
                                        return listedSF;
340
                                }
341
                        }                        
342
                }
343
                return null;
344
        }
345

    
346
        /**
347
         * This method group geometries to one attribute
348
         * 
349
         * @param desc
350
         * @param features
351
         * @return
352
         */
353
        public static HashMap<String, List<ScoredFeature>> groupScoredFeaturesByAttribute(
354
                        FeatureAttributeDescriptor desc, List<ScoredFeature> features) {
355

    
356
                HashMap<String, List<ScoredFeature>> groups = new HashMap<String, List<ScoredFeature>>();
357
                Iterator<ScoredFeature> it = features.iterator();
358
                // Go for all geometries of the collection
359
                while (it.hasNext()) {
360
                        // Get feature
361
                        ScoredFeature sFeat = (ScoredFeature) it.next();
362
                        Feature feat = null;
363
                        try {
364
                                feat = sFeat.getFeature();
365
                                String key = feat.get(desc.getIndex()).toString();
366
                                // Store the geometries for attribute in the List
367
                                boolean contiene = groups.containsKey(key);
368
                                if (!contiene) {
369
                                        List<ScoredFeature> featss = new ArrayList<ScoredFeature>();
370
                                        featss.add(sFeat);
371
                                        groups.put(key, featss);
372
                                } else {
373
                                        ((List<ScoredFeature>) groups.get(key)).add(sFeat);
374
                                }
375
                        } catch (DataException e) {
376
                                log.debug("Error clustering element", e);
377
                                continue;
378
                        }
379
                }
380
                return groups;
381
        }
382

    
383
        /**
384
         * Calculate the position inside single line from distance
385
         * 
386
         * @param geomJTS
387
         * @param distance
388
         * @return
389
         */
390
        public static Point2D getLinePositionFromDistance(
391
                        com.vividsolutions.jts.geom.Geometry geomJTS, double distance) {
392

    
393
                if (geomJTS != null) {
394
                        LengthIndexedLine lenline = new LengthIndexedLine(geomJTS);
395
                        if (distance < 0) {
396
                                distance = 0.0;
397
                        }
398
                        if (distance > geomJTS.getLength()) {
399
                                distance = geomJTS.getLength();
400
                        }
401
                        if (lenline.isValidIndex(distance)) {
402
                                Coordinate coors = lenline.extractPoint(distance);
403
                                return new Point2D(coors.x, coors.y);
404
                        }
405
                }
406
                return null;
407
        }
408

    
409
        /**
410
         * Calculate the position inside single line from relative distance
411
         * 
412
         * @param geomJTS
413
         * @param distance
414
         * @return
415
         */
416
        public static Point2D getLinePositionFromRelativeDistance(
417
                        com.vividsolutions.jts.geom.Geometry geomJTS, int relative) {
418
                if (geomJTS != null) {
419
                        double totaldistance = geomJTS.getLength();
420
                        LengthIndexedLine lenline = new LengthIndexedLine(geomJTS);
421

    
422
                        Coordinate coors = null;
423

    
424
                        if (relative < 0) {
425
                                coors = lenline.extractPoint(0);
426
                                return new Point2D(coors.x, coors.y);
427
                        } else if (relative <= 100 && relative >= 0) {
428
                                double dist = (relative * totaldistance) / 100.0;
429
                                coors = lenline.extractPoint(dist);
430
                                return new Point2D(coors.x, coors.y);
431
                        } else {
432
                                coors = lenline.extractPoint(totaldistance);
433
                                return new Point2D(coors.x, coors.y);
434
                        }
435
                }
436
                return null;
437
        }
438

    
439
        /**
440
         * This method calculates a point perpendicular to the line at a distance
441
         * 
442
         * @param inicio
443
         * @param fin
444
         * @param linePoint
445
         * @param dist
446
         * @return
447
         */
448
        public static Point2D getPerpendicularPointFromLine(Point2D inicio,
449
                        Point2D fin, Point2D linePoint, double dist) {
450

    
451
                java.awt.geom.Point2D pto1 = new java.awt.geom.Point2D.Double(inicio
452
                                .getX(), inicio.getY());
453
                java.awt.geom.Point2D pto2 = new java.awt.geom.Point2D.Double(fin
454
                                .getX(), fin.getY());
455

    
456
                java.awt.geom.Point2D perpPoint = new java.awt.geom.Point2D.Double(
457
                                linePoint.getX(), linePoint.getY());
458

    
459
                java.awt.geom.Point2D[] p = UtilFunctions.getPerpendicular(pto1, pto2,
460
                                perpPoint);
461
                java.awt.geom.Point2D unit = UtilFunctions.getUnitVector(p[0], p[1]);
462

    
463
                java.awt.geom.Point2D res = new java.awt.geom.Point2D.Double(perpPoint
464
                                .getX()
465
                                + (unit.getX() * dist), perpPoint.getY() + (unit.getY() * dist));
466

    
467
                return new Point2D(res.getX(), res.getY());
468
        }
469

    
470
        /**
471
         * Calculate the position in the line with offset
472
         * 
473
         * @param geoms
474
         * @param linePoint
475
         * @param dist
476
         * @return
477
         */
478
        public static Point2D getOffsetPosition(Geometry[] geoms,
479
                        Point2D linePoint, double dist) {
480

    
481
                for (int j = 0; j < geoms.length; j++) {
482
                        double[] coords = new double[6];
483
                        Point2D inicio = null;
484
                        Point2D fin = null;
485

    
486
                        boolean inter = geoms[j].intersects(linePoint.getBounds2D());
487
                        if (inter) {
488
                                PathIterator iter = ((Curve2D) geoms[j]).getGeneralPathX()
489
                                                .getPathIterator(null);
490
                                iter.currentSegment(coords);
491
                                inicio = new Point2D(coords[0], coords[1]);
492

    
493
                                iter.next();
494
                                iter.currentSegment(coords);
495
                                fin = new Point2D(coords[0], coords[1]);
496

    
497
                                log.debug("Return point with offset");
498
                                return MatcherUtils.getPerpendicularPointFromLine(inicio, fin,
499
                                                linePoint, dist);
500
                        }
501
                }
502
                log.debug("Return original point without offset");
503
                return linePoint;
504

    
505
        }
506

    
507
}