svn-gvsig-desktop / branches / v2_0_0_prep / libraries / libGeocoding / src / org / gvsig / geocoding / geommatches / MatcherUtils.java @ 28375
History | View | Annotate | Download (14.5 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.geom.Geometry; |
40 |
import org.gvsig.fmap.geom.GeometryLocator; |
41 |
import org.gvsig.fmap.geom.exception.CreateGeometryException; |
42 |
import org.gvsig.fmap.geom.primitive.Point; |
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.gvsig.geocoding.result.impl.DefaultDissolveResult; |
48 |
import org.gvsig.tools.locator.LocatorException; |
49 |
import org.slf4j.Logger; |
50 |
import org.slf4j.LoggerFactory; |
51 |
|
52 |
import com.vividsolutions.jts.geom.Coordinate; |
53 |
import com.vividsolutions.jts.linearref.LengthIndexedLine; |
54 |
import com.vividsolutions.jts.operation.overlay.OverlayOp; |
55 |
|
56 |
/**
|
57 |
* This class has the utilities to work with geometries and search the geocoding
|
58 |
* point
|
59 |
*
|
60 |
* @author <a href="mailto:jsanz@prodevelop.es"> Jorge Gaspar Sanz Salinas</a>
|
61 |
* @author <a href="mailto:vsanjaime@prodevelop.es"> Vicente Sanjaime Calvet</a>
|
62 |
*/
|
63 |
|
64 |
public class MatcherUtils { |
65 |
|
66 |
private static final Logger log = LoggerFactory |
67 |
.getLogger(MatcherUtils.class); |
68 |
|
69 |
public static final String LINES = "LINES"; |
70 |
public static final String POLYS = "POLYS"; |
71 |
|
72 |
/**
|
73 |
* Get internal point from one polygon geometry
|
74 |
*
|
75 |
* @param geomGV
|
76 |
* @return
|
77 |
*/
|
78 |
public static Point internalPointGeometry(Geometry geomGV) { |
79 |
|
80 |
if (geomGV != null) { |
81 |
com.vividsolutions.jts.geom.Geometry geomJTS = Converter |
82 |
.geometryToJts(geomGV); |
83 |
if (geomJTS != null) { |
84 |
com.vividsolutions.jts.geom.Point pto = geomJTS |
85 |
.getInteriorPoint(); |
86 |
if (pto != null) { |
87 |
return getPoint(pto.getX(), pto.getY());
|
88 |
} |
89 |
} |
90 |
} |
91 |
return null; |
92 |
} |
93 |
|
94 |
/**
|
95 |
* parse geometries of gvSIG model to JTS model
|
96 |
*
|
97 |
* @param geoms
|
98 |
* list of gvSIG geometries
|
99 |
* @return list of JTS geometries
|
100 |
*/
|
101 |
public static List<com.vividsolutions.jts.geom.Geometry> parseGeomsGVToJTS( |
102 |
List<Geometry> geoms) {
|
103 |
|
104 |
List<com.vividsolutions.jts.geom.Geometry> list = new ArrayList<com.vividsolutions.jts.geom.Geometry>(); |
105 |
|
106 |
if (geoms != null && geoms.size() > 0) { |
107 |
com.vividsolutions.jts.geom.Geometry ge = null;
|
108 |
for (Geometry geometry : geoms) {
|
109 |
ge = Converter.geometryToJts(geometry); |
110 |
list.add(ge); |
111 |
} |
112 |
} |
113 |
return list;
|
114 |
} |
115 |
|
116 |
/**
|
117 |
* parse a list of gvSIG geometries to JTS geometries
|
118 |
*
|
119 |
* @param geoms
|
120 |
* list gvSIG geometries to JTS geometries
|
121 |
* @return
|
122 |
*/
|
123 |
public static List<Geometry> parseGeomsJTSToGV( |
124 |
List<com.vividsolutions.jts.geom.Geometry> geoms) {
|
125 |
|
126 |
List<Geometry> list = new ArrayList<Geometry>(); |
127 |
|
128 |
if (geoms != null && geoms.size() > 0) { |
129 |
for (com.vividsolutions.jts.geom.Geometry geometry : geoms) {
|
130 |
list.add(Converter.jtsToGeometry(geometry)); |
131 |
} |
132 |
} |
133 |
return list;
|
134 |
} |
135 |
|
136 |
/**
|
137 |
* This method intersect two lines and return the intersection point. If
|
138 |
* result is null, two lines doesn't intersect
|
139 |
*
|
140 |
* @param geom1Jts
|
141 |
* @param geom2Jts
|
142 |
* @return
|
143 |
*/
|
144 |
public static Point intersectTwoLinesJTS( |
145 |
com.vividsolutions.jts.geom.Geometry geom1Jts, |
146 |
com.vividsolutions.jts.geom.Geometry geom2Jts) { |
147 |
|
148 |
com.vividsolutions.jts.geom.Geometry interBBoxJTS = null;
|
149 |
com.vividsolutions.jts.geom.Geometry geomPointJTS = null;
|
150 |
|
151 |
if (geom1Jts != null && geom2Jts != null) { |
152 |
|
153 |
interBBoxJTS = OverlayOp.overlayOp(geom1Jts.getEnvelope(), geom2Jts |
154 |
.getEnvelope(), OverlayOp.INTERSECTION); |
155 |
if (interBBoxJTS.getGeometryType().compareTo("LineString") == 0 |
156 |
|| interBBoxJTS.getGeometryType().compareTo("Polygon") == 0) { |
157 |
log.debug("Intersect: Intersect two BBOX");
|
158 |
geomPointJTS = OverlayOp.overlayOp(geom1Jts, geom2Jts, |
159 |
OverlayOp.INTERSECTION); |
160 |
|
161 |
if (geomPointJTS.getGeometryType().compareTo("Point") == 0) { |
162 |
log.debug("Intersect: Intersect in the point X= "
|
163 |
+ geomPointJTS.getCoordinate().x + " Y= "
|
164 |
+ geomPointJTS.getCoordinate().y); |
165 |
Point pto = getPoint(geomPointJTS.getCoordinate().x,
|
166 |
geomPointJTS.getCoordinate().y); |
167 |
|
168 |
return pto;
|
169 |
} else {
|
170 |
log.debug("Intersect: Two lines don't intersect");
|
171 |
return null; |
172 |
} |
173 |
} else {
|
174 |
log.debug("Intersect: Two BBOX don't intersect");
|
175 |
return null; |
176 |
} |
177 |
} |
178 |
log.debug("Some Geometries are NULL ......");
|
179 |
return null; |
180 |
} |
181 |
|
182 |
/**
|
183 |
* This method does the union the geometries (Features) with a attribute
|
184 |
* common
|
185 |
*
|
186 |
* @param sFeats
|
187 |
* @param geomType
|
188 |
* LINES, POLYS
|
189 |
* @return
|
190 |
* @throws DataException
|
191 |
*/
|
192 |
public static List<DissolveResult> dissolveGeomsJTS( |
193 |
List<ScoredFeature> sFeats, String geomType) throws DataException { |
194 |
|
195 |
List<DissolveResult> results = new ArrayList<DissolveResult>(); |
196 |
|
197 |
// None elements
|
198 |
if (sFeats.size() == 0) { |
199 |
return results;
|
200 |
} |
201 |
|
202 |
// Only one element
|
203 |
else if (sFeats.size() == 1) { |
204 |
DissolveResult result = new DefaultDissolveResult();
|
205 |
Feature feat = null;
|
206 |
try {
|
207 |
feat = sFeats.get(0).getFeature();
|
208 |
result.setGeom(feat.getDefaultGeometry()); |
209 |
List<ScoredFeature> list = new ArrayList<ScoredFeature>(); |
210 |
list.add(sFeats.get(0));
|
211 |
result.setScoredFeatures(list); |
212 |
results.add(result); |
213 |
} catch (DataException e) {
|
214 |
log.debug("Error getting the feature", e);
|
215 |
} |
216 |
return results;
|
217 |
} |
218 |
|
219 |
// more elements
|
220 |
else {
|
221 |
|
222 |
LinkedList<ScoredFeature> list = new LinkedList<ScoredFeature>(); |
223 |
com.vividsolutions.jts.geom.Geometry geo1, geo2; |
224 |
|
225 |
for (ScoredFeature scoredFeature : sFeats) {
|
226 |
list.add(scoredFeature); |
227 |
} |
228 |
|
229 |
// Iterate over the linked list
|
230 |
while (list.size() > 0) { |
231 |
// Remove the first element of the list
|
232 |
ScoredFeature sFeat = list.poll(); |
233 |
|
234 |
// create first dissolve result and add it to the list
|
235 |
DissolveResult result = new DefaultDissolveResult();
|
236 |
ArrayList<ScoredFeature> dissolveList = new ArrayList<ScoredFeature>(); |
237 |
dissolveList.add(sFeat); |
238 |
|
239 |
geo1 = Converter.geometryToJts(sFeat.getFeature() |
240 |
.getDefaultGeometry()); |
241 |
|
242 |
ScoredFeature touchingSFeat = null;
|
243 |
// LINES
|
244 |
|
245 |
if (geomType.compareTo(LINES) == 0) { |
246 |
touchingSFeat = getFirstLineTouchingSF(geo1, list); |
247 |
} |
248 |
// POLYS
|
249 |
if (geomType.compareTo(POLYS) == 0) { |
250 |
touchingSFeat = getFirstPolyTouchingSF(geo1, list); |
251 |
} |
252 |
|
253 |
while (touchingSFeat != null) { |
254 |
list.remove(touchingSFeat); |
255 |
geo2 = Converter.geometryToJts(touchingSFeat.getFeature() |
256 |
.getDefaultGeometry()); |
257 |
|
258 |
geo1 = OverlayOp.overlayOp(geo1, geo2, OverlayOp.UNION); |
259 |
|
260 |
dissolveList.add(touchingSFeat); |
261 |
|
262 |
touchingSFeat = getFirstLineTouchingSF(geo1, list); |
263 |
} |
264 |
result.setJTSGeom(geo1); |
265 |
result.setScoredFeatures(dissolveList); |
266 |
results.add(result); |
267 |
} |
268 |
} |
269 |
return results;
|
270 |
} |
271 |
|
272 |
/**
|
273 |
* Get first line of the list that it is touching the in geometry
|
274 |
*
|
275 |
* @param geometry
|
276 |
* @param list
|
277 |
* @return
|
278 |
* @throws DataException
|
279 |
*/
|
280 |
private static ScoredFeature getFirstLineTouchingSF( |
281 |
com.vividsolutions.jts.geom.Geometry geometry, |
282 |
LinkedList<ScoredFeature> list) throws DataException { |
283 |
|
284 |
com.vividsolutions.jts.geom.Geometry geo2; |
285 |
for (ScoredFeature listedSF : list) {
|
286 |
geo2 = Converter.geometryToJts(listedSF.getFeature() |
287 |
.getDefaultGeometry()); |
288 |
if (geometry.touches(geo2))
|
289 |
return listedSF;
|
290 |
} |
291 |
return null; |
292 |
} |
293 |
|
294 |
/**
|
295 |
* Get first poly of the list that it is touching the in geometry
|
296 |
*
|
297 |
* @param geometry
|
298 |
* @param list
|
299 |
* @return
|
300 |
* @throws DataException
|
301 |
*/
|
302 |
private static ScoredFeature getFirstPolyTouchingSF( |
303 |
com.vividsolutions.jts.geom.Geometry geometry, |
304 |
LinkedList<ScoredFeature> list) throws DataException { |
305 |
|
306 |
com.vividsolutions.jts.geom.Geometry geo2; |
307 |
com.vividsolutions.jts.geom.Geometry geo3; |
308 |
for (ScoredFeature listedSF : list) {
|
309 |
geo2 = Converter.geometryToJts(listedSF.getFeature() |
310 |
.getDefaultGeometry()); |
311 |
geo3 = geometry.intersection(geo2); |
312 |
for (int i = 0; i < geo3.getNumGeometries(); i++) { |
313 |
int dim = geo3.getGeometryN(i).getDimension();
|
314 |
if (dim == 1) { |
315 |
return listedSF;
|
316 |
} |
317 |
} |
318 |
} |
319 |
return null; |
320 |
} |
321 |
|
322 |
/**
|
323 |
* This method group geometries to one attribute
|
324 |
*
|
325 |
* @param desc
|
326 |
* @param features
|
327 |
* @return
|
328 |
*/
|
329 |
public static HashMap<String, List<ScoredFeature>> groupScoredFeaturesByAttribute( |
330 |
String desc, List<ScoredFeature> features) { |
331 |
|
332 |
HashMap<String, List<ScoredFeature>> groups = new HashMap<String, List<ScoredFeature>>(); |
333 |
Iterator<ScoredFeature> it = features.iterator();
|
334 |
// Go for all geometries of the collection
|
335 |
while (it.hasNext()) {
|
336 |
// Get feature
|
337 |
ScoredFeature sFeat = (ScoredFeature) it.next(); |
338 |
Feature feat = null;
|
339 |
try {
|
340 |
feat = sFeat.getFeature(); |
341 |
String key = feat.get(desc).toString();
|
342 |
// Store the geometries for attribute in the List
|
343 |
boolean contiene = groups.containsKey(key);
|
344 |
if (!contiene) {
|
345 |
List<ScoredFeature> featss = new ArrayList<ScoredFeature>(); |
346 |
featss.add(sFeat); |
347 |
groups.put(key, featss); |
348 |
} else {
|
349 |
((List<ScoredFeature>) groups.get(key)).add(sFeat);
|
350 |
} |
351 |
} catch (DataException e) {
|
352 |
log.debug("Error clustering element", e);
|
353 |
continue;
|
354 |
} |
355 |
} |
356 |
return groups;
|
357 |
} |
358 |
|
359 |
/**
|
360 |
* Calculate the position inside single line from distance
|
361 |
*
|
362 |
* @param geomJTS
|
363 |
* @param distance
|
364 |
* @return
|
365 |
*/
|
366 |
public static Point getLinePositionFromDistance( |
367 |
com.vividsolutions.jts.geom.Geometry geomJTS, double distance) {
|
368 |
|
369 |
if (geomJTS != null) { |
370 |
LengthIndexedLine lenline = new LengthIndexedLine(geomJTS);
|
371 |
if (distance < 0) { |
372 |
distance = 0.0;
|
373 |
} |
374 |
if (distance > geomJTS.getLength()) {
|
375 |
distance = geomJTS.getLength(); |
376 |
} |
377 |
if (lenline.isValidIndex(distance)) {
|
378 |
Coordinate coors = lenline.extractPoint(distance); |
379 |
|
380 |
return getPoint(coors.x, coors.y);
|
381 |
|
382 |
} |
383 |
} |
384 |
return null; |
385 |
} |
386 |
|
387 |
/**
|
388 |
* Calculate the position inside single line from relative distance
|
389 |
*
|
390 |
* @param geomJTS
|
391 |
* @param distance
|
392 |
* @return
|
393 |
*/
|
394 |
public static Point getLinePositionFromRelativeDistance( |
395 |
com.vividsolutions.jts.geom.Geometry geomJTS, int relative) {
|
396 |
if (geomJTS != null) { |
397 |
double totaldistance = geomJTS.getLength();
|
398 |
LengthIndexedLine lenline = new LengthIndexedLine(geomJTS);
|
399 |
|
400 |
Coordinate coors = null;
|
401 |
|
402 |
if (relative < 0) { |
403 |
coors = lenline.extractPoint(0);
|
404 |
return getPoint(coors.x, coors.y);
|
405 |
} else if (relative <= 100 && relative >= 0) { |
406 |
double dist = (relative * totaldistance) / 100.0; |
407 |
coors = lenline.extractPoint(dist); |
408 |
return getPoint(coors.x, coors.y);
|
409 |
} else {
|
410 |
coors = lenline.extractPoint(totaldistance); |
411 |
return getPoint(coors.x, coors.y);
|
412 |
} |
413 |
} |
414 |
return null; |
415 |
} |
416 |
|
417 |
/**
|
418 |
* This method calculates a point perpendicular to the line at a distance
|
419 |
*
|
420 |
* @param inicio
|
421 |
* @param fin
|
422 |
* @param linePoint
|
423 |
* @param dist
|
424 |
* @return
|
425 |
*/
|
426 |
public static Point getPerpendicularPointFromLine(Point inicio, Point fin, |
427 |
Point linePoint, double dist) { |
428 |
|
429 |
java.awt.geom.Point2D pto1 = new java.awt.geom.Point2D.Double(inicio
|
430 |
.getX(), inicio.getY()); |
431 |
java.awt.geom.Point2D pto2 = new java.awt.geom.Point2D.Double(fin
|
432 |
.getX(), fin.getY()); |
433 |
|
434 |
java.awt.geom.Point2D perpPoint = new java.awt.geom.Point2D.Double(
|
435 |
linePoint.getX(), linePoint.getY()); |
436 |
|
437 |
java.awt.geom.Point2D[] p = UtilFunctions.getPerpendicular(pto1, pto2,
|
438 |
perpPoint); |
439 |
java.awt.geom.Point2D unit = UtilFunctions.getUnitVector(p[0], p[1]); |
440 |
|
441 |
java.awt.geom.Point2D res = new java.awt.geom.Point2D.Double(perpPoint
|
442 |
.getX() |
443 |
+ (unit.getX() * dist), perpPoint.getY() + (unit.getY() * dist)); |
444 |
|
445 |
return getPoint(res.getX(), res.getY());
|
446 |
} |
447 |
|
448 |
/**
|
449 |
* Calculate the position in the line with offset
|
450 |
*
|
451 |
* @param geoms
|
452 |
* @param linePoint
|
453 |
* @param dist
|
454 |
* @return
|
455 |
*/
|
456 |
public static Point getOffsetPosition(Geometry[] geoms, Point linePoint, |
457 |
double dist) {
|
458 |
|
459 |
for (int j = 0; j < geoms.length; j++) { |
460 |
double[] coords = new double[6]; |
461 |
Point inicio = null; |
462 |
Point fin = null; |
463 |
|
464 |
boolean inter = geoms[j].intersects(linePoint.getBounds2D());
|
465 |
if (inter) {
|
466 |
PathIterator iter = geoms[j].getGeneralPath().getPathIterator(
|
467 |
null);
|
468 |
iter.currentSegment(coords); |
469 |
inicio = getPoint(coords[0], coords[1]); |
470 |
|
471 |
iter.next(); |
472 |
iter.currentSegment(coords); |
473 |
fin = getPoint(coords[0], coords[1]); |
474 |
|
475 |
log.debug("Return point with offset");
|
476 |
return MatcherUtils.getPerpendicularPointFromLine(inicio, fin,
|
477 |
linePoint, dist); |
478 |
} |
479 |
} |
480 |
log.debug("Return original point without offset");
|
481 |
return linePoint;
|
482 |
} |
483 |
|
484 |
/**
|
485 |
* get geometry dimension
|
486 |
*
|
487 |
* @param geom
|
488 |
* @return
|
489 |
*/
|
490 |
public static int getGeometryDimension(Geometry geom) { |
491 |
com.vividsolutions.jts.geom.Geometry geomJTS = Converter |
492 |
.geometryToJts(geom); |
493 |
return geomJTS.getDimension();
|
494 |
} |
495 |
|
496 |
/**
|
497 |
* Get point 2D from x and y coordinates
|
498 |
*
|
499 |
* @param x
|
500 |
* @param y
|
501 |
* @return
|
502 |
*/
|
503 |
public static Point getPoint(double x, double y) { |
504 |
Point pto = null; |
505 |
try {
|
506 |
pto = GeometryLocator.getGeometryManager().createPoint(x, y, |
507 |
Geometry.SUBTYPES.GEOM2D); |
508 |
} catch (LocatorException e) {
|
509 |
log.error("Error getting the geometry locator", e);
|
510 |
return null; |
511 |
} catch (CreateGeometryException e) {
|
512 |
log.error("Error creating geometry", e);
|
513 |
return null; |
514 |
} |
515 |
return pto;
|
516 |
} |
517 |
|
518 |
} |