source: josm/trunk/src/org/openstreetmap/josm/tools/Geometry.java@ 5266

Last change on this file since 5266 was 5266, checked in by bastiK, 12 years ago

fixed majority of javadoc warnings by replacing "{@see" by "{@link"

  • Property svn:eol-style set to native
File size: 24.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.tools;
3
4import java.awt.geom.Line2D;
5import java.math.BigDecimal;
6import java.math.MathContext;
7import java.util.ArrayList;
8import java.util.Comparator;
9import java.util.HashSet;
10import java.util.LinkedHashSet;
11import java.util.List;
12import java.util.Set;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.command.AddCommand;
16import org.openstreetmap.josm.command.ChangeCommand;
17import org.openstreetmap.josm.command.Command;
18import org.openstreetmap.josm.data.coor.EastNorth;
19import org.openstreetmap.josm.data.coor.LatLon;
20import org.openstreetmap.josm.data.osm.BBox;
21import org.openstreetmap.josm.data.osm.Node;
22import org.openstreetmap.josm.data.osm.NodePositionComparator;
23import org.openstreetmap.josm.data.osm.Way;
24
25/**
26 * Some tools for geometry related tasks.
27 *
28 * @author viesturs
29 */
30public class Geometry {
31 public enum PolygonIntersection {FIRST_INSIDE_SECOND, SECOND_INSIDE_FIRST, OUTSIDE, CROSSING}
32
33 /**
34 * Will find all intersection and add nodes there for list of given ways. Handles self-intersections too.
35 * And make commands to add the intersection points to ways.
36 * @param List<Way> - a list of ways to test
37 * @return ArrayList<Node> List of new nodes
38 * Prerequisite: no two nodes have the same coordinates.
39 */
40 public static Set<Node> addIntersections(List<Way> ways, boolean test, List<Command> cmds) {
41
42 //stupid java, cannot instantiate array of generic classes..
43 @SuppressWarnings("unchecked")
44 ArrayList<Node>[] newNodes = new ArrayList[ways.size()];
45 BBox[] wayBounds = new BBox[ways.size()];
46 boolean[] changedWays = new boolean[ways.size()];
47
48 Set<Node> intersectionNodes = new LinkedHashSet<Node>();
49
50 //copy node arrays for local usage.
51 for (int pos = 0; pos < ways.size(); pos ++) {
52 newNodes[pos] = new ArrayList<Node>(ways.get(pos).getNodes());
53 wayBounds[pos] = getNodesBounds(newNodes[pos]);
54 changedWays[pos] = false;
55 }
56
57 //iterate over all way pairs and introduce the intersections
58 Comparator<Node> coordsComparator = new NodePositionComparator();
59
60 WayLoop: for (int seg1Way = 0; seg1Way < ways.size(); seg1Way ++) {
61 for (int seg2Way = seg1Way; seg2Way < ways.size(); seg2Way ++) {
62
63 //do not waste time on bounds that do not intersect
64 if (!wayBounds[seg1Way].intersects(wayBounds[seg2Way])) {
65 continue;
66 }
67
68 ArrayList<Node> way1Nodes = newNodes[seg1Way];
69 ArrayList<Node> way2Nodes = newNodes[seg2Way];
70
71 //iterate over primary segmemt
72 for (int seg1Pos = 0; seg1Pos + 1 < way1Nodes.size(); seg1Pos ++) {
73
74 //iterate over secondary segment
75 int seg2Start = seg1Way != seg2Way ? 0: seg1Pos + 2;//skip the adjacent segment
76
77 for (int seg2Pos = seg2Start; seg2Pos + 1< way2Nodes.size(); seg2Pos ++) {
78
79 //need to get them again every time, because other segments may be changed
80 Node seg1Node1 = way1Nodes.get(seg1Pos);
81 Node seg1Node2 = way1Nodes.get(seg1Pos + 1);
82 Node seg2Node1 = way2Nodes.get(seg2Pos);
83 Node seg2Node2 = way2Nodes.get(seg2Pos + 1);
84
85 int commonCount = 0;
86 //test if we have common nodes to add.
87 if (seg1Node1 == seg2Node1 || seg1Node1 == seg2Node2) {
88 commonCount ++;
89
90 if (seg1Way == seg2Way &&
91 seg1Pos == 0 &&
92 seg2Pos == way2Nodes.size() -2) {
93 //do not add - this is first and last segment of the same way.
94 } else {
95 intersectionNodes.add(seg1Node1);
96 }
97 }
98
99 if (seg1Node2 == seg2Node1 || seg1Node2 == seg2Node2) {
100 commonCount ++;
101
102 intersectionNodes.add(seg1Node2);
103 }
104
105 //no common nodes - find intersection
106 if (commonCount == 0) {
107 EastNorth intersection = getSegmentSegmentIntersection(
108 seg1Node1.getEastNorth(), seg1Node2.getEastNorth(),
109 seg2Node1.getEastNorth(), seg2Node2.getEastNorth());
110
111 if (intersection != null) {
112 if (test) {
113 intersectionNodes.add(seg2Node1);
114 return intersectionNodes;
115 }
116
117 Node newNode = new Node(Main.getProjection().eastNorth2latlon(intersection));
118 Node intNode = newNode;
119 boolean insertInSeg1 = false;
120 boolean insertInSeg2 = false;
121
122 //find if the intersection point is at end point of one of the segments, if so use that point
123
124 //segment 1
125 if (coordsComparator.compare(newNode, seg1Node1) == 0) {
126 intNode = seg1Node1;
127 } else if (coordsComparator.compare(newNode, seg1Node2) == 0) {
128 intNode = seg1Node2;
129 } else {
130 insertInSeg1 = true;
131 }
132
133 //segment 2
134 if (coordsComparator.compare(newNode, seg2Node1) == 0) {
135 intNode = seg2Node1;
136 } else if (coordsComparator.compare(newNode, seg2Node2) == 0) {
137 intNode = seg2Node2;
138 } else {
139 insertInSeg2 = true;
140 }
141
142 if (insertInSeg1) {
143 way1Nodes.add(seg1Pos +1, intNode);
144 changedWays[seg1Way] = true;
145
146 //fix seg2 position, as indexes have changed, seg2Pos is always bigger than seg1Pos on the same segment.
147 if (seg2Way == seg1Way) {
148 seg2Pos ++;
149 }
150 }
151
152 if (insertInSeg2) {
153 way2Nodes.add(seg2Pos +1, intNode);
154 changedWays[seg2Way] = true;
155
156 //Do not need to compare again to already split segment
157 seg2Pos ++;
158 }
159
160 intersectionNodes.add(intNode);
161
162 if (intNode == newNode) {
163 cmds.add(new AddCommand(intNode));
164 }
165 }
166 }
167 else if (test && intersectionNodes.size() > 0)
168 return intersectionNodes;
169 }
170 }
171 }
172 }
173
174
175 for (int pos = 0; pos < ways.size(); pos ++) {
176 if (changedWays[pos] == false) {
177 continue;
178 }
179
180 Way way = ways.get(pos);
181 Way newWay = new Way(way);
182 newWay.setNodes(newNodes[pos]);
183
184 cmds.add(new ChangeCommand(way, newWay));
185 }
186
187 return intersectionNodes;
188 }
189
190 private static BBox getNodesBounds(ArrayList<Node> nodes) {
191
192 BBox bounds = new BBox(nodes.get(0));
193 for(Node n: nodes) {
194 bounds.add(n.getCoor());
195 }
196 return bounds;
197 }
198
199 /**
200 * Tests if given point is to the right side of path consisting of 3 points.
201 * @param lineP1 first point in path
202 * @param lineP2 second point in path
203 * @param lineP3 third point in path
204 * @param testPoint
205 * @return true if to the right side, false otherwise
206 */
207 public static boolean isToTheRightSideOfLine(Node lineP1, Node lineP2, Node lineP3, Node testPoint) {
208 boolean pathBendToRight = angleIsClockwise(lineP1, lineP2, lineP3);
209 boolean rightOfSeg1 = angleIsClockwise(lineP1, lineP2, testPoint);
210 boolean rightOfSeg2 = angleIsClockwise(lineP2, lineP3, testPoint);
211
212 if (pathBendToRight)
213 return rightOfSeg1 && rightOfSeg2;
214 else
215 return !(!rightOfSeg1 && !rightOfSeg2);
216 }
217
218 /**
219 * This method tests if secondNode is clockwise to first node.
220 * @param commonNode starting point for both vectors
221 * @param firstNode first vector end node
222 * @param secondNode second vector end node
223 * @return true if first vector is clockwise before second vector.
224 */
225 public static boolean angleIsClockwise(Node commonNode, Node firstNode, Node secondNode) {
226 return angleIsClockwise(commonNode.getEastNorth(), firstNode.getEastNorth(), secondNode.getEastNorth());
227 }
228
229 /**
230 * Finds the intersection of two line segments
231 * @return EastNorth null if no intersection was found, the EastNorth coordinates of the intersection otherwise
232 */
233 public static EastNorth getSegmentSegmentIntersection(
234 EastNorth p1, EastNorth p2,
235 EastNorth p3, EastNorth p4) {
236 double x1 = p1.getX();
237 double y1 = p1.getY();
238 double x2 = p2.getX();
239 double y2 = p2.getY();
240 double x3 = p3.getX();
241 double y3 = p3.getY();
242 double x4 = p4.getX();
243 double y4 = p4.getY();
244
245 //TODO: do this locally.
246 if (!Line2D.linesIntersect(x1, y1, x2, y2, x3, y3, x4, y4)) return null;
247
248 // Convert line from (point, point) form to ax+by=c
249 double a1 = y2 - y1;
250 double b1 = x1 - x2;
251 double c1 = x2*y1 - x1*y2;
252
253 double a2 = y4 - y3;
254 double b2 = x3 - x4;
255 double c2 = x4*y3 - x3*y4;
256
257 // Solve the equations
258 double det = a1*b2 - a2*b1;
259 if (det == 0) return null; // Lines are parallel
260
261 double x = (b1*c2 - b2*c1)/det;
262 double y = (a2*c1 -a1*c2)/det;
263
264 return new EastNorth(x, y);
265 }
266
267 /**
268 * Finds the intersection of two lines of infinite length.
269 * @return EastNorth null if no intersection was found, the coordinates of the intersection otherwise
270 */
271 public static EastNorth getLineLineIntersection(EastNorth p1, EastNorth p2, EastNorth p3, EastNorth p4) {
272
273 // Convert line from (point, point) form to ax+by=c
274 double a1 = p2.getY() - p1.getY();
275 double b1 = p1.getX() - p2.getX();
276 double c1 = p2.getX() * p1.getY() - p1.getX() * p2.getY();
277
278 double a2 = p4.getY() - p3.getY();
279 double b2 = p3.getX() - p4.getX();
280 double c2 = p4.getX() * p3.getY() - p3.getX() * p4.getY();
281
282 // Solve the equations
283 double det = a1 * b2 - a2 * b1;
284 if (det == 0)
285 return null; // Lines are parallel
286
287 return new EastNorth((b1 * c2 - b2 * c1) / det, (a2 * c1 - a1 * c2) / det);
288 }
289
290 public static boolean segmentsParallel(EastNorth p1, EastNorth p2, EastNorth p3, EastNorth p4) {
291 // Convert line from (point, point) form to ax+by=c
292 double a1 = p2.getY() - p1.getY();
293 double b1 = p1.getX() - p2.getX();
294
295 double a2 = p4.getY() - p3.getY();
296 double b2 = p3.getX() - p4.getX();
297
298 // Solve the equations
299 double det = a1 * b2 - a2 * b1;
300 // remove influence of of scaling factor
301 det /= Math.sqrt(a1*a1 + b1*b1) * Math.sqrt(a2*a2 + b2*b2);
302 return Math.abs(det) < 1e-3;
303 }
304
305 /**
306 * Calculates closest point to a line segment.
307 * @param segmentP1
308 * @param segmentP2
309 * @param point
310 * @return segmentP1 if it is the closest point, segmentP2 if it is the closest point,
311 * a new point if closest point is between segmentP1 and segmentP2.
312 */
313 public static EastNorth closestPointToSegment(EastNorth segmentP1, EastNorth segmentP2, EastNorth point) {
314
315 double ldx = segmentP2.getX() - segmentP1.getX();
316 double ldy = segmentP2.getY() - segmentP1.getY();
317
318 if (ldx == 0 && ldy == 0) //segment zero length
319 return segmentP1;
320
321 double pdx = point.getX() - segmentP1.getX();
322 double pdy = point.getY() - segmentP1.getY();
323
324 double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy);
325
326 if (offset <= 0)
327 return segmentP1;
328 else if (offset >= 1)
329 return segmentP2;
330 else
331 return new EastNorth(segmentP1.getX() + ldx * offset, segmentP1.getY() + ldy * offset);
332 }
333
334 public static EastNorth closestPointToLine(EastNorth lineP1, EastNorth lineP2, EastNorth point) {
335 double ldx = lineP2.getX() - lineP1.getX();
336 double ldy = lineP2.getY() - lineP1.getY();
337
338 if (ldx == 0 && ldy == 0) //segment zero length
339 return lineP1;
340
341 double pdx = point.getX() - lineP1.getX();
342 double pdy = point.getY() - lineP1.getY();
343
344 double offset = (pdx * ldx + pdy * ldy) / (ldx * ldx + ldy * ldy);
345 return new EastNorth(lineP1.getX() + ldx * offset, lineP1.getY() + ldy * offset);
346 }
347
348 /**
349 * This method tests if secondNode is clockwise to first node.
350 * @param commonNode starting point for both vectors
351 * @param firstNode first vector end node
352 * @param secondNode second vector end node
353 * @return true if first vector is clockwise before second vector.
354 */
355 public static boolean angleIsClockwise(EastNorth commonNode, EastNorth firstNode, EastNorth secondNode) {
356 double dy1 = (firstNode.getY() - commonNode.getY());
357 double dy2 = (secondNode.getY() - commonNode.getY());
358 double dx1 = (firstNode.getX() - commonNode.getX());
359 double dx2 = (secondNode.getX() - commonNode.getX());
360
361 return dy1 * dx2 - dx1 * dy2 > 0;
362 }
363
364 /**
365 * Tests if two polygons intersect.
366 * @param first
367 * @param second
368 * @return intersection kind
369 * TODO: test segments, not only points
370 * TODO: is O(N*M), should use sweep for better performance.
371 */
372 public static PolygonIntersection polygonIntersection(List<Node> first, List<Node> second) {
373 Set<Node> firstSet = new HashSet<Node>(first);
374 Set<Node> secondSet = new HashSet<Node>(second);
375
376 int nodesInsideSecond = 0;
377 int nodesOutsideSecond = 0;
378 int nodesInsideFirst = 0;
379 int nodesOutsideFirst = 0;
380
381 for (Node insideNode : first) {
382 if (secondSet.contains(insideNode)) {
383 continue;
384 //ignore touching nodes.
385 }
386
387 if (nodeInsidePolygon(insideNode, second)) {
388 nodesInsideSecond ++;
389 }
390 else {
391 nodesOutsideSecond ++;
392 }
393 }
394
395 for (Node insideNode : second) {
396 if (firstSet.contains(insideNode)) {
397 continue;
398 //ignore touching nodes.
399 }
400
401 if (nodeInsidePolygon(insideNode, first)) {
402 nodesInsideFirst ++;
403 }
404 else {
405 nodesOutsideFirst ++;
406 }
407 }
408
409 if (nodesInsideFirst == 0) {
410 if (nodesInsideSecond == 0){
411 if (nodesOutsideFirst + nodesInsideSecond > 0)
412 return PolygonIntersection.OUTSIDE;
413 else
414 //all nodes common
415 return PolygonIntersection.CROSSING;
416 } else
417 return PolygonIntersection.FIRST_INSIDE_SECOND;
418 }
419 else
420 {
421 if (nodesInsideSecond == 0)
422 return PolygonIntersection.SECOND_INSIDE_FIRST;
423 else
424 return PolygonIntersection.CROSSING;
425 }
426 }
427
428 /**
429 * Tests if point is inside a polygon. The polygon can be self-intersecting. In such case the contains function works in xor-like manner.
430 * @param polygonNodes list of nodes from polygon path.
431 * @param point the point to test
432 * @return true if the point is inside polygon.
433 */
434 public static boolean nodeInsidePolygon(Node point, List<Node> polygonNodes) {
435 if (polygonNodes.size() < 2)
436 return false;
437
438 boolean inside = false;
439 Node p1, p2;
440
441 //iterate each side of the polygon, start with the last segment
442 Node oldPoint = polygonNodes.get(polygonNodes.size() - 1);
443
444 for (Node newPoint : polygonNodes) {
445 //skip duplicate points
446 if (newPoint.equals(oldPoint)) {
447 continue;
448 }
449
450 //order points so p1.lat <= p2.lat;
451 if (newPoint.getEastNorth().getY() > oldPoint.getEastNorth().getY()) {
452 p1 = oldPoint;
453 p2 = newPoint;
454 } else {
455 p1 = newPoint;
456 p2 = oldPoint;
457 }
458
459 //test if the line is crossed and if so invert the inside flag.
460 if ((newPoint.getEastNorth().getY() < point.getEastNorth().getY()) == (point.getEastNorth().getY() <= oldPoint.getEastNorth().getY())
461 && (point.getEastNorth().getX() - p1.getEastNorth().getX()) * (p2.getEastNorth().getY() - p1.getEastNorth().getY())
462 < (p2.getEastNorth().getX() - p1.getEastNorth().getX()) * (point.getEastNorth().getY() - p1.getEastNorth().getY()))
463 {
464 inside = !inside;
465 }
466
467 oldPoint = newPoint;
468 }
469
470 return inside;
471 }
472
473 /**
474 * returns area of a closed way in square meters
475 * (approximate(?), but should be OK for small areas)
476 */
477 public static double closedWayArea(Way way) {
478
479 //http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
480 double area = 0;
481 Node lastN = null;
482 for (Node n : way.getNodes()) {
483 if (lastN != null) {
484 n.getEastNorth().getX();
485
486 area += (calcX(n) * calcY(lastN)) - (calcY(n) * calcX(lastN));
487 }
488 lastN = n;
489 }
490 return Math.abs(area/2);
491 }
492
493 protected static double calcX(Node p1){
494 double lat1, lon1, lat2, lon2;
495 double dlon, dlat;
496
497 lat1 = p1.getCoor().lat() * Math.PI / 180.0;
498 lon1 = p1.getCoor().lon() * Math.PI / 180.0;
499 lat2 = lat1;
500 lon2 = 0;
501
502 dlon = lon2 - lon1;
503 dlat = lat2 - lat1;
504
505 double a = (Math.pow(Math.sin(dlat/2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2), 2));
506 double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
507 return 6367000 * c;
508 }
509
510 protected static double calcY(Node p1){
511 double lat1, lon1, lat2, lon2;
512 double dlon, dlat;
513
514 lat1 = p1.getCoor().lat() * Math.PI / 180.0;
515 lon1 = p1.getCoor().lon() * Math.PI / 180.0;
516 lat2 = 0;
517 lon2 = lon1;
518
519 dlon = lon2 - lon1;
520 dlat = lat2 - lat1;
521
522 double a = (Math.pow(Math.sin(dlat/2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2), 2));
523 double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
524 return 6367000 * c;
525 }
526
527 /**
528 * Determines whether a way is oriented clockwise.
529 *
530 * Internals: Assuming a closed non-looping way, compute twice the area
531 * of the polygon using the formula {@code 2 * area = sum (X[n] * Y[n+1] - X[n+1] * Y[n])}.
532 * If the area is negative the way is ordered in a clockwise direction.
533 *
534 * @param w the way to be checked.
535 * @return true if and only if way is oriented clockwise.
536 * @throws IllegalArgumentException if way is not closed (see {@link Way#isClosed}).
537 * @see http://paulbourke.net/geometry/polyarea/
538 */
539 public static boolean isClockwise(Way w) {
540 if (!w.isClosed()) {
541 throw new IllegalArgumentException("Way must be closed to check orientation.");
542 }
543
544 double area2 = 0.;
545 int nodesCount = w.getNodesCount();
546
547 for (int node = 1; node <= /*sic! consider last-first as well*/ nodesCount; node++) {
548 LatLon coorPrev = w.getNode(node - 1).getCoor();
549 LatLon coorCurr = w.getNode(node % nodesCount).getCoor();
550 area2 += coorPrev.lon() * coorCurr.lat();
551 area2 -= coorCurr.lon() * coorPrev.lat();
552 }
553 return area2 < 0;
554 }
555
556 /**
557 * Returns angle of a segment defined with 2 point coordinates.
558 *
559 * @param p1
560 * @param p2
561 * @return Angle in radians (-pi, pi]
562 */
563 public static double getSegmentAngle(EastNorth p1, EastNorth p2) {
564 return Math.atan2(p2.north() - p1.north(), p2.east() - p1.east());
565 }
566
567 /**
568 * Returns angle of a corner defined with 3 point coordinates.
569 *
570 * @param p1
571 * @param p2 Common endpoint
572 * @param p3
573 * @return Angle in radians (-pi, pi]
574 */
575 public static double getCornerAngle(EastNorth p1, EastNorth p2, EastNorth p3) {
576 Double result = getSegmentAngle(p2, p1) - getSegmentAngle(p2, p3);
577 if (result <= -Math.PI) {
578 result += 2 * Math.PI;
579 }
580
581 if (result > Math.PI) {
582 result -= 2 * Math.PI;
583 }
584
585 return result;
586 }
587
588 public static EastNorth getCentroid(List<Node> nodes) {
589 // Compute the centroid of nodes
590
591 BigDecimal area = new BigDecimal(0);
592 BigDecimal north = new BigDecimal(0);
593 BigDecimal east = new BigDecimal(0);
594
595 // See http://en.wikipedia.org/w/index.php?title=Centroid&oldid=294224857#Centroid_of_polygon for the equation used here
596 for (int i = 0; i < nodes.size(); i++) {
597 EastNorth n0 = nodes.get(i).getEastNorth();
598 EastNorth n1 = nodes.get((i+1) % nodes.size()).getEastNorth();
599
600 BigDecimal x0 = new BigDecimal(n0.east());
601 BigDecimal y0 = new BigDecimal(n0.north());
602 BigDecimal x1 = new BigDecimal(n1.east());
603 BigDecimal y1 = new BigDecimal(n1.north());
604
605 BigDecimal k = x0.multiply(y1, MathContext.DECIMAL128).subtract(y0.multiply(x1, MathContext.DECIMAL128));
606
607 area = area.add(k, MathContext.DECIMAL128);
608 east = east.add(k.multiply(x0.add(x1, MathContext.DECIMAL128), MathContext.DECIMAL128));
609 north = north.add(k.multiply(y0.add(y1, MathContext.DECIMAL128), MathContext.DECIMAL128));
610 }
611
612 BigDecimal d = new BigDecimal(3, MathContext.DECIMAL128); // 1/2 * 6 = 3
613 area = area.multiply(d, MathContext.DECIMAL128);
614 north = north.divide(area, MathContext.DECIMAL128);
615 east = east.divide(area, MathContext.DECIMAL128);
616
617 return new EastNorth(east.doubleValue(), north.doubleValue());
618 }
619
620 /**
621 * Returns the coordinate of intersection of segment sp1-sp2 and an altitude
622 * to it starting at point ap. If the line defined with sp1-sp2 intersects
623 * its altitude out of sp1-sp2, null is returned.
624 *
625 * @param sp1
626 * @param sp2
627 * @param ap
628 * @return Intersection coordinate or null
629 */
630 public static EastNorth getSegmentAltituteIntersection(EastNorth sp1,
631 EastNorth sp2, EastNorth ap) {
632 Double segmentLenght = sp1.distance(sp2);
633 Double altitudeAngle = getSegmentAngle(sp1, sp2) + Math.PI / 2;
634
635 // Taking a random point on the altitude line (angle is known).
636 EastNorth ap2 = new EastNorth(ap.east() + 1000
637 * Math.cos(altitudeAngle), ap.north() + 1000
638 * Math.sin(altitudeAngle));
639
640 // Finding the intersection of two lines
641 EastNorth resultCandidate = Geometry.getLineLineIntersection(sp1, sp2,
642 ap, ap2);
643
644 // Filtering result
645 if (resultCandidate != null
646 && resultCandidate.distance(sp1) * .999 < segmentLenght
647 && resultCandidate.distance(sp2) * .999 < segmentLenght) {
648 return resultCandidate;
649 } else {
650 return null;
651 }
652 }
653}
Note: See TracBrowser for help on using the repository browser.