]> granicus.if.org Git - postgis/commitdiff
Implement ptarray_append_ptarray, and change its signature
authorSandro Santilli <strk@keybit.net>
Thu, 26 Jan 2012 09:16:37 +0000 (09:16 +0000)
committerSandro Santilli <strk@keybit.net>
Thu, 26 Jan 2012 09:16:37 +0000 (09:16 +0000)
This is propedeutic to ticket #1500

git-svn-id: http://svn.osgeo.org/postgis/trunk@8926 b70326c6-7e19-0410-871a-916f4a2858ee

liblwgeom/cunit/cu_ptarray.c
liblwgeom/liblwgeom.h.in
liblwgeom/ptarray.c

index 9082a7233d5e216c6e6a2bb9c9874149bf5da8bb..50e518b0abfe77edd1a47ebf03ae4c4c85950b7e 100644 (file)
@@ -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)
index c5282f446cef182767b57c9a14f5f52e5b075dd5..30a715536fcbdb10426ca321f969041c833e028e 100644 (file)
@@ -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
index 701996bd7c9f76604ac9ed9a4599345f75fe2fb1..cd24c6316824ec23e69a5aa1d1112d43e3266407 100644 (file)
@@ -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;
 }
 
 /*