From: Paul Ramsey Date: Wed, 10 Oct 2012 00:00:54 +0000 (+0000) Subject: Add in arc ptarray vs ptarray and arc ptarray vs arc ptarray distance functions.... X-Git-Tag: 2.1.0beta2~573 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=97fc6137b1a10e244c6d632a819f7f0f9cc79814;p=postgis Add in arc ptarray vs ptarray and arc ptarray vs arc ptarray distance functions. (#2018) git-svn-id: http://svn.osgeo.org/postgis/trunk@10390 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/cunit/cu_measures.c b/liblwgeom/cunit/cu_measures.c index e9ae11911..b8bdf6e18 100644 --- a/liblwgeom/cunit/cu_measures.c +++ b/liblwgeom/cunit/cu_measures.c @@ -666,6 +666,51 @@ test_lw_dist2d_pt_ptarrayarc(void) lwline_free(lwline); } +static void +test_lw_dist2d_ptarray_ptarrayarc(void) +{ + /* int lw_dist2d_ptarray_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl) */ + DISTPTS dl; + int rv; + LWLINE *lwline1; + LWLINE *lwline2; + + /* Unit semi-circle above X axis */ + lwline1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 0, 0 1, 1 0)")); + + /* Line above top of semi-circle */ + lwline2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-2 2, -1 2, 1 2, 2 2)")); + lw_dist2d_distpts_init(&dl, DIST_MIN); + rv = lw_dist2d_ptarray_ptarrayarc(lwline2->points, lwline1->points, &dl); + CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001); + + /* Reversed arguments, should fail */ + lw_dist2d_distpts_init(&dl, DIST_MIN); + cu_error_msg_reset(); + rv = lw_dist2d_ptarray_ptarrayarc(lwline1->points, lwline2->points, &dl); + //printf("%s\n", cu_error_msg); + CU_ASSERT_STRING_EQUAL("lw_dist2d_ptarray_ptarrayarc called with non-arc input", cu_error_msg); + + lwline_free(lwline2); + + /* Line along side of semi-circle */ + lwline2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-2 -3, -2 -2, -2 2, -2 3)")); + lw_dist2d_distpts_init(&dl, DIST_MIN); + rv = lw_dist2d_ptarray_ptarrayarc(lwline2->points, lwline1->points, &dl); + CU_ASSERT_DOUBLE_EQUAL(dl.distance, 1, 0.000001); + + /* Four unit semi-circles surrounding the 2x2 box around origin */ + lwline_free(lwline1); + lwline_free(lwline2); + lwline1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-1 -1, -2 0, -1 1, 0 2, 1 1, 2 0, 1 -1, 0 -2, -1 -1)")); + lwline2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(-2.5 -3, -2.5 -2, -2.5 2, -2.5 3)")); + rv = lw_dist2d_ptarray_ptarrayarc(lwline2->points, lwline1->points, &dl); + CU_ASSERT_DOUBLE_EQUAL(dl.distance, 0.5, 0.000001); + + lwline_free(lwline2); + lwline_free(lwline1); +} + /* ** Used by test harness to register the tests in this file. */ @@ -681,6 +726,7 @@ CU_TestInfo measures_tests[] = PG_TEST(test_lw_dist2d_arc_arc), PG_TEST(test_lw_arc_length), PG_TEST(test_lw_dist2d_pt_ptarrayarc), + PG_TEST(test_lw_dist2d_ptarray_ptarrayarc), CU_TEST_INFO_NULL }; CU_SuiteInfo measures_suite = {"PostGIS Measures Suite", NULL, NULL, measures_tests}; diff --git a/liblwgeom/measures.c b/liblwgeom/measures.c index 0cf285445..47aa5eb47 100644 --- a/liblwgeom/measures.c +++ b/liblwgeom/measures.c @@ -709,6 +709,18 @@ lw_dist2d_pt_ptarrayarc(const POINT2D *p, const POINTARRAY *pa, DISTPTS *dl) LWDEBUG(2, "lw_dist2d_pt_ptarrayarc is called"); + if ( pa->npoints % 2 == 0 || pa->npoints < 3 ) + { + lwerror("lw_dist2d_pt_ptarrayarc called with non-arc input"); + return LW_FALSE; + } + + if (dl->mode == DIST_MAX) + { + lwerror("lw_dist2d_pt_ptarrayarc does not currently support DIST_MAX mode"); + return LW_FALSE; + } + A1 = getPoint2d_cp(pa, 0); if ( ! lw_dist2d_pt_pt(p, A1, dl) ) @@ -811,8 +823,7 @@ lw_dist2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly, DISTPTS *dl) /** - -test each segment of l1 against each segment of l2. +* test each segment of l1 against each segment of l2. */ int lw_dist2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2,DISTPTS *dl) @@ -863,6 +874,109 @@ lw_dist2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2,DISTPTS *dl) return LW_TRUE; } +/** +* Test each segment of pa against each arc of pb for distance. +*/ +int +lw_dist2d_ptarray_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl) +{ + int t, u; + const POINT2D *A1; + const POINT2D *A2; + const POINT2D *B1; + const POINT2D *B2; + const POINT2D *B3; + int twist = dl->twisted; + + LWDEBUGF(2, "lw_dist2d_ptarray_ptarrayarc called (points: %d-%d)",pa->npoints, pb->npoints); + + if ( pb->npoints % 2 == 0 || pb->npoints < 3 ) + { + lwerror("lw_dist2d_ptarray_ptarrayarc called with non-arc input"); + return LW_FALSE; + } + + if ( dl->mode == DIST_MAX ) + { + lwerror("lw_dist2d_ptarray_ptarrayarc does not currently support DIST_MAX mode"); + return LW_FALSE; + } + else + { + A1 = getPoint2d_cp(pa, 0); + for ( t=1; t < pa->npoints; t++ ) /* For each segment in pa */ + { + A2 = getPoint2d_cp(pa, t); + B1 = getPoint2d_cp(pb, 0); + for ( u=1; u < pb->npoints; u += 2 ) /* For each arc in pb */ + { + B2 = getPoint2d_cp(pb, u); + B3 = getPoint2d_cp(pb, u+1); + dl->twisted = twist; + + lw_dist2d_seg_arc(A1, A2, B1, B2, B3, dl); + + /* If we've found a distance within tolerance, we're done */ + if ( dl->distance <= dl->tolerance && dl->mode == DIST_MIN ) + return LW_TRUE; + + B1 = B3; + } + A1 = A2; + } + } + return LW_TRUE; +} + +/** +* Test each arc of pa against each arc of pb for distance. +*/ +int +lw_dist2d_ptarrayarc_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl) +{ + int t, u; + const POINT2D *A1; + const POINT2D *A2; + const POINT2D *A3; + const POINT2D *B1; + const POINT2D *B2; + const POINT2D *B3; + int twist = dl->twisted; + + LWDEBUGF(2, "lw_dist2d_ptarrayarc_ptarrayarc called (points: %d-%d)",pa->npoints, pb->npoints); + + if (dl->mode == DIST_MAX) + { + lwerror("lw_dist2d_ptarrayarc_ptarrayarc does not currently support DIST_MAX mode"); + return LW_FALSE; + } + else + { + A1 = getPoint2d_cp(pa, 0); + for ( t=1; t < pa->npoints; t++ ) /* For each segment in pa */ + { + A2 = getPoint2d_cp(pa, t); + A3 = getPoint2d_cp(pa, t+1); + B1 = getPoint2d_cp(pb, 0); + for ( u=1; u < pb->npoints; u += 2 ) /* For each arc in pb */ + { + B2 = getPoint2d_cp(pb, u); + B3 = getPoint2d_cp(pb, u+1); + dl->twisted = twist; + + lw_dist2d_arc_arc(A1, A2, A3, B1, B2, B3, dl); + + /* If we've found a distance within tolerance, we're done */ + if ( dl->distance <= dl->tolerance && dl->mode == DIST_MIN ) + return LW_TRUE; + + B1 = B3; + } + A1 = A3; + } + } + return LW_TRUE; +} /** * Calculate the shortest distance between an arc and an edge. * Line/circle approach from http://stackoverflow.com/questions/1073336/circle-line-collision-detection diff --git a/liblwgeom/measures.h b/liblwgeom/measures.h index 377774131..0a3958dda 100644 --- a/liblwgeom/measures.h +++ b/liblwgeom/measures.h @@ -50,6 +50,8 @@ int lw_dist2d_distribute_fast(LWGEOM *lwg1, LWGEOM *lwg2, DISTPTS *dl); int lw_dist2d_pt_ptarray(POINT2D *p, POINTARRAY *pa, DISTPTS *dl); int lw_dist2d_pt_ptarrayarc(const POINT2D *p, const POINTARRAY *pa, DISTPTS *dl); int lw_dist2d_ptarray_ptarray(POINTARRAY *l1, POINTARRAY *l2, DISTPTS *dl); +int lw_dist2d_ptarray_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl); +int lw_dist2d_ptarrayarc_ptarrayarc(const POINTARRAY *pa, const POINTARRAY *pb, DISTPTS *dl); int lw_dist2d_ptarray_poly(POINTARRAY *pa, LWPOLY *poly, DISTPTS *dl); int lw_dist2d_point_point(LWPOINT *point1, LWPOINT *point2, DISTPTS *dl); int lw_dist2d_point_line(LWPOINT *point, LWLINE *line, DISTPTS *dl);