/** ** @brief lwline_crossing_direction: returns the kind of #CG_LINE_CROSS_TYPE behavior of 2 linestrings ** @param l1 first line string ** @param l2 second line string ** @return a #CG_LINE_CROSS_TYPE ** LINE_NO_CROSS = 0 ** LINE_CROSS_LEFT = -1 ** LINE_CROSS_RIGHT = 1 ** LINE_MULTICROSS_END_LEFT = -2 ** LINE_MULTICROSS_END_RIGHT = 2 ** LINE_MULTICROSS_END_SAME_FIRST_LEFT = -3 ** LINE_MULTICROSS_END_SAME_FIRST_RIGHT = 3 ** */ int lwline_crossing_direction(const LWLINE *l1, const LWLINE *l2) { int i = 0, j = 0, rv = 0; POINT2D p1, p2, q1, q2; POINTARRAY *pa1 = NULL, *pa2 = NULL; int cross_left = 0; int cross_right = 0; int first_cross = 0; int this_cross = 0; pa1 = (POINTARRAY*)l1->points; pa2 = (POINTARRAY*)l2->points; /* One-point lines can't intersect (and shouldn't exist). */ if ( pa1->npoints < 2 || pa2->npoints < 2 ) return LINE_NO_CROSS; LWDEBUGF(4, "l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1)); LWDEBUGF(4, "l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2)); /* Initialize first point of q */ rv = getPoint2d_p(pa2, 0, &q1); for ( i = 1; i < pa2->npoints; i++ ) { /* 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++ ) { /* Update second point of p to next value */ rv = getPoint2d_p(pa1, j, &p2); this_cross = lw_segment_intersects(&p1, &p2, &q1, &q2); 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++; if ( ! first_cross ) first_cross = SEG_CROSS_LEFT; } if ( this_cross == SEG_CROSS_RIGHT ) { LWDEBUG(4,"this_cross == SEG_CROSS_RIGHT"); cross_right++; if ( ! first_cross ) first_cross = SEG_CROSS_LEFT; } /* ** 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 ) { LWDEBUG(4,"this_cross == SEG_COLINEAR"); /* TODO: Add logic here and in segment_intersects() continue; */ } 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, cross_left=%d, cross_right=%d", first_cross, cross_left, cross_right); if ( !cross_left && !cross_right ) return LINE_NO_CROSS; if ( !cross_left && cross_right == 1 ) return LINE_CROSS_RIGHT; if ( !cross_right && cross_left == 1 ) return LINE_CROSS_LEFT; if ( cross_left - cross_right == 1 ) return LINE_MULTICROSS_END_LEFT; if ( cross_left - cross_right == -1 ) return LINE_MULTICROSS_END_RIGHT; if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_LEFT ) return LINE_MULTICROSS_END_SAME_FIRST_LEFT; if ( cross_left - cross_right == 0 && first_cross == SEG_CROSS_RIGHT ) return LINE_MULTICROSS_END_SAME_FIRST_RIGHT; return LINE_NO_CROSS; }
/* ** Test crossings side. */ static 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 */ 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; 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; 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; CU_ASSERT( lw_segment_intersects(&p1, &p2, &q1, &q2) == SEG_NO_INTERSECTION ); /* 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 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 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 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 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 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 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; 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; 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; 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_NO_INTERSECTION ); /* Q: Horizontal touching at end point from 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.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.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 ); }