1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * Copyright (C) 2011-2015 Sandro Santilli <strk@kbt.io>
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU General Public Licence. See the COPYING file.
10  *
11  **********************************************************************/
12 
13 #include "CUnit/Basic.h"
14 #include "cu_tester.h"
15 
16 #include "liblwgeom.h"
17 #include "liblwgeom_internal.h"
18 #include "../lwgeom_geos.h"
19 
test_lwline_split_by_point_to(void)20 static void test_lwline_split_by_point_to(void)
21 {
22 	LWLINE *line;
23 	LWPOINT *point;
24 	LWMLINE *coll;
25 	int ret;
26 
27 	/* Because i don't trust that much prior tests...  ;) */
28 	cu_error_msg_reset();
29 
30 	coll = lwmline_construct_empty(SRID_UNKNOWN, 0, 0);
31 	CU_ASSERT_EQUAL(coll->ngeoms, 0);
32 
33 	line = lwgeom_as_lwline(lwgeom_from_wkt("LINESTRING(0 0,5 5, 10 0)",
34 		LW_PARSER_CHECK_NONE));
35 	CU_ASSERT(line != NULL);
36 
37 	point = lwgeom_as_lwpoint(lwgeom_from_wkt(
38 		"POINT(0 0)",
39 		LW_PARSER_CHECK_NONE));
40 	ret = lwline_split_by_point_to(line, point, coll);
41 	CU_ASSERT_EQUAL(ret, 1);
42 	CU_ASSERT_EQUAL(coll->ngeoms, 0);
43 	lwpoint_free(point);
44 
45 	point = lwgeom_as_lwpoint(lwgeom_from_wkt(
46 		"POINT(10 0)",
47 		LW_PARSER_CHECK_NONE));
48 	ret = lwline_split_by_point_to(line, point, coll);
49 	CU_ASSERT_EQUAL(ret, 1);
50 	CU_ASSERT_EQUAL(coll->ngeoms, 0);
51 	lwpoint_free(point);
52 
53 	point = lwgeom_as_lwpoint(lwgeom_from_wkt(
54 		"POINT(5 0)",
55 		LW_PARSER_CHECK_NONE));
56 	ret = lwline_split_by_point_to(line, point, coll);
57 	CU_ASSERT_EQUAL(ret, 0);
58 	CU_ASSERT_EQUAL(coll->ngeoms, 0);
59 	lwpoint_free(point);
60 
61 	point = lwgeom_as_lwpoint(lwgeom_from_wkt(
62 		"POINT(5 5)",
63 		LW_PARSER_CHECK_NONE));
64 	ret = lwline_split_by_point_to(line, point, coll);
65 	CU_ASSERT_EQUAL(ret, 2);
66 	CU_ASSERT_EQUAL(coll->ngeoms, 2);
67 	lwpoint_free(point);
68 
69 	point = lwgeom_as_lwpoint(lwgeom_from_wkt(
70 		"POINT(2 2)",
71 		LW_PARSER_CHECK_NONE));
72 	ret = lwline_split_by_point_to(line, point, coll);
73 	CU_ASSERT_EQUAL(ret, 2);
74 	CU_ASSERT_EQUAL(coll->ngeoms, 4);
75 	lwpoint_free(point);
76 
77 	lwcollection_free((LWCOLLECTION*)coll);
78 	lwline_free(line);
79 }
80 
test_lwgeom_split(void)81 static void test_lwgeom_split(void)
82 {
83 	LWGEOM *geom, *blade, *ret, *tmp1, *tmp2;
84 	char *wkt, *in_wkt;
85 
86 	geom = lwgeom_from_wkt("MULTILINESTRING((-5 -2,0 0),(0 0,10 10))", LW_PARSER_CHECK_NONE);
87 	CU_ASSERT(geom != NULL);
88 	blade = lwgeom_from_wkt("POINT(0 0)", LW_PARSER_CHECK_NONE);
89 	CU_ASSERT(blade != NULL);
90 	ret = lwgeom_split(geom, blade);
91 	CU_ASSERT(ret != NULL);
92 	wkt = lwgeom_to_ewkt(ret);
93 	in_wkt = "GEOMETRYCOLLECTION(LINESTRING(-5 -2,0 0),LINESTRING(0 0,10 10))";
94 	ASSERT_STRING_EQUAL(wkt, in_wkt);
95 	lwfree(wkt);
96 	lwgeom_free(ret);
97 	lwgeom_free(geom);
98 	lwgeom_free(blade);
99 
100         /* See #1311 */
101 	geom = lwgeom_from_wkt("LINESTRING(0 0,10 0,20 4,0 3)", LW_PARSER_CHECK_NONE);
102 	CU_ASSERT(geom != NULL);
103 	blade = lwgeom_from_wkt("POINT(10 0)", LW_PARSER_CHECK_NONE);
104 	ret = lwgeom_split(geom, blade);
105 	CU_ASSERT(ret != NULL);
106 	wkt = lwgeom_to_ewkt(ret);
107 	in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,10 0),LINESTRING(10 0,20 4,0 3))";
108 	ASSERT_STRING_EQUAL(wkt, in_wkt);
109 	lwfree(wkt);
110 	lwgeom_free(ret);
111 	lwgeom_free(geom);
112 	lwgeom_free(blade);
113 
114   /* See #2528 (1) -- memory leak test, needs valgrind to check */
115 	geom = lwgeom_from_wkt("SRID=1;LINESTRING(0 1,10 1)", LW_PARSER_CHECK_NONE);
116 	CU_ASSERT(geom != NULL);
117 	blade = lwgeom_from_wkt("LINESTRING(7 0,7 3)", LW_PARSER_CHECK_NONE);
118 	ret = lwgeom_split(geom, blade);
119 	CU_ASSERT(ret != NULL);
120 	wkt = lwgeom_to_ewkt(ret);
121 	in_wkt = "SRID=1;GEOMETRYCOLLECTION(LINESTRING(0 1,7 1),LINESTRING(7 1,10 1))";
122 	ASSERT_STRING_EQUAL(wkt, in_wkt);
123 	lwfree(wkt);
124 	lwgeom_free(ret);
125 	lwgeom_free(geom);
126 	lwgeom_free(blade);
127 
128   /* See #2528 (2) -- memory leak test, needs valgrind to check */
129 	geom = lwgeom_from_wkt("SRID=1;POLYGON((0 1, 10 1, 10 10, 0 10, 0 1))", LW_PARSER_CHECK_NONE);
130 	CU_ASSERT(geom != NULL);
131 	blade = lwgeom_from_wkt("LINESTRING(7 0,7 20)", LW_PARSER_CHECK_NONE);
132 	tmp1 = lwgeom_split(geom, blade);
133 	ret = lwgeom_normalize(tmp1);
134 	lwgeom_free(tmp1);
135 	CU_ASSERT(ret != NULL);
136 	wkt = lwgeom_to_ewkt(ret);
137 	tmp1 = lwgeom_from_wkt(
138 	    "SRID=1;GEOMETRYCOLLECTION(POLYGON((7 1,0 1,0 10,7 10,7 1)),POLYGON((7 10,10 10,10 1,7 1,7 10)))",
139 	    LW_PARSER_CHECK_NONE);
140 	tmp2 = lwgeom_normalize(tmp1);
141 	in_wkt = lwgeom_to_ewkt(tmp2);
142 	ASSERT_STRING_EQUAL(wkt, in_wkt);
143 	lwfree(wkt);
144 	lwfree(in_wkt);
145 	lwgeom_free(tmp1);
146 	lwgeom_free(tmp2);
147 	lwgeom_free(ret);
148 	lwgeom_free(geom);
149 	lwgeom_free(blade);
150 
151   /* Split line by multiline */
152 	geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE);
153 	CU_ASSERT_FATAL(geom != NULL);
154 	blade = lwgeom_from_wkt("MULTILINESTRING((1 1,1 -1),(2 1,2 -1,3 -1,3 1))", LW_PARSER_CHECK_NONE);
155 	ret = lwgeom_split(geom, blade);
156 	if (!ret)
157 		printf("%s", cu_error_msg);
158 	CU_ASSERT_FATAL(ret != NULL);
159 	wkt = lwgeom_to_ewkt(ret);
160 	CU_ASSERT_FATAL(wkt != NULL);
161 	in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))";
162 	ASSERT_STRING_EQUAL(wkt, in_wkt);
163 	lwfree(wkt);
164 	lwgeom_free(ret);
165 	lwgeom_free(geom);
166 	lwgeom_free(blade);
167 
168   /* Split line by polygon (boundary) */
169 	geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE);
170 	CU_ASSERT_FATAL(geom != NULL);
171 	blade = lwgeom_from_wkt("POLYGON((1 -2,1 1,2 1,2 -1,3 -1,3 1,11 1,11 -2,1 -2))", LW_PARSER_CHECK_NONE);
172 	ret = lwgeom_split(geom, blade);
173 	if (!ret)
174 		printf("%s", cu_error_msg);
175 	CU_ASSERT_FATAL(ret != NULL);
176 	wkt = lwgeom_to_ewkt(ret);
177 	CU_ASSERT_FATAL(wkt != NULL);
178 	in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))";
179 	ASSERT_STRING_EQUAL(wkt, in_wkt);
180 	lwfree(wkt);
181 	lwgeom_free(ret);
182 	lwgeom_free(geom);
183 	lwgeom_free(blade);
184 
185 	/* Split line by EMPTY polygon (boundary) */
186 	geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE);
187 	CU_ASSERT_FATAL(geom != NULL);
188 	blade = lwgeom_from_wkt("POLYGON EMPTY", LW_PARSER_CHECK_NONE);
189 	ret = lwgeom_split(geom, blade);
190 	if (!ret)
191 		printf("%s", cu_error_msg);
192 	CU_ASSERT_FATAL(ret != NULL);
193 	wkt = lwgeom_to_ewkt(ret);
194 	CU_ASSERT_FATAL(wkt != NULL);
195 	in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,10 0))";
196 	ASSERT_STRING_EQUAL(wkt, in_wkt);
197 	lwfree(wkt);
198 	lwgeom_free(ret);
199 	lwgeom_free(geom);
200 	lwgeom_free(blade);
201 
202   /* Split line by multipolygon (boundary) */
203 	geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE);
204 	CU_ASSERT_FATAL(geom != NULL);
205 	blade = lwgeom_from_wkt("MULTIPOLYGON(((1 -1,1 1,2 1,2 -1,1 -1)),((3 -1,3 1,11 1,11 -1,3 -1)))",
206 				LW_PARSER_CHECK_NONE);
207 	ret = lwgeom_split(geom, blade);
208 	if (!ret)
209 		printf("%s", cu_error_msg);
210 	CU_ASSERT_FATAL(ret != NULL);
211 	wkt = lwgeom_to_ewkt(ret);
212 	CU_ASSERT_FATAL(wkt != NULL);
213 	in_wkt = "GEOMETRYCOLLECTION(LINESTRING(0 0,1 0),LINESTRING(1 0,2 0),LINESTRING(2 0,3 0),LINESTRING(3 0,10 0))";
214 	ASSERT_STRING_EQUAL(wkt, in_wkt);
215 	lwfree(wkt);
216 	lwgeom_free(ret);
217 	lwgeom_free(geom);
218 	lwgeom_free(blade);
219 
220 	/* Split line by multipoint */
221 	geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE);
222 	CU_ASSERT_FATAL(geom != NULL);
223 	blade = lwgeom_from_wkt("MULTIPOINT(2 0,8 0,4 0)", LW_PARSER_CHECK_NONE);
224 	ret = lwgeom_split(geom, blade);
225 	if (!ret)
226 		printf("%s", cu_error_msg);
227 	CU_ASSERT_FATAL(ret != NULL);
228 	wkt = lwgeom_to_ewkt(ret);
229 	CU_ASSERT_FATAL(wkt != NULL);
230 	in_wkt = "GEOMETRYCOLLECTION(LINESTRING(8 0,10 0),LINESTRING(0 0,2 0),LINESTRING(4 0,8 0),LINESTRING(2 0,4 0))";
231 	ASSERT_STRING_EQUAL(wkt, in_wkt);
232 	lwfree(wkt);
233 	lwgeom_free(ret);
234 	lwgeom_free(geom);
235 	lwgeom_free(blade);
236 
237 	/* See #3401 -- robustness issue */
238 	geom = lwgeom_from_wkt("LINESTRING(-180 0,0 0)", LW_PARSER_CHECK_NONE);
239 	CU_ASSERT(geom != NULL);
240 	blade = lwgeom_from_wkt("POINT(-20 0)", LW_PARSER_CHECK_NONE);
241 	ret = lwgeom_split(geom, blade);
242 	CU_ASSERT(ret != NULL);
243 	{
244 		LWCOLLECTION *split = lwgeom_as_lwcollection(ret);
245 		LWLINE *l1, *l2;
246 		POINT2D pt;
247 		CU_ASSERT(split != NULL);
248 		l1 = lwgeom_as_lwline(split->geoms[0]);
249 		CU_ASSERT(l1 != NULL);
250 		getPoint2d_p(l1->points, 1, &pt);
251 		ASSERT_DOUBLE_EQUAL(pt.x, -20);
252 		ASSERT_DOUBLE_EQUAL(pt.y, 0);
253 		l2 = lwgeom_as_lwline(split->geoms[1]);
254 		CU_ASSERT(l2 != NULL);
255 		getPoint2d_p(l2->points, 0, &pt);
256 		ASSERT_DOUBLE_EQUAL(pt.x, -20);
257 		ASSERT_DOUBLE_EQUAL(pt.y, 0);
258 	}
259 	lwgeom_free(ret);
260 	lwgeom_free(geom);
261 	lwgeom_free(blade);
262 }
263 
264 static int
clean_geos_split_suite(void)265 clean_geos_split_suite(void)
266 {
267 	finishGEOS();
268 	return 0;
269 }
270 
271 /*
272 ** Used by test harness to register the tests in this file.
273 */
274 void split_suite_setup(void);
split_suite_setup(void)275 void split_suite_setup(void)
276 {
277 	CU_pSuite suite = CU_add_suite("split", NULL, clean_geos_split_suite);
278 	PG_ADD_TEST(suite, test_lwline_split_by_point_to);
279 	PG_ADD_TEST(suite, test_lwgeom_split);
280 }
281