1 /**********************************************************************
4 * GEOS - Geometry Engine Open Source
5 * http://geos.refractions.net
7 * Copyright (C) 2001-2002 Vivid Solutions Inc.
9 * This is free software; you can redistribute and/or modify it under
10 * the terms of the GNU Lesser General Public Licence as published
11 * by the Free Software Foundation.
12 * See the COPYING file for more information.
14 **********************************************************************/
16 #include <geos/geosAlgorithm.h>
17 #include <geos/util.h>
26 namespace algorithm
{ // geos.algorithm
28 RobustLineIntersector::RobustLineIntersector(){}
29 RobustLineIntersector::~RobustLineIntersector(){}
32 RobustLineIntersector::computeIntersection(const Coordinate
& p
,const Coordinate
& p1
,const Coordinate
& p2
)
36 // do between check first, since it is faster than the orientation test
37 if(Envelope::intersects(p1
,p2
,p
)) {
38 if ((CGAlgorithms::orientationIndex(p1
,p2
,p
)==0)&&
39 (CGAlgorithms::orientationIndex(p2
,p1
,p
)==0)) {
41 if ((p
==p1
)||(p
==p2
)) // 2d only test
46 intPt
[0].setCoordinate(p
);
48 cerr
<<"RobustIntersector::computeIntersection(Coordinate,Coordinate,Coordinate) calling interpolateZ"<<endl
;
50 double z
= interpolateZ(p
, p1
, p2
);
53 if ( ISNAN(intPt
[0].z
) )
56 intPt
[0].z
= (intPt
[0].z
+z
)/2;
63 result
= DONT_INTERSECT
;
67 RobustLineIntersector::computeIntersect(const Coordinate
& p1
,const Coordinate
& p2
,const Coordinate
& q1
,const Coordinate
& q2
)
70 cerr
<<"RobustLineIntersector::computeIntersect called"<<endl
;
71 cerr
<<" p1:"<<p1
.toString()<<" p2:"<<p2
.toString()<<" q1:"<<q1
.toString()<<" q2:"<<q2
.toString()<<endl
;
76 // first try a fast test to see if the envelopes of the lines intersect
77 if (!Envelope::intersects(p1
,p2
,q1
,q2
))
80 cerr
<<" DONT_INTERSECT"<<endl
;
82 return DONT_INTERSECT
;
85 // for each endpoint, compute which side of the other segment it lies
86 // if both endpoints lie on the same side of the other segment,
87 // the segments do not intersect
88 int Pq1
=CGAlgorithms::orientationIndex(p1
,p2
,q1
);
89 int Pq2
=CGAlgorithms::orientationIndex(p1
,p2
,q2
);
91 if ((Pq1
>0 && Pq2
>0) || (Pq1
<0 && Pq2
<0))
94 cerr
<<" DONT_INTERSECT"<<endl
;
96 return DONT_INTERSECT
;
99 int Qp1
=CGAlgorithms::orientationIndex(q1
,q2
,p1
);
100 int Qp2
=CGAlgorithms::orientationIndex(q1
,q2
,p2
);
102 if ((Qp1
>0 && Qp2
>0)||(Qp1
<0 && Qp2
<0)) {
104 cerr
<<" DONT_INTERSECT"<<endl
;
106 return DONT_INTERSECT
;
109 bool collinear
=Pq1
==0 && Pq2
==0 && Qp1
==0 && Qp2
==0;
112 cerr
<<" computingCollinearIntersection"<<endl
;
114 return computeCollinearIntersection(p1
,p2
,q1
,q2
);
118 * Check if the intersection is an endpoint.
119 * If it is, copy the endpoint as
120 * the intersection point. Copying the point rather than
121 * computing it ensures the point has the exact value,
122 * which is important for robustness. It is sufficient to
123 * simply check for an endpoint which is on the other line,
124 * since at this point we know that the inputLines must
127 if (Pq1
==0 || Pq2
==0 || Qp1
==0 || Qp2
==0) {
134 intPt
[0].setCoordinate(q1
);
144 intPt
[0].setCoordinate(q2
);
154 intPt
[0].setCoordinate(p1
);
164 intPt
[0].setCoordinate(p2
);
175 cerr
<<"RobustLineIntersector::computeIntersect: z:"<<z
<<" hits:"<<hits
<<endl
;
177 if ( hits
) intPt
[0].z
= z
/hits
;
181 Coordinate
*c
=intersection(p1
, p2
, q1
, q2
);
182 intPt
[0].setCoordinate(*c
);
186 cerr
<<" DO_INTERSECT; intPt[0]:"<<intPt
[0].toString()<<endl
;
191 //bool RobustLineIntersector::intersectsEnvelope(Coordinate& p1,Coordinate& p2,Coordinate& q) {
192 // if (((q.x>=min(p1.x,p2.x)) && (q.x<=max(p1.x,p2.x))) &&
193 // ((q.y>=min(p1.y,p2.y)) && (q.y<=max(p1.y,p2.y)))) {
201 RobustLineIntersector::computeCollinearIntersection(const Coordinate
& p1
,const Coordinate
& p2
,const Coordinate
& q1
,const Coordinate
& q2
)
213 cerr
<<"RobustLineIntersector::computeCollinearIntersection called"<<endl
;
214 cerr
<<" p1:"<<p1
.toString()<<" p2:"<<p2
.toString()<<" q1:"<<q1
.toString()<<" q2:"<<q2
.toString()<<endl
;
217 bool p1q1p2
=Envelope::intersects(p1
,p2
,q1
);
218 bool p1q2p2
=Envelope::intersects(p1
,p2
,q2
);
219 bool q1p1q2
=Envelope::intersects(q1
,q2
,p1
);
220 bool q1p2q2
=Envelope::intersects(q1
,q2
,p2
);
222 if (p1q1p2
&& p1q2p2
) {
224 cerr
<<" p1q1p2 && p1q2p2"<<endl
;
226 intPt
[0].setCoordinate(q1
);
230 q1z
= interpolateZ(q1
, p1
, p2
);
231 if (!ISNAN(q1z
)) { ztot
+=q1z
; hits
++; }
232 if (!ISNAN(q1
.z
)) { ztot
+=q1
.z
; hits
++; }
233 if ( hits
) intPt
[0].z
= ztot
/hits
;
235 intPt
[1].setCoordinate(q2
);
239 q2z
= interpolateZ(q2
, p1
, p2
);
240 if (!ISNAN(q2z
)) { ztot
+=q2z
; hits
++; }
241 if (!ISNAN(q2
.z
)) { ztot
+=q2
.z
; hits
++; }
242 if ( hits
) intPt
[1].z
= ztot
/hits
;
245 cerr
<<" intPt[0]: "<<intPt
[0].toString()<<endl
;
246 cerr
<<" intPt[1]: "<<intPt
[1].toString()<<endl
;
250 if (q1p1q2
&& q1p2q2
) {
252 cerr
<<" q1p1q2 && q1p2q2"<<endl
;
254 intPt
[0].setCoordinate(p1
);
258 p1z
= interpolateZ(p1
, q1
, q2
);
259 if (!ISNAN(p1z
)) { ztot
+=p1z
; hits
++; }
260 if (!ISNAN(p1
.z
)) { ztot
+=p1
.z
; hits
++; }
261 if ( hits
) intPt
[0].z
= ztot
/hits
;
263 intPt
[1].setCoordinate(p2
);
267 p2z
= interpolateZ(p2
, q1
, q2
);
268 if (!ISNAN(p2z
)) { ztot
+=p2z
; hits
++; }
269 if (!ISNAN(p2
.z
)) { ztot
+=p2
.z
; hits
++; }
270 if ( hits
) intPt
[1].z
= ztot
/hits
;
274 if (p1q1p2
&& q1p1q2
) {
276 cerr
<<" p1q1p2 && q1p1q2"<<endl
;
278 intPt
[0].setCoordinate(q1
);
282 q1z
= interpolateZ(q1
, p1
, p2
);
283 if (!ISNAN(q1z
)) { ztot
+=q1z
; hits
++; }
284 if (!ISNAN(q1
.z
)) { ztot
+=q1
.z
; hits
++; }
285 if ( hits
) intPt
[0].z
= ztot
/hits
;
287 intPt
[1].setCoordinate(p1
);
291 p1z
= interpolateZ(p1
, q1
, q2
);
292 if (!ISNAN(p1z
)) { ztot
+=p1z
; hits
++; }
293 if (!ISNAN(p1
.z
)) { ztot
+=p1
.z
; hits
++; }
294 if ( hits
) intPt
[1].z
= ztot
/hits
;
297 cerr
<<" intPt[0]: "<<intPt
[0].toString()<<endl
;
298 cerr
<<" intPt[1]: "<<intPt
[1].toString()<<endl
;
300 return (q1
==p1
) && !p1q2p2
&& !q1p2q2
? DO_INTERSECT
: COLLINEAR
;
302 if (p1q1p2
&& q1p2q2
) {
304 cerr
<<" p1q1p2 && q1p2q2"<<endl
;
306 intPt
[0].setCoordinate(q1
);
310 q1z
= interpolateZ(q1
, p1
, p2
);
311 if (!ISNAN(q1z
)) { ztot
+=q1z
; hits
++; }
312 if (!ISNAN(q1
.z
)) { ztot
+=q1
.z
; hits
++; }
313 if ( hits
) intPt
[0].z
= ztot
/hits
;
315 intPt
[1].setCoordinate(p2
);
319 p2z
= interpolateZ(p2
, q1
, q2
);
320 if (!ISNAN(p2z
)) { ztot
+=p2z
; hits
++; }
321 if (!ISNAN(p2
.z
)) { ztot
+=p2
.z
; hits
++; }
322 if ( hits
) intPt
[1].z
= ztot
/hits
;
325 cerr
<<" intPt[0]: "<<intPt
[0].toString()<<endl
;
326 cerr
<<" intPt[1]: "<<intPt
[1].toString()<<endl
;
328 return (q1
==p2
) && !p1q2p2
&& !q1p1q2
? DO_INTERSECT
: COLLINEAR
;
330 if (p1q2p2
&& q1p1q2
) {
332 cerr
<<" p1q2p2 && q1p1q2"<<endl
;
334 intPt
[0].setCoordinate(q2
);
338 q2z
= interpolateZ(q2
, p1
, p2
);
339 if (!ISNAN(q2z
)) { ztot
+=q2z
; hits
++; }
340 if (!ISNAN(q2
.z
)) { ztot
+=q2
.z
; hits
++; }
341 if ( hits
) intPt
[0].z
= ztot
/hits
;
343 intPt
[1].setCoordinate(p1
);
347 p1z
= interpolateZ(p1
, q1
, q2
);
348 if (!ISNAN(p1z
)) { ztot
+=p1z
; hits
++; }
349 if (!ISNAN(p1
.z
)) { ztot
+=p1
.z
; hits
++; }
350 if ( hits
) intPt
[1].z
= ztot
/hits
;
353 cerr
<<" intPt[0]: "<<intPt
[0].toString()<<endl
;
354 cerr
<<" intPt[1]: "<<intPt
[1].toString()<<endl
;
356 return (q2
==p1
) && !p1q1p2
&& !q1p2q2
? DO_INTERSECT
: COLLINEAR
;
358 if (p1q2p2
&& q1p2q2
) {
360 cerr
<<" p1q2p2 && q1p2q2"<<endl
;
362 intPt
[0].setCoordinate(q2
);
366 q2z
= interpolateZ(q2
, p1
, p2
);
367 if (!ISNAN(q2z
)) { ztot
+=q2z
; hits
++; }
368 if (!ISNAN(q2
.z
)) { ztot
+=q2
.z
; hits
++; }
369 if ( hits
) intPt
[0].z
= ztot
/hits
;
371 intPt
[1].setCoordinate(p2
);
375 p2z
= interpolateZ(p2
, q1
, q2
);
376 if (!ISNAN(p2z
)) { ztot
+=p2z
; hits
++; }
377 if (!ISNAN(p2
.z
)) { ztot
+=p2
.z
; hits
++; }
378 if ( hits
) intPt
[1].z
= ztot
/hits
;
381 cerr
<<" intPt[0]: "<<intPt
[0].toString()<<endl
;
382 cerr
<<" intPt[1]: "<<intPt
[1].toString()<<endl
;
384 return (q2
==p2
) && !p1q1p2
&& !q1p1q2
? DO_INTERSECT
: COLLINEAR
;
386 return DONT_INTERSECT
;
390 RobustLineIntersector::intersection(const Coordinate
& p1
,const Coordinate
& p2
,const Coordinate
& q1
,const Coordinate
& q2
) const
398 //normalize(&n1, &n2, &n3, &n4, &normPt);
399 normalizeToEnvCentre(n1
, n2
, n3
, n4
, normPt
);
401 Coordinate
*intPt
=NULL
;
404 cerr
<<"RobustIntersector::intersection(p1,p2,q1,q2) called:"<<endl
;
405 cerr
<<" p1"<<p1
.toString()<<endl
;
406 cerr
<<" p2"<<p2
.toString()<<endl
;
407 cerr
<<" q1"<<q1
.toString()<<endl
;
408 cerr
<<" q2"<<q2
.toString()<<endl
;
410 cerr
<<" n1"<<n1
.toString()<<endl
;
411 cerr
<<" n2"<<n2
.toString()<<endl
;
412 cerr
<<" n3"<<n3
.toString()<<endl
;
413 cerr
<<" n4"<<n4
.toString()<<endl
;
417 intPt
=HCoordinate::intersection(n1
,n2
,n3
,n4
);
419 cerr
<<" HCoordinate found intersection h:"<<h
->toString()<<endl
;
422 } catch (const NotRepresentableException
& e
) {
424 Assert::shouldNeverReachHere("Coordinate for intersection is not calculable"+e
.toString());
432 * MD - May 4 2005 - This is still a problem. Here is a failure case:
434 * LINESTRING (2089426.5233462777 1180182.3877339689,
435 * 2085646.6891757075 1195618.7333999649)
436 * LINESTRING (1889281.8148903656 1997547.0560044837,
437 * 2259977.3672235999 483675.17050843034)
438 * int point = (2097408.2633752143,1144595.8008114607)
442 if (! isInSegmentEnvelopes(intPt
))
444 cerr
<<"Intersection outside segment envelopes: "<<
449 if (precisionModel
!=NULL
) precisionModel
->makePrecise(intPt
);
455 double zp
= interpolateZ(*intPt
, p1
, p2
);
456 double zq
= interpolateZ(*intPt
, q1
, q2
);
457 if ( !ISNAN(zp
)) { ztot
+= zp
; zvals
++; }
458 if ( !ISNAN(zq
)) { ztot
+= zq
; zvals
++; }
459 if ( zvals
) intPt
->z
= ztot
/zvals
;
467 RobustLineIntersector::normalize(Coordinate
*n1
,Coordinate
*n2
,Coordinate
*n3
,Coordinate
*n4
,Coordinate
*normPt
) const
469 normPt
->x
=smallestInAbsValue(n1
->x
,n2
->x
,n3
->x
,n4
->x
);
470 normPt
->y
=smallestInAbsValue(n1
->y
,n2
->y
,n3
->y
,n4
->y
);
481 normPt
->z
=smallestInAbsValue(n1
->z
,n2
->z
,n3
->z
,n4
->z
);
490 RobustLineIntersector::smallestInAbsValue(double x1
,double x2
,double x3
,double x4
) const
509 * Test whether a point lies in the envelopes of both input segments.
510 * A correctly computed intersection point should return <code>true</code>
512 * Since this test is for debugging purposes only, no attempt is
513 * made to optimize the envelope test.
515 * @return <code>true</code> if the input point lies within both input
519 RobustLineIntersector::isInSegmentEnvelopes(const Coordinate
& intPt
)
521 Envelope
*env0
=new Envelope(*inputLines
[0][0], *inputLines
[0][1]);
522 Envelope
*env1
=new Envelope(*inputLines
[1][0], *inputLines
[1][1]);
523 return env0
->contains(intPt
) && env1
->contains(intPt
);
527 RobustLineIntersector::normalizeToEnvCentre(Coordinate
&n00
, Coordinate
&n01
,
528 Coordinate
&n10
, Coordinate
&n11
, Coordinate
&normPt
) const
530 double minX0
= n00
.x
< n01
.x
? n00
.x
: n01
.x
;
531 double minY0
= n00
.y
< n01
.y
? n00
.y
: n01
.y
;
532 double maxX0
= n00
.x
> n01
.x
? n00
.x
: n01
.x
;
533 double maxY0
= n00
.y
> n01
.y
? n00
.y
: n01
.y
;
535 double minX1
= n10
.x
< n11
.x
? n10
.x
: n11
.x
;
536 double minY1
= n10
.y
< n11
.y
? n10
.y
: n11
.y
;
537 double maxX1
= n10
.x
> n11
.x
? n10
.x
: n11
.x
;
538 double maxY1
= n10
.y
> n11
.y
? n10
.y
: n11
.y
;
540 double intMinX
= minX0
> minX1
? minX0
: minX1
;
541 double intMaxX
= maxX0
< maxX1
? maxX0
: maxX1
;
542 double intMinY
= minY0
> minY1
? minY0
: minY1
;
543 double intMaxY
= maxY0
< maxY1
? maxY0
: maxY1
;
545 double intMidX
= (intMinX
+ intMaxX
) / 2.0;
546 double intMidY
= (intMinY
+ intMaxY
) / 2.0;
551 n00
.x
-= normPt
.x
; n00
.y
-= normPt
.y
;
552 n01
.x
-= normPt
.x
; n01
.y
-= normPt
.y
;
553 n10
.x
-= normPt
.x
; n10
.y
-= normPt
.y
;
554 n11
.x
-= normPt
.x
; n11
.y
-= normPt
.y
;
557 double minZ0
= n00
.z
< n01
.z
? n00
.z
: n01
.z
;
558 double minZ1
= n10
.z
< n11
.z
? n10
.z
: n11
.z
;
559 double maxZ0
= n00
.z
> n01
.z
? n00
.z
: n01
.z
;
560 double maxZ1
= n10
.z
> n11
.z
? n10
.z
: n11
.z
;
561 double intMinZ
= minZ0
> minZ1
? minZ0
: minZ1
;
562 double intMaxZ
= maxZ0
< maxZ1
? maxZ0
: maxZ1
;
563 double intMidZ
= (intMinZ
+ intMaxZ
) / 2.0;
572 } // namespace geos.algorithm
575 /**********************************************************************
577 * Revision 1.36 2006/03/21 11:12:23 strk
578 * Cleanups: headers inclusion and Log section
580 * Revision 1.35 2006/02/19 19:46:49 strk
581 * Packages <-> namespaces mapping for most GEOS internal code (uncomplete, but working). Dir-level libs for index/ subdirs.
582 **********************************************************************/