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

Revision 5125, 24.1 KB checked in by Don-vip, 8 weeks ago (diff)

Make polygon centroid computation a public method in Geometry class

  • Property svn:eol-style set to native
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 {@see 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.