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