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)
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
}
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 )
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;
}
/*