Simplify code and improve consistency of linecrossing results (#272)

git-svn-id: http://svn.osgeo.org/postgis/trunk@4786 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
Paul Ramsey 2009-11-11 19:02:19 +00:00
parent bc01c844b6
commit 6adec1b2be
4 changed files with 294 additions and 325 deletions

View file

@ -29,7 +29,8 @@ CU_pSuite register_cg_suite(void)
(NULL == CU_add_test(pSuite, "test_lw_segment_side()", test_lw_segment_side)) ||
(NULL == CU_add_test(pSuite, "test_lw_segment_intersects()", test_lw_segment_intersects)) ||
(NULL == CU_add_test(pSuite, "test_lwline_crossing_short_lines()", test_lwline_crossing_short_lines)) ||
(NULL == CU_add_test(pSuite, "test_lwline_crossing_long_lines()", test_lwline_crossing_long_lines)) ||
(NULL == CU_add_test(pSuite, "test_lwline_crossing_long_lines()", test_lwline_crossing_long_lines)) ||
(NULL == CU_add_test(pSuite, "test_lwline_crossing_bugs()", test_lwline_crossing_bugs)) ||
(NULL == CU_add_test(pSuite, "test_lwpoint_set_ordinate()", test_lwpoint_set_ordinate)) ||
(NULL == CU_add_test(pSuite, "test_lwpoint_get_ordinate()", test_lwpoint_get_ordinate)) ||
(NULL == CU_add_test(pSuite, "test_lwpoint_interpolate()", test_lwpoint_interpolate)) ||
@ -38,7 +39,7 @@ CU_pSuite register_cg_suite(void)
(NULL == CU_add_test(pSuite, "test_lwmline_clip()", test_lwmline_clip)) ||
(NULL == CU_add_test(pSuite, "test_geohash_point()", test_geohash_point)) ||
(NULL == CU_add_test(pSuite, "test_geohash_precision()", test_geohash_precision)) ||
(NULL == CU_add_test(pSuite, "test_geohash()", test_geohash))
(NULL == CU_add_test(pSuite, "test_geohash()", test_geohash))
)
{
CU_cleanup_registry();
@ -51,20 +52,12 @@ CU_pSuite register_cg_suite(void)
/*
** Global variables used by tests below
*/
POINT2D *p1 = NULL;
POINT2D *p2 = NULL;
POINT2D *q1 = NULL;
POINT2D *q2 = NULL;
POINT4D *p = NULL;
POINT4D *q = NULL;
/* Two-point objects */
POINTARRAY *pa21 = NULL;
POINTARRAY *pa22 = NULL;
LWLINE *l21 = NULL;
LWLINE *l22 = NULL;
/* Five-point objects */
LWLINE *l51 = NULL;
LWLINE *l52 = NULL;
/* Parsing support */
LWGEOM_PARSER_RESULT parse_result;
@ -75,12 +68,6 @@ LWGEOM_PARSER_RESULT parse_result;
*/
int init_cg_suite(void)
{
p = lwalloc(sizeof(POINT4D));
q = lwalloc(sizeof(POINT4D));
p1 = lwalloc(sizeof(POINT2D));
p2 = lwalloc(sizeof(POINT2D));
q1 = lwalloc(sizeof(POINT2D));
q2 = lwalloc(sizeof(POINT2D));
pa21 = ptarray_construct(0, 0, 2);
pa22 = ptarray_construct(0, 0, 2);
l21 = lwline_construct(-1, NULL, pa21);
@ -95,11 +82,6 @@ int init_cg_suite(void)
*/
int clean_cg_suite(void)
{
if ( p ) lwfree(p);
if ( p1 )lwfree(p1);
if ( p2 ) lwfree(p2);
if ( q1 ) lwfree(q1);
if ( q2 ) lwfree(q2);
if ( l21 ) lwline_free(l21);
if ( l22 ) lwline_free(l22);
return 0;
@ -111,36 +93,33 @@ int clean_cg_suite(void)
void test_lw_segment_side(void)
{
double rv = 0.0;
POINT2D *q = NULL;
q = lwalloc(sizeof(POINT2D));
POINT2D p1, p2, q;
/* Vertical line at x=0 */
p1->x = 0.0;
p1->y = 0.0;
p2->x = 0.0;
p2->y = 1.0;
p1.x = 0.0;
p1.y = 0.0;
p2.x = 0.0;
p2.y = 1.0;
/* On the left */
q->x = -2.0;
q->y = 1.5;
q.x = -2.0;
q.y = 1.5;
rv = lw_segment_side(p1, p2, q);
//printf("left %g\n",rv);
CU_ASSERT(rv < 0.0);
/* On the right */
q->x = 2.0;
q.x = 2.0;
rv = lw_segment_side(p1, p2, q);
//printf("right %g\n",rv);
CU_ASSERT(rv > 0.0);
/* On the line */
q->x = 0.0;
q.x = 0.0;
rv = lw_segment_side(p1, p2, q);
//printf("on line %g\n",rv);
CU_ASSERT_EQUAL(rv, 0.0);
lwfree(q);
}
/*
@ -149,189 +128,203 @@ void test_lw_segment_side(void)
void test_lw_segment_intersects(void)
{
#define setpoint(p, x1, y1) {(p).x = (x1); (p).y = (y1);}
POINT2D p1, p2, q1, q2;
/* P: Vertical line at x=0 */
p1->x = 0.0;
p1->y = 0.0;
p2->x = 0.0;
p2->y = 1.0;
setpoint(p1, 0.0, 0.0);
p1.x = 0.0;
p1.y = 0.0;
p2.x = 0.0;
p2.y = 1.0;
/* Q: Horizontal line crossing left to right */
q1->x = -0.5;
q1->y = 0.5;
q2->x = 0.5;
q2->y = 0.5;
q1.x = -0.5;
q1.y = 0.5;
q2.x = 0.5;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_RIGHT );
/* Q: Horizontal line crossing right to left */
q1->x = 0.5;
q1->y = 0.5;
q2->x = -0.5;
q2->y = 0.5;
q1.x = 0.5;
q1.y = 0.5;
q2.x = -0.5;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT );
/* Q: Horizontal line not crossing right to left */
q1->x = 0.5;
q1->y = 1.5;
q2->x = -0.5;
q2->y = 1.5;
q1.x = 0.5;
q1.y = 1.5;
q2.x = -0.5;
q2.y = 1.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION );
/* Q: Horizontal line crossing at vertex right to left */
q1->x = 0.5;
q1->y = 1.0;
q2->x = -0.5;
q2->y = 1.0;
/* Q: Horizontal line crossing at second vertex right to left */
q1.x = 0.5;
q1.y = 1.0;
q2.x = -0.5;
q2.y = 1.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION );
/* Q: Horizontal line crossing at first vertex right to left */
q1.x = 0.5;
q1.y = 0.0;
q2.x = -0.5;
q2.y = 0.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT );
/* Q: Diagonal line with large range crossing at vertex right to left */
q1->x = 0.5;
q1->y = 10.0;
q2->x = -0.5;
q2->y = -10.0;
/* Q: Diagonal line with large range crossing at first vertex right to left */
q1.x = 0.5;
q1.y = 10.0;
q2.x = -0.5;
q2.y = -10.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT );
/* Q: Diagonal line with large range crossing at vertex right to left */
q1->x = 0.5;
q1->y = 11.0;
q2->x = -0.5;
q2->y = -9.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT );
/* Q: Diagonal line with large range crossing at second vertex right to left */
q1.x = 0.5;
q1.y = 11.0;
q2.x = -0.5;
q2.y = -9.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION );
/* Q: Horizontal touching from left */
q1->x = -0.5;
q1->y = 0.5;
q2->x = 0.0;
q2->y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_LEFT );
/* Q: Horizontal touching from left at second vertex*/
q1.x = -0.5;
q1.y = 0.5;
q2.x = 0.0;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION );
/* Q: Horizontal touching from right */
q1->x = 0.5;
q1->y = 0.5;
q2->x = 0.0;
q2->y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_RIGHT );
/* Q: Horizontal touching from right at first vertex */
q1.x = 0.0;
q1.y = 0.5;
q2.x = 0.5;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_RIGHT );
/* Q: Horizontal touching from left and far below*/
q1->x = -0.5;
q1->y = -10.5;
q2->x = 0.0;
q2->y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_LEFT );
/* Q: Horizontal touching from left and far below on second vertex */
q1.x = -0.5;
q1.y = -10.5;
q2.x = 0.0;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION );
/* Q: Horizontal touching from right and far above */
q1->x = 0.5;
q1->y = 10.5;
q2->x = 0.0;
q2->y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_RIGHT );
/* Q: Horizontal touching from right and far above on second vertex */
q1.x = 0.5;
q1.y = 10.5;
q2.x = 0.0;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION );
/* Q: Co-linear from top */
q1->x = 0.0;
q1->y = 10.0;
q2->x = 0.0;
q2->y = 0.5;
q1.x = 0.0;
q1.y = 10.0;
q2.x = 0.0;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR );
/* Q: Co-linear from bottom */
q1->x = 0.0;
q1->y = -10.0;
q2->x = 0.0;
q2->y = 0.5;
q1.x = 0.0;
q1.y = -10.0;
q2.x = 0.0;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR );
/* Q: Co-linear contained */
q1->x = 0.0;
q1->y = 0.4;
q2->x = 0.0;
q2->y = 0.5;
q1.x = 0.0;
q1.y = 0.4;
q2.x = 0.0;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR );
/* Q: Horizontal touching at end point from left */
q1->x = -0.5;
q1->y = 1.0;
q2->x = 0.0;
q2->y = 1.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_LEFT );
q1.x = -0.5;
q1.y = 1.0;
q2.x = 0.0;
q2.y = 1.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION );
/* Q: Horizontal touching at end point from right */
q1->x = 0.5;
q1->y = 1.0;
q2->x = 0.0;
q2->y = 1.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_RIGHT );
q1.x = 0.0;
q1.y = 1.0;
q2.x = 0.0;
q2.y = 0.5;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR );
/* Q: Horizontal touching at start point from left */
q1->x = -0.5;
q1->y = 0.0;
q2->x = 0.0;
q2->y = 0.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_LEFT );
q1.x = 0.0;
q1.y = 0.0;
q2.x = -0.5;
q2.y = 0.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT );
/* Q: Horizontal touching at start point from right */
q1->x = 0.5;
q1->y = 0.0;
q2->x = 0.0;
q2->y = 0.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_RIGHT );
q1.x = 0.0;
q1.y = 0.0;
q2.x = 0.5;
q2.y = 0.0;
CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_RIGHT );
}
void test_lwline_crossing_short_lines(void)
{
POINT4D p;
/*
** Simple test, two two-point lines
*/
/* Vertical line from 0,0 to 1,1 */
p->x = 0.0;
p->y = 0.0;
setPoint4d(pa21, 0, p);
p->y = 1.0;
setPoint4d(pa21, 1, p);
p.x = 0.0;
p.y = 0.0;
setPoint4d(pa21, 0, &p);
p.y = 1.0;
setPoint4d(pa21, 1, &p);
/* Horizontal, crossing mid-segment */
p->x = -0.5;
p->y = 0.5;
setPoint4d(pa22, 0, p);
p->x = 0.5;
setPoint4d(pa22, 1, p);
p.x = -0.5;
p.y = 0.5;
setPoint4d(pa22, 0, &p);
p.x = 0.5;
setPoint4d(pa22, 1, &p);
CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_CROSS_RIGHT );
/* Horizontal, crossing at top end vertex */
p->x = -0.5;
p->y = 1.0;
setPoint4d(pa22, 0, p);
p->x = 0.5;
setPoint4d(pa22, 1, p);
/* Horizontal, crossing at top end vertex (end crossings don't count) */
p.x = -0.5;
p.y = 1.0;
setPoint4d(pa22, 0, &p);
p.x = 0.5;
setPoint4d(pa22, 1, &p);
CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_CROSS_RIGHT );
CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS );
/* Horizontal, crossing at bottom end vertex */
p->x = -0.5;
p->y = 0.0;
setPoint4d(pa22, 0, p);
p->x = 0.5;
setPoint4d(pa22, 1, p);
p.x = -0.5;
p.y = 0.0;
setPoint4d(pa22, 0, &p);
p.x = 0.5;
setPoint4d(pa22, 1, &p);
CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_CROSS_RIGHT );
/* Horizontal, no crossing */
p->x = -0.5;
p->y = 2.0;
setPoint4d(pa22, 0, p);
p->x = 0.5;
setPoint4d(pa22, 1, p);
p.x = -0.5;
p.y = 2.0;
setPoint4d(pa22, 0, &p);
p.x = 0.5;
setPoint4d(pa22, 1, &p);
CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS );
/* Vertical, no crossing */
p->x = -0.5;
p->y = 0.0;
setPoint4d(pa22, 0, p);
p->y = 1.0;
setPoint4d(pa22, 1, p);
p.x = -0.5;
p.y = 0.0;
setPoint4d(pa22, 0, &p);
p.y = 1.0;
setPoint4d(pa22, 1, &p);
CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS );
@ -344,7 +337,6 @@ void test_lwline_crossing_long_lines(void)
/*
** More complex test, longer lines and multiple crossings
*/
/* Vertical line with vertices at y integers */
l51 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(0 0, 0 1, 0 2, 0 3, 0 4)", PARSER_CHECK_NONE);
@ -373,11 +365,6 @@ void test_lwline_crossing_long_lines(void)
CU_ASSERT( lwline_crossing_direction(l51, l52) == LINE_MULTICROSS_END_SAME_FIRST_LEFT );
lwline_free(l52);
/* Two crossings, one at the last vertex on the next interior vertex */
l52 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(1 4, 0 4, -1 3, 0 3, 1 3)", PARSER_CHECK_NONE);
CU_ASSERT( lwline_crossing_direction(l51, l52) == LINE_MULTICROSS_END_SAME_FIRST_LEFT );
lwline_free(l52);
/* Three crossings, two at midpoints, one at vertex */
l52 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(0.5 1, -1 0.5, 1 2, -1 2, -1 3)", PARSER_CHECK_NONE);
CU_ASSERT( lwline_crossing_direction(l51, l52) == LINE_MULTICROSS_END_LEFT );
@ -402,67 +389,83 @@ void test_lwline_crossing_long_lines(void)
}
void test_lwline_crossing_bugs(void)
{
LWLINE *l1;
LWLINE *l2;
l1 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(2.99 90.16,71 74,20 140,171 154)", PARSER_CHECK_NONE);
l2 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(25 169,89 114,40 70,86 43)", PARSER_CHECK_NONE);
CU_ASSERT( lwline_crossing_direction(l1, l2) == LINE_MULTICROSS_END_RIGHT );
lwline_free(l1);
lwline_free(l2);
}
void test_lwpoint_set_ordinate(void)
{
p->x = 0.0;
p->y = 0.0;
p->z = 0.0;
p->m = 0.0;
POINT4D p;
lwpoint_set_ordinate(p, 0, 1.5);
CU_ASSERT_EQUAL( p->x, 1.5 );
p.x = 0.0;
p.y = 0.0;
p.z = 0.0;
p.m = 0.0;
lwpoint_set_ordinate(p, 3, 2.5);
CU_ASSERT_EQUAL( p->m, 2.5 );
lwpoint_set_ordinate(&p, 0, 1.5);
CU_ASSERT_EQUAL( p.x, 1.5 );
lwpoint_set_ordinate(p, 2, 3.5);
CU_ASSERT_EQUAL( p->z, 3.5 );
lwpoint_set_ordinate(&p, 3, 2.5);
CU_ASSERT_EQUAL( p.m, 2.5 );
lwpoint_set_ordinate(&p, 2, 3.5);
CU_ASSERT_EQUAL( p.z, 3.5 );
}
void test_lwpoint_get_ordinate(void)
{
POINT4D p;
p->x = 10.0;
p->y = 20.0;
p->z = 30.0;
p->m = 40.0;
p.x = 10.0;
p.y = 20.0;
p.z = 30.0;
p.m = 40.0;
CU_ASSERT_EQUAL( lwpoint_get_ordinate(p, 0), 10.0 );
CU_ASSERT_EQUAL( lwpoint_get_ordinate(p, 1), 20.0 );
CU_ASSERT_EQUAL( lwpoint_get_ordinate(p, 2), 30.0 );
CU_ASSERT_EQUAL( lwpoint_get_ordinate(p, 3), 40.0 );
CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 0), 10.0 );
CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 1), 20.0 );
CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 2), 30.0 );
CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 3), 40.0 );
}
void test_lwpoint_interpolate(void)
{
POINT4D *r = NULL;
r = lwalloc(sizeof(POINT4D));
POINT4D p, q, r;
int rv = 0;
p->x = 10.0;
p->y = 20.0;
p->z = 30.0;
p->m = 40.0;
q->x = 20.0;
q->y = 30.0;
q->z = 40.0;
q->m = 50.0;
p.x = 10.0;
p.y = 20.0;
p.z = 30.0;
p.m = 40.0;
q.x = 20.0;
q.y = 30.0;
q.z = 40.0;
q.m = 50.0;
rv = lwpoint_interpolate(p, q, r, 4, 2, 35.0);
CU_ASSERT_EQUAL( r->x, 15.0);
rv = lwpoint_interpolate(&p, &q, &r, 4, 2, 35.0);
CU_ASSERT_EQUAL( r.x, 15.0);
rv = lwpoint_interpolate(p, q, r, 4, 3, 41.0);
CU_ASSERT_EQUAL( r->y, 21.0);
rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 41.0);
CU_ASSERT_EQUAL( r.y, 21.0);
rv = lwpoint_interpolate(p, q, r, 4, 3, 50.0);
CU_ASSERT_EQUAL( r->y, 30.0);
rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 50.0);
CU_ASSERT_EQUAL( r.y, 30.0);
rv = lwpoint_interpolate(p, q, r, 4, 3, 40.0);
CU_ASSERT_EQUAL( r->y, 20.0);
lwfree(r);
rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 40.0);
CU_ASSERT_EQUAL( r.y, 20.0);
}
@ -678,21 +681,22 @@ void test_lwline_clip_big(void)
LWLINE *line = lwline_construct(-1, NULL, pa);
LWCOLLECTION *c;
char *ewkt;
POINT4D p;
p->x = 0.0;
p->y = 0.0;
p->z = 0.0;
setPoint4d(pa, 0, p);
p.x = 0.0;
p.y = 0.0;
p.z = 0.0;
setPoint4d(pa, 0, &p);
p->x = 1.0;
p->y = 1.0;
p->z = 1.0;
setPoint4d(pa, 1, p);
p.x = 1.0;
p.y = 1.0;
p.z = 1.0;
setPoint4d(pa, 1, &p);
p->x = 2.0;
p->y = 2.0;
p->z = 2.0;
setPoint4d(pa, 2, p);
p.x = 2.0;
p.y = 2.0;
p.z = 2.0;
setPoint4d(pa, 2, &p);
c = lwline_clip_to_ordinate_range(line, 2, 0.5, 1.5);
ewkt = lwgeom_to_ewkt((LWGEOM*)c, PARSER_CHECK_NONE);

View file

@ -36,3 +36,4 @@ void test_lwmline_clip(void);
void test_geohash_precision(void);
void test_geohash_point(void);
void test_geohash(void);
void test_lwline_crossing_bugs(void);

View file

@ -13,6 +13,7 @@
#include "lwalgorithm.h"
/**
** lw_segment_side()
**
@ -20,11 +21,12 @@
** Return > 0.0 if point Q is right of segment P
** Return = 0.0 if point Q in on segment P
*/
double lw_segment_side(POINT2D *p1, POINT2D *p2, POINT2D *q)
double lw_segment_side(POINT2D p1, POINT2D p2, POINT2D q)
{
return ( (q->x - p1->x) * (p2->y - p1->y) - (p2->x - p1->x) * (q->y - p1->y) );
return ( (q.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (q.y - p1.y) );
}
int lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2)
{
double minq=LW_MIN(q1.x,q2.x);
@ -32,7 +34,7 @@ int lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q
double minp=LW_MIN(p1.x,p2.x);
double maxp=LW_MAX(p1.x,p2.x);
if (minp>maxq || maxp<minq)
if (FP_GT(minp,maxq) || FP_LT(maxp,minq))
return LW_FALSE;
minq=LW_MIN(q1.y,q2.y);
@ -40,7 +42,7 @@ int lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q
minp=LW_MIN(p1.y,p2.y);
maxp=LW_MAX(p1.y,p2.y);
if (minp>maxq || maxp<minq)
if (FP_GT(minp,maxq) || FP_LT(maxp,minq))
return LW_FALSE;
return LW_TRUE;
@ -59,16 +61,14 @@ int lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q
** SEG_COLINEAR = 1,
** SEG_CROSS_LEFT = 2,
** SEG_CROSS_RIGHT = 3,
** SEG_TOUCH_LEFT = 4,
** SEG_TOUCH_RIGHT = 5
*/
int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2)
int lw_segment_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2)
{
double pq1, pq2, qp1, qp2;
/* No envelope interaction => we are done. */
if (!lw_segment_envelope_intersects(*p1, *p2, *q1, *p2))
if (!lw_segment_envelope_intersects(p1, p2, q1, p2))
{
return SEG_NO_INTERSECTION;
}
@ -90,32 +90,45 @@ int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2)
}
/* Nobody is on one side or another? Must be colinear. */
if (pq1 == 0.0 && pq2 == 0.0 && qp1 == 0.0 && qp2 == 0.0)
if (FP_IS_ZERO(pq1) && FP_IS_ZERO(pq2) && FP_IS_ZERO(qp1) && FP_IS_ZERO(qp2))
{
return SEG_COLINEAR;
}
/*
** When one end-point touches, the sidedness is determined by the
** location of the other end-point.
** location of the other end-point. Only touches by the first point
** will be considered "real" to avoid double counting.
*/
if ( pq2 == 0.0 )
LWDEBUGF(4, "pq1=%.15g pq2=%.15g", pq1, pq2);
LWDEBUGF(4, "qp1=%.15g qp2=%.15g", qp1, qp2);
/* Second point of p or q touches, it's not a crossing. */
if ( FP_IS_ZERO(pq2) || FP_IS_ZERO(qp2) )
{
if ( pq1 < 0.0 )
return SEG_TOUCH_LEFT;
else
return SEG_TOUCH_RIGHT;
}
if ( pq1 == 0.0 )
{
if ( pq2 < 0.0 )
return SEG_TOUCH_LEFT;
else
return SEG_TOUCH_RIGHT;
return SEG_NO_INTERSECTION;
}
/* First point of p touches, it's a "crossing". */
if ( FP_IS_ZERO(pq1) )
{
if ( FP_GT(pq2,0.0) )
return SEG_CROSS_RIGHT;
else
return SEG_CROSS_LEFT;
}
/* First point of q touches, it's a crossing. */
if ( FP_IS_ZERO(qp1) )
{
if ( FP_LT(pq1,pq2) )
return SEG_CROSS_RIGHT;
else
return SEG_CROSS_LEFT;
}
/* The segments cross, what direction is the crossing? */
if ( pq1 < pq2 )
if ( FP_LT(pq1,pq2) )
return SEG_CROSS_RIGHT;
else
return SEG_CROSS_LEFT;
@ -141,133 +154,88 @@ int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2)
*/
int lwline_crossing_direction(LWLINE *l1, LWLINE *l2)
{
int i = 0, j = 0, rv = 0;
POINT2D *p1;
POINT2D *p2;
POINT2D *q1;
POINT2D *q2;
POINTARRAY *pa1;
POINTARRAY *pa2;
POINT2D p1, p2, q1, q2;
POINTARRAY *pa1 = NULL, *pa2 = NULL;
int cross_left = 0;
int cross_right = 0;
int first_cross = 0;
int final_cross = 0;
int this_cross = 0;
int vertex_touch = -1;
int vertex_touch_type = 0;
pa1 = (POINTARRAY*)l1->points;
pa2 = (POINTARRAY*)l2->points;
p1 = lwalloc(sizeof(POINT2D));
p2 = lwalloc(sizeof(POINT2D));
q1 = lwalloc(sizeof(POINT2D));
q2 = lwalloc(sizeof(POINT2D));
/* One-point lines can't intersect (and shouldn't exist). */
if ( pa1->npoints < 2 || pa2->npoints < 2 )
return LINE_NO_CROSS;
LWDEBUGF(4, "lineCrossingDirection: l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1,0));
LWDEBUGF(4, "lineCrossingDirection: l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2,0));
LWDEBUGF(4, "l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1,0));
LWDEBUGF(4, "l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2,0));
/* Initialize first point of q */
rv = getPoint2d_p(pa2, 0, &q1);
for ( i = 1; i < pa2->npoints; i++ )
{
rv = getPoint2d_p(pa2, i-1, q1);
rv = getPoint2d_p(pa2, i, q2);
/* Update second point of q to next value */
rv = getPoint2d_p(pa2, i, &q2);
/* Initialize first point of p */
rv = getPoint2d_p(pa1, 0, &p1);
for ( j = 1; j < pa1->npoints; j++ )
{
rv = getPoint2d_p(pa1, j-1, p1);
rv = getPoint2d_p(pa1, j, p2);
LWDEBUGF(4, "lineCrossingDirection: i=%d, j=%d", i, j);
/* Update second point of p to next value */
rv = getPoint2d_p(pa1, j, &p2);
this_cross = lw_segment_intersects(p1, p2, q1, q2);
if ( ! first_cross && this_cross )
first_cross = this_cross;
if ( this_cross )
final_cross = this_cross;
LWDEBUGF(4, "i=%d, j=%d (%.8g %.8g, %.8g %.8g)", this_cross, i, j, p1.x, p1.y, p2.x, p2.y);
if ( this_cross == SEG_CROSS_LEFT )
{
LWDEBUG(4,"this_cross == SEG_CROSS_LEFT");
cross_left++;
break;
if ( ! first_cross )
first_cross = SEG_CROSS_LEFT;
}
if ( this_cross == SEG_CROSS_RIGHT )
{
LWDEBUG(4,"this_cross == SEG_CROSS_RIGHT");
cross_right++;
break;
if ( ! first_cross )
first_cross = SEG_CROSS_LEFT;
}
/*
** Crossing at a co-linearity can be turned into crossing at
** a vertex by pulling the original touch point forward along
** the co-linearity.
** Crossing at a co-linearity can be turned handled by extending
** segment to next vertext and seeing if the end points straddle
** the co-linear segment.
*/
if ( this_cross == SEG_COLINEAR && vertex_touch == (i-1) )
if ( this_cross == SEG_COLINEAR )
{
vertex_touch = i;
break;
LWDEBUG(4,"this_cross == SEG_COLINEAR");
/* TODO: Add logic here and in segment_intersects()
continue;
*/
}
/*
** Crossing-at-vertex will cause four segment touch interactions, two at
** j-1 and two at j. We avoid incrementing our cross count by ignoring the
** second pair.
*/
if ( this_cross == SEG_TOUCH_LEFT )
{
if ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_RIGHT )
{
cross_left++;
vertex_touch = -1;
vertex_touch_type = 0;
}
else
{
vertex_touch = i;
vertex_touch_type = this_cross;
}
break;
}
if ( this_cross == SEG_TOUCH_RIGHT )
{
if ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_LEFT )
{
cross_right++;
vertex_touch = -1;
vertex_touch_type = 0;
}
else
{
vertex_touch = i;
vertex_touch_type = this_cross;
}
break;
}
/*
** TODO Handle co-linear cases.
*/
LWDEBUGF(4, "lineCrossingDirection: this_cross=%d, vertex_touch=%d, vertex_touch_type=%d", this_cross, vertex_touch, vertex_touch_type);
LWDEBUG(4,"this_cross == SEG_NO_INTERSECTION");
/* Turn second point of p into first point */
p1 = p2;
}
/* Turn second point of q into first point */
q1 = q2;
}
LWDEBUGF(4, "first_cross=%d, final_cross=%d, cross_left=%d, cross_right=%d", first_cross, final_cross, cross_left, cross_right);
lwfree(p1);
lwfree(p2);
lwfree(q1);
lwfree(q2);
LWDEBUGF(4, "first_cross=%d, cross_left=%d, cross_right=%d", first_cross, cross_left, cross_right);
if ( !cross_left && !cross_right )
return LINE_NO_CROSS;
@ -290,16 +258,12 @@ int lwline_crossing_direction(LWLINE *l1, LWLINE *l2)
if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_RIGHT )
return LINE_MULTICROSS_END_SAME_FIRST_RIGHT;
if ( cross_left - cross_right == 0 && first_cross == SEG_TOUCH_LEFT )
return LINE_MULTICROSS_END_SAME_FIRST_RIGHT;
if ( cross_left - cross_right == 0 && first_cross == SEG_TOUCH_RIGHT )
return LINE_MULTICROSS_END_SAME_FIRST_LEFT;
return LINE_NO_CROSS;
}
/*
** lwpoint_get_ordinate(point, ordinate) => double
*/

View file

@ -23,8 +23,8 @@ enum CG_SEGMENT_INTERSECTION_TYPE {
SEG_TOUCH_RIGHT = 5
};
double lw_segment_side(POINT2D *p1, POINT2D *p2, POINT2D *q);
int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2);
double lw_segment_side(POINT2D p1, POINT2D p2, POINT2D q);
int lw_segment_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2);
int lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2);