Changeset 4787

Show
Ignore:
Timestamp:
11/11/09 11:02:49 (3 years ago)
Author:
pramsey
Message:

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

Location:
branches/1.4/liblwgeom
Files:
5 modified

Legend:

Unmodified
Added
Removed
  • branches/1.4/liblwgeom/cunit/cu_algorithm.c

    r4168 r4787  
    3030            (NULL == CU_add_test(pSuite, "test_lw_segment_intersects()", test_lw_segment_intersects)) || 
    3131            (NULL == CU_add_test(pSuite, "test_lwline_crossing_short_lines()", test_lwline_crossing_short_lines)) || 
    32             (NULL == CU_add_test(pSuite, "test_lwline_crossing_long_lines()", test_lwline_crossing_long_lines)) || 
     32            (NULL == CU_add_test(pSuite, "test_lwline_crossing_long_lines()", test_lwline_crossing_long_lines)) ||  
     33            (NULL == CU_add_test(pSuite, "test_lwline_crossing_bugs()", test_lwline_crossing_bugs)) || 
    3334            (NULL == CU_add_test(pSuite, "test_lwpoint_set_ordinate()", test_lwpoint_set_ordinate)) || 
    3435            (NULL == CU_add_test(pSuite, "test_lwpoint_get_ordinate()", test_lwpoint_get_ordinate)) || 
     
    3940            (NULL == CU_add_test(pSuite, "test_geohash_point()", test_geohash_point)) || 
    4041            (NULL == CU_add_test(pSuite, "test_geohash_precision()", test_geohash_precision)) || 
    41             (NULL == CU_add_test(pSuite, "test_geohash()", test_geohash)) 
     42            (NULL == CU_add_test(pSuite, "test_geohash()", test_geohash))  
    4243        ) 
    4344        { 
     
    5253** Global variables used by tests below 
    5354*/ 
    54 POINT2D *p1 = NULL; 
    55 POINT2D *p2 = NULL; 
    56 POINT2D *q1 = NULL; 
    57 POINT2D *q2 = NULL; 
    58 POINT4D *p = NULL; 
    59 POINT4D *q = NULL; 
     55 
    6056/* Two-point objects */ 
    6157POINTARRAY *pa21 = NULL; 
     
    6359LWLINE *l21 = NULL; 
    6460LWLINE *l22 = NULL; 
    65 /* Five-point objects */ 
    66 LWLINE *l51 = NULL; 
    67 LWLINE *l52 = NULL; 
    6861/* Parsing support */ 
    6962LWGEOM_PARSER_RESULT parse_result; 
     
    7669int init_cg_suite(void) 
    7770{ 
    78         p = lwalloc(sizeof(POINT4D)); 
    79         q = lwalloc(sizeof(POINT4D)); 
    80         p1 = lwalloc(sizeof(POINT2D)); 
    81         p2 = lwalloc(sizeof(POINT2D)); 
    82         q1 = lwalloc(sizeof(POINT2D)); 
    83         q2 = lwalloc(sizeof(POINT2D)); 
    8471        pa21 = ptarray_construct(0, 0, 2); 
    8572        pa22 = ptarray_construct(0, 0, 2); 
     
    9683int clean_cg_suite(void) 
    9784{ 
    98         if ( p ) lwfree(p); 
    99         if ( p1 )lwfree(p1); 
    100         if ( p2 ) lwfree(p2); 
    101         if ( q1 ) lwfree(q1); 
    102         if ( q2 ) lwfree(q2); 
    10385        if ( l21 ) lwline_free(l21); 
    10486        if ( l22 ) lwline_free(l22); 
     
    11294{ 
    11395        double rv = 0.0; 
    114         POINT2D *q = NULL; 
    115         q = lwalloc(sizeof(POINT2D)); 
     96        POINT2D p1, p2, q; 
    11697 
    11798        /* Vertical line at x=0 */ 
    118         p1->x = 0.0; 
    119         p1->y = 0.0; 
    120         p2->x = 0.0; 
    121         p2->y = 1.0; 
     99        p1.x = 0.0; 
     100        p1.y = 0.0; 
     101        p2.x = 0.0; 
     102        p2.y = 1.0; 
    122103 
    123104        /* On the left */ 
    124         q->x = -2.0; 
    125         q->y = 1.5; 
     105        q.x = -2.0; 
     106        q.y = 1.5; 
    126107        rv = lw_segment_side(p1, p2, q); 
    127108        //printf("left %g\n",rv); 
     
    129110 
    130111        /* On the right */ 
    131         q->x = 2.0; 
     112        q.x = 2.0; 
    132113        rv = lw_segment_side(p1, p2, q); 
    133114        //printf("right %g\n",rv); 
     
    135116 
    136117        /* On the line */ 
    137         q->x = 0.0; 
     118        q.x = 0.0; 
    138119        rv = lw_segment_side(p1, p2, q); 
    139120        //printf("on line %g\n",rv); 
    140121        CU_ASSERT_EQUAL(rv, 0.0); 
    141  
    142         lwfree(q); 
    143122 
    144123} 
     
    150129{ 
    151130 
     131#define setpoint(p, x1, y1) {(p).x = (x1); (p).y = (y1);} 
     132 
     133        POINT2D p1, p2, q1, q2; 
     134         
    152135        /* P: Vertical line at x=0 */ 
    153         p1->x = 0.0; 
    154         p1->y = 0.0; 
    155         p2->x = 0.0; 
    156         p2->y = 1.0; 
     136        setpoint(p1, 0.0, 0.0); 
     137        p1.x = 0.0; 
     138        p1.y = 0.0; 
     139        p2.x = 0.0; 
     140        p2.y = 1.0; 
    157141 
    158142        /* Q: Horizontal line crossing left to right */ 
    159         q1->x = -0.5; 
    160         q1->y = 0.5; 
    161         q2->x = 0.5; 
    162         q2->y = 0.5; 
     143        q1.x = -0.5; 
     144        q1.y = 0.5; 
     145        q2.x = 0.5; 
     146        q2.y = 0.5; 
    163147        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_RIGHT ); 
    164148 
    165149        /* Q: Horizontal line crossing right to left */ 
    166         q1->x = 0.5; 
    167         q1->y = 0.5; 
    168         q2->x = -0.5; 
    169         q2->y = 0.5; 
     150        q1.x = 0.5; 
     151        q1.y = 0.5; 
     152        q2.x = -0.5; 
     153        q2.y = 0.5; 
    170154        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT ); 
    171155 
    172156        /* Q: Horizontal line not crossing right to left */ 
    173         q1->x = 0.5; 
    174         q1->y = 1.5; 
    175         q2->x = -0.5; 
    176         q2->y = 1.5; 
     157        q1.x = 0.5; 
     158        q1.y = 1.5; 
     159        q2.x = -0.5; 
     160        q2.y = 1.5; 
    177161        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION ); 
    178162 
    179         /* Q: Horizontal line crossing at vertex right to left */ 
    180         q1->x = 0.5; 
    181         q1->y = 1.0; 
    182         q2->x = -0.5; 
    183         q2->y = 1.0; 
     163        /* Q: Horizontal line crossing at second vertex right to left */ 
     164        q1.x = 0.5; 
     165        q1.y = 1.0; 
     166        q2.x = -0.5; 
     167        q2.y = 1.0; 
     168        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION ); 
     169 
     170        /* Q: Horizontal line crossing at first vertex right to left */ 
     171        q1.x = 0.5; 
     172        q1.y = 0.0; 
     173        q2.x = -0.5; 
     174        q2.y = 0.0; 
    184175        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT ); 
    185176 
    186         /* Q: Diagonal line with large range crossing at vertex right to left */ 
    187         q1->x = 0.5; 
    188         q1->y = 10.0; 
    189         q2->x = -0.5; 
    190         q2->y = -10.0; 
     177        /* Q: Diagonal line with large range crossing at first vertex right to left */ 
     178        q1.x = 0.5; 
     179        q1.y = 10.0; 
     180        q2.x = -0.5; 
     181        q2.y = -10.0; 
    191182        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT ); 
    192183 
    193         /* Q: Diagonal line with large range crossing at vertex right to left */ 
    194         q1->x = 0.5; 
    195         q1->y = 11.0; 
    196         q2->x = -0.5; 
    197         q2->y = -9.0; 
     184        /* Q: Diagonal line with large range crossing at second vertex right to left */ 
     185        q1.x = 0.5; 
     186        q1.y = 11.0; 
     187        q2.x = -0.5; 
     188        q2.y = -9.0; 
     189        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION ); 
     190 
     191        /* Q: Horizontal touching from left at second vertex*/ 
     192        q1.x = -0.5; 
     193        q1.y = 0.5; 
     194        q2.x = 0.0; 
     195        q2.y = 0.5; 
     196        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION ); 
     197 
     198        /* Q: Horizontal touching from right at first vertex */ 
     199        q1.x = 0.0; 
     200        q1.y = 0.5; 
     201        q2.x = 0.5; 
     202        q2.y = 0.5; 
     203        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_RIGHT ); 
     204 
     205        /* Q: Horizontal touching from left and far below on second vertex */ 
     206        q1.x = -0.5; 
     207        q1.y = -10.5; 
     208        q2.x = 0.0; 
     209        q2.y = 0.5; 
     210        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION ); 
     211 
     212        /* Q: Horizontal touching from right and far above on second vertex */ 
     213        q1.x = 0.5; 
     214        q1.y = 10.5; 
     215        q2.x = 0.0; 
     216        q2.y = 0.5; 
     217        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION ); 
     218 
     219        /* Q: Co-linear from top */ 
     220        q1.x = 0.0; 
     221        q1.y = 10.0; 
     222        q2.x = 0.0; 
     223        q2.y = 0.5; 
     224        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR ); 
     225 
     226        /* Q: Co-linear from bottom */ 
     227        q1.x = 0.0; 
     228        q1.y = -10.0; 
     229        q2.x = 0.0; 
     230        q2.y = 0.5; 
     231        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR ); 
     232 
     233        /* Q: Co-linear contained */ 
     234        q1.x = 0.0; 
     235        q1.y = 0.4; 
     236        q2.x = 0.0; 
     237        q2.y = 0.5; 
     238        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR ); 
     239 
     240        /* Q: Horizontal touching at end point from left */ 
     241        q1.x = -0.5; 
     242        q1.y = 1.0; 
     243        q2.x = 0.0; 
     244        q2.y = 1.0; 
     245        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_NO_INTERSECTION ); 
     246 
     247        /* Q: Horizontal touching at end point from right */ 
     248        q1.x = 0.0; 
     249        q1.y = 1.0; 
     250        q2.x = 0.0; 
     251        q2.y = 0.5; 
     252        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR ); 
     253 
     254        /* Q: Horizontal touching at start point from left */ 
     255        q1.x = 0.0; 
     256        q1.y = 0.0; 
     257        q2.x = -0.5; 
     258        q2.y = 0.0; 
    198259        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_LEFT ); 
    199260 
    200         /* Q: Horizontal touching from left */ 
    201         q1->x = -0.5; 
    202         q1->y = 0.5; 
    203         q2->x = 0.0; 
    204         q2->y = 0.5; 
    205         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_LEFT ); 
    206  
    207         /* Q: Horizontal touching from right */ 
    208         q1->x = 0.5; 
    209         q1->y = 0.5; 
    210         q2->x = 0.0; 
    211         q2->y = 0.5; 
    212         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_RIGHT ); 
    213  
    214         /* Q: Horizontal touching from left and far below*/ 
    215         q1->x = -0.5; 
    216         q1->y = -10.5; 
    217         q2->x = 0.0; 
    218         q2->y = 0.5; 
    219         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_LEFT ); 
    220  
    221         /* Q: Horizontal touching from right and far above */ 
    222         q1->x = 0.5; 
    223         q1->y = 10.5; 
    224         q2->x = 0.0; 
    225         q2->y = 0.5; 
    226         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_RIGHT ); 
    227  
    228         /* Q: Co-linear from top */ 
    229         q1->x = 0.0; 
    230         q1->y = 10.0; 
    231         q2->x = 0.0; 
    232         q2->y = 0.5; 
    233         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR ); 
    234  
    235         /* Q: Co-linear from bottom */ 
    236         q1->x = 0.0; 
    237         q1->y = -10.0; 
    238         q2->x = 0.0; 
    239         q2->y = 0.5; 
    240         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR ); 
    241  
    242         /* Q: Co-linear contained */ 
    243         q1->x = 0.0; 
    244         q1->y = 0.4; 
    245         q2->x = 0.0; 
    246         q2->y = 0.5; 
    247         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_COLINEAR ); 
    248  
    249         /* Q: Horizontal touching at end point from left */ 
    250         q1->x = -0.5; 
    251         q1->y = 1.0; 
    252         q2->x = 0.0; 
    253         q2->y = 1.0; 
    254         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_LEFT ); 
    255  
    256         /* Q: Horizontal touching at end point from right */ 
    257         q1->x = 0.5; 
    258         q1->y = 1.0; 
    259         q2->x = 0.0; 
    260         q2->y = 1.0; 
    261         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_RIGHT ); 
    262  
    263         /* Q: Horizontal touching at start point from left */ 
    264         q1->x = -0.5; 
    265         q1->y = 0.0; 
    266         q2->x = 0.0; 
    267         q2->y = 0.0; 
    268         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_LEFT ); 
    269  
    270261        /* Q: Horizontal touching at start point from right */ 
    271         q1->x = 0.5; 
    272         q1->y = 0.0; 
    273         q2->x = 0.0; 
    274         q2->y = 0.0; 
    275         CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_TOUCH_RIGHT ); 
     262        q1.x = 0.0; 
     263        q1.y = 0.0; 
     264        q2.x = 0.5; 
     265        q2.y = 0.0; 
     266        CU_ASSERT( lw_segment_intersects(p1, p2, q1, q2) == SEG_CROSS_RIGHT ); 
    276267 
    277268} 
     
    280271{ 
    281272 
     273        POINT4D p; 
     274         
    282275        /* 
    283276        ** Simple test, two two-point lines  
     
    285278 
    286279        /* Vertical line from 0,0 to 1,1 */ 
    287         p->x = 0.0; 
    288         p->y = 0.0; 
    289         setPoint4d(pa21, 0, p); 
    290         p->y = 1.0; 
    291         setPoint4d(pa21, 1, p); 
     280        p.x = 0.0; 
     281        p.y = 0.0; 
     282        setPoint4d(pa21, 0, &p); 
     283        p.y = 1.0; 
     284        setPoint4d(pa21, 1, &p); 
    292285 
    293286        /* Horizontal, crossing mid-segment */ 
    294         p->x = -0.5; 
    295         p->y = 0.5; 
    296         setPoint4d(pa22, 0, p); 
    297         p->x = 0.5; 
    298         setPoint4d(pa22, 1, p); 
     287        p.x = -0.5; 
     288        p.y = 0.5; 
     289        setPoint4d(pa22, 0, &p); 
     290        p.x = 0.5; 
     291        setPoint4d(pa22, 1, &p); 
    299292 
    300293        CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_CROSS_RIGHT ); 
    301294 
    302         /* Horizontal, crossing at top end vertex */ 
    303         p->x = -0.5; 
    304         p->y = 1.0; 
    305         setPoint4d(pa22, 0, p); 
    306         p->x = 0.5; 
    307         setPoint4d(pa22, 1, p); 
     295        /* Horizontal, crossing at top end vertex (end crossings don't count) */ 
     296        p.x = -0.5; 
     297        p.y = 1.0; 
     298        setPoint4d(pa22, 0, &p); 
     299        p.x = 0.5; 
     300        setPoint4d(pa22, 1, &p); 
     301 
     302        CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS ); 
     303 
     304        /* Horizontal, crossing at bottom end vertex */ 
     305        p.x = -0.5; 
     306        p.y = 0.0; 
     307        setPoint4d(pa22, 0, &p); 
     308        p.x = 0.5; 
     309        setPoint4d(pa22, 1, &p); 
    308310 
    309311        CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_CROSS_RIGHT ); 
    310312 
    311         /* Horizontal, crossing at bottom end vertex */ 
    312         p->x = -0.5; 
    313         p->y = 0.0; 
    314         setPoint4d(pa22, 0, p); 
    315         p->x = 0.5; 
    316         setPoint4d(pa22, 1, p); 
    317  
    318         CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_CROSS_RIGHT ); 
    319  
    320313        /* Horizontal, no crossing */ 
    321         p->x = -0.5; 
    322         p->y = 2.0; 
    323         setPoint4d(pa22, 0, p); 
    324         p->x = 0.5; 
    325         setPoint4d(pa22, 1, p); 
     314        p.x = -0.5; 
     315        p.y = 2.0; 
     316        setPoint4d(pa22, 0, &p); 
     317        p.x = 0.5; 
     318        setPoint4d(pa22, 1, &p); 
    326319 
    327320        CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS ); 
    328321 
    329322        /* Vertical, no crossing */ 
    330         p->x = -0.5; 
    331         p->y = 0.0; 
    332         setPoint4d(pa22, 0, p); 
    333         p->y = 1.0; 
    334         setPoint4d(pa22, 1, p); 
     323        p.x = -0.5; 
     324        p.y = 0.0; 
     325        setPoint4d(pa22, 0, &p); 
     326        p.y = 1.0; 
     327        setPoint4d(pa22, 1, &p); 
    335328 
    336329        CU_ASSERT( lwline_crossing_direction(l21, l22) == LINE_NO_CROSS ); 
     
    345338        ** More complex test, longer lines and multiple crossings  
    346339        */ 
    347  
    348340        /* Vertical line with vertices at y integers */ 
    349341        l51 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(0 0, 0 1, 0 2, 0 3, 0 4)", PARSER_CHECK_NONE); 
     
    374366        lwline_free(l52); 
    375367 
    376         /* Two crossings, one at the last vertex on the next interior vertex */ 
    377         l52 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(1 4, 0 4, -1 3, 0 3, 1 3)", PARSER_CHECK_NONE); 
    378         CU_ASSERT( lwline_crossing_direction(l51, l52) == LINE_MULTICROSS_END_SAME_FIRST_LEFT ); 
    379         lwline_free(l52); 
    380  
    381368        /* Three crossings, two at midpoints, one at vertex */ 
    382369        l52 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(0.5 1, -1 0.5, 1 2, -1 2, -1 3)", PARSER_CHECK_NONE); 
     
    403390} 
    404391 
     392 
     393void test_lwline_crossing_bugs(void) 
     394{ 
     395        LWLINE *l1; 
     396        LWLINE *l2; 
     397         
     398        l1 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(2.99 90.16,71 74,20 140,171 154)", PARSER_CHECK_NONE); 
     399        l2 = (LWLINE*)lwgeom_from_ewkt("LINESTRING(25 169,89 114,40 70,86 43)", PARSER_CHECK_NONE); 
     400 
     401        CU_ASSERT( lwline_crossing_direction(l1, l2) == LINE_MULTICROSS_END_RIGHT ); 
     402        lwline_free(l1); 
     403        lwline_free(l2); 
     404         
     405} 
     406 
    405407void test_lwpoint_set_ordinate(void) 
    406408{ 
    407         p->x = 0.0; 
    408         p->y = 0.0; 
    409         p->z = 0.0; 
    410         p->m = 0.0; 
    411  
    412         lwpoint_set_ordinate(p, 0, 1.5); 
    413         CU_ASSERT_EQUAL( p->x, 1.5 ); 
    414  
    415         lwpoint_set_ordinate(p, 3, 2.5); 
    416         CU_ASSERT_EQUAL( p->m, 2.5 ); 
    417  
    418         lwpoint_set_ordinate(p, 2, 3.5); 
    419         CU_ASSERT_EQUAL( p->z, 3.5 ); 
     409        POINT4D p; 
     410 
     411        p.x = 0.0; 
     412        p.y = 0.0; 
     413        p.z = 0.0; 
     414        p.m = 0.0; 
     415 
     416        lwpoint_set_ordinate(&p, 0, 1.5); 
     417        CU_ASSERT_EQUAL( p.x, 1.5 ); 
     418 
     419        lwpoint_set_ordinate(&p, 3, 2.5); 
     420        CU_ASSERT_EQUAL( p.m, 2.5 ); 
     421 
     422        lwpoint_set_ordinate(&p, 2, 3.5); 
     423        CU_ASSERT_EQUAL( p.z, 3.5 ); 
    420424 
    421425} 
     
    423427void test_lwpoint_get_ordinate(void) 
    424428{ 
    425  
    426         p->x = 10.0; 
    427         p->y = 20.0; 
    428         p->z = 30.0; 
    429         p->m = 40.0; 
    430  
    431         CU_ASSERT_EQUAL( lwpoint_get_ordinate(p, 0), 10.0 ); 
    432         CU_ASSERT_EQUAL( lwpoint_get_ordinate(p, 1), 20.0 ); 
    433         CU_ASSERT_EQUAL( lwpoint_get_ordinate(p, 2), 30.0 ); 
    434         CU_ASSERT_EQUAL( lwpoint_get_ordinate(p, 3), 40.0 ); 
     429        POINT4D p; 
     430 
     431        p.x = 10.0; 
     432        p.y = 20.0; 
     433        p.z = 30.0; 
     434        p.m = 40.0; 
     435 
     436        CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 0), 10.0 ); 
     437        CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 1), 20.0 ); 
     438        CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 2), 30.0 ); 
     439        CU_ASSERT_EQUAL( lwpoint_get_ordinate(&p, 3), 40.0 ); 
    435440 
    436441} 
     
    438443void test_lwpoint_interpolate(void) 
    439444{ 
    440         POINT4D *r = NULL; 
    441         r = lwalloc(sizeof(POINT4D)); 
     445        POINT4D p, q, r; 
    442446        int rv = 0; 
    443447 
    444         p->x = 10.0; 
    445         p->y = 20.0; 
    446         p->z = 30.0; 
    447         p->m = 40.0; 
    448         q->x = 20.0; 
    449         q->y = 30.0; 
    450         q->z = 40.0; 
    451         q->m = 50.0; 
    452  
    453         rv = lwpoint_interpolate(p, q, r, 4, 2, 35.0); 
    454         CU_ASSERT_EQUAL( r->x, 15.0); 
    455  
    456         rv = lwpoint_interpolate(p, q, r, 4, 3, 41.0); 
    457         CU_ASSERT_EQUAL( r->y, 21.0); 
    458  
    459         rv = lwpoint_interpolate(p, q, r, 4, 3, 50.0); 
    460         CU_ASSERT_EQUAL( r->y, 30.0); 
    461  
    462         rv = lwpoint_interpolate(p, q, r, 4, 3, 40.0); 
    463         CU_ASSERT_EQUAL( r->y, 20.0); 
    464  
    465         lwfree(r); 
     448        p.x = 10.0; 
     449        p.y = 20.0; 
     450        p.z = 30.0; 
     451        p.m = 40.0; 
     452         
     453        q.x = 20.0; 
     454        q.y = 30.0; 
     455        q.z = 40.0; 
     456        q.m = 50.0; 
     457 
     458        rv = lwpoint_interpolate(&p, &q, &r, 4, 2, 35.0); 
     459        CU_ASSERT_EQUAL( r.x, 15.0); 
     460 
     461        rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 41.0); 
     462        CU_ASSERT_EQUAL( r.y, 21.0); 
     463 
     464        rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 50.0); 
     465        CU_ASSERT_EQUAL( r.y, 30.0); 
     466 
     467        rv = lwpoint_interpolate(&p, &q, &r, 4, 3, 40.0); 
     468        CU_ASSERT_EQUAL( r.y, 20.0); 
    466469 
    467470} 
     
    679682        LWCOLLECTION *c; 
    680683        char *ewkt; 
    681  
    682         p->x = 0.0; 
    683         p->y = 0.0; 
    684         p->z = 0.0; 
    685         setPoint4d(pa, 0, p); 
    686  
    687         p->x = 1.0; 
    688         p->y = 1.0; 
    689         p->z = 1.0; 
    690         setPoint4d(pa, 1, p); 
    691  
    692         p->x = 2.0; 
    693         p->y = 2.0; 
    694         p->z = 2.0; 
    695         setPoint4d(pa, 2, p); 
     684        POINT4D p; 
     685 
     686        p.x = 0.0; 
     687        p.y = 0.0; 
     688        p.z = 0.0; 
     689        setPoint4d(pa, 0, &p); 
     690 
     691        p.x = 1.0; 
     692        p.y = 1.0; 
     693        p.z = 1.0; 
     694        setPoint4d(pa, 1, &p); 
     695 
     696        p.x = 2.0; 
     697        p.y = 2.0; 
     698        p.z = 2.0; 
     699        setPoint4d(pa, 2, &p); 
    696700 
    697701        c = lwline_clip_to_ordinate_range(line, 2, 0.5, 1.5); 
  • branches/1.4/liblwgeom/cunit/cu_algorithm.h

    r4168 r4787  
    4141void test_geohash_point(void); 
    4242void test_geohash(void); 
     43void test_lwline_crossing_bugs(void); 
  • branches/1.4/liblwgeom/liblwgeom.h

    r4309 r4787  
    5454#define FP_CONTAINS_EXCL(A, X, B) (FP_LT(A, X) && FP_LT(X, B)) 
    5555#define FP_CONTAINS(A, X, B) FP_CONTAINS_EXCL(A, X, B) 
     56#define FP_IS_ZERO(A) (fabs(A) <= PGIS_EPSILON) 
    5657#define LW_TRUE 1 
    5758#define LW_FALSE 0 
  • branches/1.4/liblwgeom/lwalgorithm.c

    r4168 r4787  
    2121** Return = 0.0 if point Q in on segment P 
    2222*/ 
    23 double lw_segment_side(POINT2D *p1, POINT2D *p2, POINT2D *q) 
    24 { 
    25         return ( (q->x - p1->x) * (p2->y - p1->y) - (p2->x - p1->x) * (q->y - p1->y) ); 
     23double lw_segment_side(POINT2D p1, POINT2D p2, POINT2D q) 
     24{ 
     25        return ( (q.x - p1.x) * (p2.y - p1.y) - (p2.x - p1.x) * (q.y - p1.y) ); 
    2626} 
    2727 
     
    3333        double maxp=LW_MAX(p1.x,p2.x); 
    3434 
    35         if (minp>maxq || maxp<minq) 
     35        if (FP_GT(minp,maxq) || FP_LT(maxp,minq)) 
    3636                return LW_FALSE; 
    3737 
     
    4141        maxp=LW_MAX(p1.y,p2.y); 
    4242 
    43         if (minp>maxq || maxp<minq) 
     43        if (FP_GT(minp,maxq) || FP_LT(maxp,minq)) 
    4444                return LW_FALSE; 
    4545 
    4646        return LW_TRUE; 
    4747} 
     48 
    4849 
    4950/** 
     
    6061**              SEG_CROSS_LEFT = 2, 
    6162**              SEG_CROSS_RIGHT = 3, 
    62 **              SEG_TOUCH_LEFT = 4, 
    63 **              SEG_TOUCH_RIGHT = 5 
    6463*/ 
    65 int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2) 
     64int lw_segment_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2) 
    6665{ 
    6766 
     
    6968 
    7069        /* No envelope interaction => we are done. */ 
    71         if (!lw_segment_envelope_intersects(*p1, *p2, *q1, *p2)) 
     70        if (!lw_segment_envelope_intersects(p1, p2, q1, p2)) 
    7271        { 
    7372                return SEG_NO_INTERSECTION; 
     
    9190 
    9291        /* Nobody is on one side or another? Must be colinear. */ 
    93         if (pq1 == 0.0 && pq2 == 0.0 && qp1 == 0.0 && qp2 == 0.0) 
     92        if (FP_IS_ZERO(pq1) && FP_IS_ZERO(pq2) && FP_IS_ZERO(qp1) && FP_IS_ZERO(qp2)) 
    9493        { 
    9594                return SEG_COLINEAR; 
     
    9897        /* 
    9998        ** When one end-point touches, the sidedness is determined by the 
    100         ** location of the other end-point. 
     99        ** location of the other end-point. Only touches by the first point 
     100        ** will be considered "real" to avoid double counting. 
    101101        */ 
    102         if ( pq2 == 0.0 ) 
    103         { 
    104                 if ( pq1 < 0.0 ) 
    105                         return SEG_TOUCH_LEFT; 
     102        LWDEBUGF(4, "pq1=%.15g pq2=%.15g", pq1, pq2); 
     103        LWDEBUGF(4, "qp1=%.15g qp2=%.15g", qp1, qp2); 
     104 
     105        /* Second point of p or q touches, it's not a crossing. */ 
     106        if ( FP_IS_ZERO(pq2) || FP_IS_ZERO(qp2) ) 
     107        { 
     108                return SEG_NO_INTERSECTION; 
     109        } 
     110 
     111        /* First point of p touches, it's a "crossing". */ 
     112        if ( FP_IS_ZERO(pq1) ) 
     113        { 
     114                if ( FP_GT(pq2,0.0) ) 
     115                        return SEG_CROSS_RIGHT; 
    106116                else 
    107                         return SEG_TOUCH_RIGHT; 
    108         } 
    109         if ( pq1 == 0.0 ) 
    110         { 
    111                 if ( pq2 < 0.0 ) 
    112                         return SEG_TOUCH_LEFT; 
     117                        return SEG_CROSS_LEFT; 
     118        } 
     119 
     120        /* First point of q touches, it's a crossing. */ 
     121        if ( FP_IS_ZERO(qp1) ) 
     122        { 
     123                if ( FP_LT(pq1,pq2) ) 
     124                        return SEG_CROSS_RIGHT; 
    113125                else 
    114                         return SEG_TOUCH_RIGHT; 
    115         } 
    116  
     126                        return SEG_CROSS_LEFT; 
     127        } 
     128         
    117129        /* The segments cross, what direction is the crossing? */ 
    118         if ( pq1 < pq2 ) 
     130        if ( FP_LT(pq1,pq2) ) 
    119131                return SEG_CROSS_RIGHT; 
    120132        else 
     
    142154int lwline_crossing_direction(LWLINE *l1, LWLINE *l2) 
    143155{ 
    144  
    145156        int i = 0, j = 0, rv = 0; 
    146         POINT2D *p1; 
    147         POINT2D *p2; 
    148         POINT2D *q1; 
    149         POINT2D *q2; 
    150         POINTARRAY *pa1; 
    151         POINTARRAY *pa2; 
     157        POINT2D p1, p2, q1, q2; 
     158        POINTARRAY *pa1 = NULL, *pa2 = NULL; 
    152159        int cross_left = 0; 
    153160        int cross_right = 0; 
    154161        int first_cross = 0; 
    155         int final_cross = 0; 
    156162        int this_cross = 0; 
    157         int vertex_touch = -1; 
    158         int vertex_touch_type = 0; 
    159163 
    160164        pa1 = (POINTARRAY*)l1->points; 
    161165        pa2 = (POINTARRAY*)l2->points; 
    162  
    163         p1 = lwalloc(sizeof(POINT2D)); 
    164         p2 = lwalloc(sizeof(POINT2D)); 
    165         q1 = lwalloc(sizeof(POINT2D)); 
    166         q2 = lwalloc(sizeof(POINT2D)); 
    167166 
    168167        /* One-point lines can't intersect (and shouldn't exist). */ 
     
    170169                return LINE_NO_CROSS; 
    171170 
    172         LWDEBUGF(4, "lineCrossingDirection: l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1,0)); 
    173         LWDEBUGF(4, "lineCrossingDirection: l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2,0)); 
     171        LWDEBUGF(4, "l1 = %s", lwgeom_to_ewkt((LWGEOM*)l1,0)); 
     172        LWDEBUGF(4, "l2 = %s", lwgeom_to_ewkt((LWGEOM*)l2,0)); 
     173 
     174        /* Initialize first point of q */ 
     175        rv = getPoint2d_p(pa2, 0, &q1); 
    174176 
    175177        for ( i = 1; i < pa2->npoints; i++ ) 
    176178        { 
    177179 
    178                 rv = getPoint2d_p(pa2, i-1, q1); 
    179                 rv = getPoint2d_p(pa2, i, q2); 
    180  
     180                /* Update second point of q to next value */ 
     181                rv = getPoint2d_p(pa2, i, &q2); 
     182 
     183                /* Initialize first point of p */ 
     184                rv = getPoint2d_p(pa1, 0, &p1); 
     185                 
    181186                for ( j = 1; j < pa1->npoints; j++ ) 
    182187                { 
    183188 
    184                         rv = getPoint2d_p(pa1, j-1, p1); 
    185                         rv = getPoint2d_p(pa1, j, p2); 
    186  
    187                         LWDEBUGF(4, "lineCrossingDirection: i=%d, j=%d", i, j); 
    188  
     189                        /* Update second point of p to next value */ 
     190                        rv = getPoint2d_p(pa1, j, &p2); 
     191                         
    189192                        this_cross = lw_segment_intersects(p1, p2, q1, q2); 
    190193 
    191                         if ( ! first_cross && this_cross ) 
    192                                 first_cross = this_cross; 
    193                         if ( this_cross ) 
    194                                 final_cross = this_cross; 
     194                        LWDEBUGF(4, "i=%d, j=%d (%.8g %.8g, %.8g %.8g)", this_cross, i, j, p1.x, p1.y, p2.x, p2.y); 
    195195 
    196196                        if ( this_cross == SEG_CROSS_LEFT ) 
    197197                        { 
     198                                LWDEBUG(4,"this_cross == SEG_CROSS_LEFT"); 
    198199                                cross_left++; 
    199                                 break; 
     200                                if ( ! first_cross )  
     201                                        first_cross = SEG_CROSS_LEFT; 
    200202                        } 
    201203 
    202204                        if ( this_cross == SEG_CROSS_RIGHT ) 
    203205                        { 
     206                                LWDEBUG(4,"this_cross == SEG_CROSS_RIGHT"); 
    204207                                cross_right++; 
    205                                 break; 
     208                                if ( ! first_cross )  
     209                                        first_cross = SEG_CROSS_LEFT; 
    206210                        } 
    207211 
    208212                        /* 
    209                         ** Crossing at a co-linearity can be turned into crossing at 
    210                         ** a vertex by pulling the original touch point forward along 
    211                         ** the co-linearity. 
     213                        ** Crossing at a co-linearity can be turned handled by extending 
     214                        ** segment to next vertext and seeing if the end points straddle 
     215                        ** the co-linear segment. 
    212216                        */ 
    213                         if ( this_cross == SEG_COLINEAR && vertex_touch == (i-1) ) 
    214                         { 
    215                                 vertex_touch = i; 
    216                                 break; 
    217                         } 
    218  
    219                         /* 
    220                         ** Crossing-at-vertex will cause four segment touch interactions, two at 
    221                         ** j-1 and two at j. We avoid incrementing our cross count by ignoring the 
    222                         ** second pair. 
    223                         */ 
    224                         if ( this_cross == SEG_TOUCH_LEFT ) 
    225                         { 
    226                                 if ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_RIGHT ) 
    227                                 { 
    228                                         cross_left++; 
    229                                         vertex_touch = -1; 
    230                                         vertex_touch_type = 0; 
    231                                 } 
    232                                 else 
    233                                 { 
    234                                         vertex_touch = i; 
    235                                         vertex_touch_type = this_cross; 
    236                                 } 
    237                                 break; 
    238                         } 
    239                         if ( this_cross == SEG_TOUCH_RIGHT ) 
    240                         { 
    241                                 if ( vertex_touch == (i-1) && vertex_touch_type == SEG_TOUCH_LEFT ) 
    242                                 { 
    243                                         cross_right++; 
    244                                         vertex_touch = -1; 
    245                                         vertex_touch_type = 0; 
    246                                 } 
    247                                 else 
    248                                 { 
    249                                         vertex_touch = i; 
    250                                         vertex_touch_type = this_cross; 
    251                                 } 
    252                                 break; 
    253                         } 
    254  
    255                         /* 
    256                         ** TODO Handle co-linear cases. 
    257                         */ 
    258  
    259                         LWDEBUGF(4, "lineCrossingDirection: this_cross=%d, vertex_touch=%d, vertex_touch_type=%d", this_cross, vertex_touch, vertex_touch_type); 
    260  
    261                 } 
    262  
    263         } 
    264  
    265         LWDEBUGF(4, "first_cross=%d, final_cross=%d, cross_left=%d, cross_right=%d", first_cross, final_cross, cross_left, cross_right); 
    266  
    267         lwfree(p1); 
    268         lwfree(p2); 
    269         lwfree(q1); 
    270         lwfree(q2); 
     217                        if ( this_cross == SEG_COLINEAR ) 
     218                        { 
     219                                LWDEBUG(4,"this_cross == SEG_COLINEAR"); 
     220                                /* TODO: Add logic here and in segment_intersects()  
     221                                continue;  
     222                                */ 
     223                        } 
     224                         
     225                        LWDEBUG(4,"this_cross == SEG_NO_INTERSECTION"); 
     226                         
     227                        /* Turn second point of p into first point */ 
     228                        p1 = p2; 
     229 
     230                } 
     231                 
     232                /* Turn second point of q into first point */ 
     233                q1 = q2; 
     234 
     235        } 
     236 
     237        LWDEBUGF(4, "first_cross=%d, cross_left=%d, cross_right=%d", first_cross, cross_left, cross_right); 
    271238 
    272239        if ( !cross_left && !cross_right ) 
     
    291258                return LINE_MULTICROSS_END_SAME_FIRST_RIGHT; 
    292259 
    293         if ( cross_left - cross_right == 0 && first_cross == SEG_TOUCH_LEFT ) 
    294                 return LINE_MULTICROSS_END_SAME_FIRST_RIGHT; 
    295  
    296         if ( cross_left - cross_right == 0 && first_cross == SEG_TOUCH_RIGHT ) 
    297                 return LINE_MULTICROSS_END_SAME_FIRST_LEFT; 
    298  
    299260        return LINE_NO_CROSS; 
    300261 
    301262} 
     263 
     264 
    302265 
    303266/* 
  • branches/1.4/liblwgeom/lwalgorithm.h

    r4168 r4787  
    2424}; 
    2525 
    26 double lw_segment_side(POINT2D *p1, POINT2D *p2, POINT2D *q); 
    27 int lw_segment_intersects(POINT2D *p1, POINT2D *p2, POINT2D *q1, POINT2D *q2); 
     26double lw_segment_side(POINT2D p1, POINT2D p2, POINT2D q); 
     27int lw_segment_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2); 
    2828int lw_segment_envelope_intersects(POINT2D p1, POINT2D p2, POINT2D q1, POINT2D q2); 
    2929