From: Sandro Santilli Date: Thu, 26 Jan 2012 09:16:37 +0000 (+0000) Subject: Implement ptarray_append_ptarray, and change its signature X-Git-Tag: 2.0.0alpha3~69 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=925d626bbd78ce37019bd42550222c9dcf1efdb1;p=postgis Implement ptarray_append_ptarray, and change its signature This is propedeutic to ticket #1500 git-svn-id: http://svn.osgeo.org/postgis/trunk@8926 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/liblwgeom/cunit/cu_ptarray.c b/liblwgeom/cunit/cu_ptarray.c index 9082a7233..50e518b0a 100644 --- a/liblwgeom/cunit/cu_ptarray.c +++ b/liblwgeom/cunit/cu_ptarray.c @@ -59,7 +59,84 @@ static void test_ptarray_append_point(void) static void test_ptarray_append_ptarray(void) { - /* TODO: add tests here ! */ + LWLINE *line1, *line2; + int ret; + char *wkt; + + /* Empty first line */ + line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); + line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10,5 5)")); + ret = ptarray_append_ptarray(line1->points, line2->points, -1); + CU_ASSERT(ret == LW_SUCCESS); + wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); + CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,0 10,5 5)"); + lwfree(wkt); + lwline_free(line2); + lwline_free(line1); + + /* Empty second line */ + line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0, 5 5, 6 3)")); + line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); + ret = ptarray_append_ptarray(line1->points, line2->points, -1); + CU_ASSERT(ret == LW_SUCCESS); + wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); + CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,5 5,6 3)"); + lwfree(wkt); + lwline_free(line2); + lwline_free(line1); + + /* Both lines empty */ + line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); + line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING EMPTY")); + ret = ptarray_append_ptarray(line1->points, line2->points, -1); + CU_ASSERT(ret == LW_SUCCESS); + wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); + CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING EMPTY"); + lwfree(wkt); + lwline_free(line2); + lwline_free(line1); + + /* Sane sewing */ + line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)")); + line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5 7,12 43, 42 15)")); + ret = ptarray_append_ptarray(line1->points, line2->points, 0); + CU_ASSERT(ret == LW_SUCCESS); + wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); + CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(10 4,0 0,5 7,12 43,42 15)"); + lwfree(wkt); + lwline_free(line2); + lwline_free(line1); + + /* Untolerated sewing */ + line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)")); + line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5.5 7,12 43, 42 15)")); + ret = ptarray_append_ptarray(line1->points, line2->points, 0); + CU_ASSERT(ret == LW_FAILURE); + lwline_free(line2); + lwline_free(line1); + + /* Tolerated sewing */ + line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(10 4, 0 0,5 7)")); + line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(5.5 7,12 43, 42 15)")); + ret = ptarray_append_ptarray(line1->points, line2->points, .7); + CU_ASSERT(ret == LW_SUCCESS); + wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); + CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(10 4,0 0,5 7,5.5 7,12 43,42 15)"); + lwfree(wkt); + lwline_free(line2); + lwline_free(line1); + + /* Check user input trust (creates non-simple line */ + line1 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10)")); + line2 = lwgeom_as_lwline(lwgeom_from_text("LINESTRING(0 0,0 10)")); + ret = ptarray_append_ptarray(line1->points, line2->points, -1); + CU_ASSERT(ret == LW_SUCCESS); + wkt = lwgeom_to_text(lwline_as_lwgeom(line1)); + CU_ASSERT_STRING_EQUAL(wkt, "LINESTRING(0 0,0 10,0 0,0 10)"); + lwfree(wkt); + lwline_free(line2); + lwline_free(line1); + } static void test_ptarray_locate_point(void) diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index c5282f446..30a715536 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -793,11 +793,17 @@ extern POINTARRAY* ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoi extern int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates); /** -* Append a #POINTARRAY, pa2 to the end of an existing #POINTARRAY, pa1. -* If splice_ends is LW_TRUE, then duplicate points and the end of pa1 and -* start of pa2 will be removed. -*/ -extern int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, int splice_ends); + * Append a #POINTARRAY, pa2 to the end of an existing #POINTARRAY, pa1. + * + * If gap_tolerance is >= 0 then the end point of pa1 will be checked for + * being within gap_tolerance 2d distance from start point of pa2 or an + * error will be raised and LW_FAILURE returned. + * A gap_tolerance < 0 disables the check. + * + * If end point of pa1 and start point of pa2 are 2d-equal, then pa2 first + * point will not be appended. + */ +extern int ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance); /** * Insert a point into an existing #POINTARRAY. Zero diff --git a/liblwgeom/ptarray.c b/liblwgeom/ptarray.c index 701996bd7..cd24c6316 100644 --- a/liblwgeom/ptarray.c +++ b/liblwgeom/ptarray.c @@ -167,8 +167,12 @@ ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int repeated_points) } int -ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, int splice_ends) +ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, double gap_tolerance) { + unsigned int poff = 0; + unsigned int npoints; + unsigned int ncap; + unsigned int ptsize; /* Check for pathology */ if( ! pa1 || ! pa2 ) @@ -176,34 +180,54 @@ ptarray_append_ptarray(POINTARRAY *pa1, POINTARRAY *pa2, int splice_ends) lwerror("ptarray_append_ptarray: null input"); return LW_FAILURE; } + + npoints = pa2->npoints; + if ( ! npoints ) return LW_SUCCESS; /* nothing more to do */ + if( pa1->flags != pa2->flags ) { lwerror("ptarray_append_ptarray: appending mixed dimensionality is not allowed"); return LW_FAILURE; } + ptsize = ptarray_point_size(pa1); + /* Check for duplicate end point */ - if ( splice_ends && pa1->npoints > 0 && pa2->npoints > 0 ) + if ( pa1->npoints ) { - POINT4D tmp1, tmp2; - getPoint4d_p(pa1, pa1->npoints-1, &tmp1); - getPoint4d_p(pa2, 0, &tmp2); - - /* If the end point and start point are the same, then strip off the end point */ - if (p4d_same(&tmp1, &tmp2)) - { - pa1->npoints--; + POINT2D tmp1, tmp2; + getPoint2d_p(pa1, pa1->npoints-1, &tmp1); + getPoint2d_p(pa2, 0, &tmp2); + + /* If the end point and start point are the same, then don't copy start point */ + if (p2d_same(&tmp1, &tmp2)) { + poff = 1; + --npoints; } + else if ( gap_tolerance == 0 || ( gap_tolerance > 0 && + distance2d_pt_pt(&tmp1, &tmp2) > gap_tolerance ) ) + { + lwerror("Second line start point too far from first line end point"); + return LW_FAILURE; + } } - + /* Check if we need extra space */ - if ( pa1->maxpoints - pa1->npoints - pa2->npoints < 0 ) + ncap = pa1->npoints + npoints; + if ( pa1->maxpoints < ncap ) { - + pa1->maxpoints = ncap > pa1->maxpoints*2 ? + ncap : pa1->maxpoints*2; + pa1->serialized_pointlist = lwrealloc(pa1->serialized_pointlist, ptsize * pa1->maxpoints); } - return 0; + memcpy(getPoint_internal(pa1, pa1->npoints), + getPoint_internal(pa2, poff), ptsize * npoints); + + pa1->npoints = ncap; + + return LW_SUCCESS; } /*