1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  * Copyright 2014 Nicklas Avén
6  *
7  * This is free software; you can redistribute and/or modify it under
8  * the terms of the GNU General Public Licence. See the COPYING file.
9  *
10  **********************************************************************/
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include "CUnit/Basic.h"
16 
17 #include "liblwgeom_internal.h"
18 #include "cu_tester.h"
19 
20 
21 /*
22 ** Global variable to hold hex TWKB strings
23 */
24 char *s;
25 char *w;
26 
27 /*
28 ** The suite initialization function.
29 ** Create any re-used objects.
30 */
init_twkb_out_suite(void)31 static int init_twkb_out_suite(void)
32 {
33 	s = NULL;
34 	w = NULL;
35 	return 0;
36 }
37 
38 /*
39 ** The suite cleanup function.
40 ** Frees any global objects.
41 */
clean_twkb_out_suite(void)42 static int clean_twkb_out_suite(void)
43 {
44 	if (s) free(s);
45 	if (w) free(w);
46 	s = NULL;
47 	w = NULL;
48 	return 0;
49 }
50 
51 
52 /*
53 ** Creating an input TWKB from a wkt string
54 */
cu_twkb(char * wkt,int8_t prec_xy,int8_t prec_z,int8_t prec_m,uint8_t variant)55 static void cu_twkb(char *wkt, int8_t prec_xy, int8_t prec_z, int8_t prec_m, uint8_t variant)
56 {
57 	LWGEOM *g = lwgeom_from_wkt(wkt, LW_PARSER_CHECK_NONE);
58 	size_t twkb_size;
59 	uint8_t *twkb;
60 	if ( ! g )  lwnotice("input wkt is invalid: %s", wkt);
61 	twkb = lwgeom_to_twkb(g, variant, prec_xy,  prec_z, prec_m, &twkb_size);
62 	lwgeom_free(g);
63 	if ( s ) free(s);
64 	s = hexbytes_from_bytes(twkb, twkb_size);
65 	free(twkb);
66 }
67 
68 
69 /*
70 ** Creating an input TWKB from a wkt string
71 */
cu_twkb_idlist(char * wkt,int64_t * idlist,int8_t prec_xy,int8_t prec_z,int8_t prec_m,uint8_t variant)72 static void cu_twkb_idlist(char *wkt, int64_t *idlist, int8_t prec_xy, int8_t prec_z, int8_t prec_m, uint8_t variant)
73 {
74 	LWGEOM *g = lwgeom_from_wkt(wkt, LW_PARSER_CHECK_NONE);
75 	LWGEOM *g_b;
76 	size_t twkb_size;
77 	uint8_t *twkb;
78 	if ( ! g )  lwnotice("input wkt is invalid: %s", wkt);
79 	twkb = lwgeom_to_twkb_with_idlist(g, idlist, variant, prec_xy,  prec_z, prec_m, &twkb_size);
80 	lwgeom_free(g);
81 	if ( s ) free(s);
82 	if ( w ) free(w);
83 	s = hexbytes_from_bytes(twkb, twkb_size);
84 	g_b = lwgeom_from_twkb(twkb, twkb_size, LW_PARSER_CHECK_NONE);
85 	w = lwgeom_to_ewkt(g_b);
86 	lwgeom_free(g_b);
87 	free(twkb);
88 }
89 
90 
91 
test_twkb_out_point(void)92 static void test_twkb_out_point(void)
93 {
94 
95 	cu_twkb("POINT EMPTY", 0, 0, 0, 0);
96 	CU_ASSERT_STRING_EQUAL(s,"0110");
97 
98 	cu_twkb("POINT(0 0)", 0, 0, 0, 0);
99 	CU_ASSERT_STRING_EQUAL(s,"01000000");
100 
101 	cu_twkb("POINT(0 0 0 0)", 0, 0, 0, 0);
102 	CU_ASSERT_STRING_EQUAL(s,"01080300000000");
103 
104 	/* Point with bounding box */
105 	cu_twkb("POINT(0 0)", 0, 0, 0, TWKB_BBOX);
106 	CU_ASSERT_STRING_EQUAL(s,"0101000000000000");
107 	// printf("TWKB: %s\n",s);
108 
109 	/* Adding a size paramters to X/Y */
110 	cu_twkb("POINT(0 0)", 0, 0, 0, TWKB_SIZE);
111 	CU_ASSERT_STRING_EQUAL(s,"0102020000");
112 
113 	/* Adding a size paramters to X/Y/M */
114 	cu_twkb("POINTM(0 0 0)", 0, 0, 0, TWKB_SIZE);
115 	CU_ASSERT_STRING_EQUAL(s,"010A0203000000");
116 
117 	/* Adding a size paramters to X/Y/Z/M */
118 	cu_twkb("POINT(0 0 0 0)", 0, 0, 0, TWKB_SIZE);
119 	CU_ASSERT_STRING_EQUAL(s,"010A030400000000");
120 
121 	/* Since the third dimension is Z it shall get a precision of 1 decimal (third argument) */
122 	cu_twkb("POINTZ(1 1 1)", 0,1,2, 0);
123 	CU_ASSERT_STRING_EQUAL(s,"010845020214");
124 
125 	/* Since the third dimension is M it shall get a precision of 2 decimals (fourth argument) */
126 	cu_twkb("POINTM(1 1 1)", 0,1,2, 0);
127 	// printf("\n%s\n", s);
128 	CU_ASSERT_STRING_EQUAL(s,"0108460202C801");
129 }
130 
test_twkb_out_linestring(void)131 static void test_twkb_out_linestring(void)
132 {
133 
134 	cu_twkb("LINESTRING(0 0,1 1)", 0, 0, 0, 0);
135 	CU_ASSERT_STRING_EQUAL(s,"02000200000202");
136 	// printf("TWKB: %s\n",s);
137 
138 	cu_twkb("LINESTRING(0 0 1,1 1 2,2 2 3)", 0, 0, 0, 0);
139 	CU_ASSERT_STRING_EQUAL(s,"02080103000002020202020202");
140 	// printf("TWKB: %s\n",s);
141 
142 	/* Line with bounding box */
143 	cu_twkb("LINESTRING(0 0,1 1,2 2)", 0, 0, 0, TWKB_BBOX);
144 	CU_ASSERT_STRING_EQUAL(s,"02010004000403000002020202");
145 	// printf("TWKB: %s\n",s);
146 
147 	cu_twkb("LINESTRING EMPTY", 0, 0, 0, 0);
148 	CU_ASSERT_STRING_EQUAL(s,"0210");
149 	// printf("TWKB: %s\n",s);
150 }
151 
test_twkb_out_polygon(void)152 static void test_twkb_out_polygon(void)
153 {
154 	cu_twkb("SRID=4;POLYGON((0 0 0, 0 1 0,1 1 0,1 0 0, 0 0 0))", 0, 0, 0, 0);
155 	CU_ASSERT_STRING_EQUAL(s,"0308010105000000000200020000000100010000");
156 	// printf("TWKB: %s\n",s);
157 
158 	cu_twkb("SRID=14;POLYGON((0 0 0 1, 0 1 0 2,1 1 0 3,1 0 0 4, 0 0 0 5))", 0, 0, 0, 0);
159 	CU_ASSERT_STRING_EQUAL(s,"03080301050000000200020002020000020001000201000002");
160 	// printf("TWKB: %s\n",s);
161 
162 	cu_twkb("POLYGON EMPTY", 0, 0, 0, 0);
163 	CU_ASSERT_STRING_EQUAL(s,"0310");
164 	// printf("TWKB: %s\n",s);
165 }
166 
test_twkb_out_multipoint(void)167 static void test_twkb_out_multipoint(void)
168 {
169 	cu_twkb("MULTIPOINT(0 0 0, 0 1 0,1 1 0,1 0 0, 0 0 0)", 0, 0, 0, 0);
170 	CU_ASSERT_STRING_EQUAL(s,"04080105000000000200020000000100010000");
171 
172 	cu_twkb("MULTIPOINT(0 0 0, 0.26794919243112270647255365849413 1 3)",7 ,7 , 0, 0);
173 	//printf("WKB: %s",s);
174 	CU_ASSERT_STRING_EQUAL(s,"E4081D02000000888BC70280DAC409808ECE1C");
175 //	printf("TWKB: %s\n",s);
176 }
177 
test_twkb_out_multilinestring(void)178 static void test_twkb_out_multilinestring(void) {}
179 
test_twkb_out_multipolygon(void)180 static void test_twkb_out_multipolygon(void)
181 {
182 	cu_twkb("MULTIPOLYGON(((0 0 0, 0 1 0,1 1 0,1 0 0, 0 0 0)),((-1 -1 0,-1 2 0,2 2 0,2 -1 0,-1 -1 0),(0 0 0, 0 1 0,1 1 0,1 0 0, 0 0 0)))", 0, 0, 0, 0);
183 	CU_ASSERT_STRING_EQUAL(s,"060801020105000000000200020000000100010000020501010000060006000000050005000005020200000200020000000100010000");
184 }
185 
test_twkb_out_collection(void)186 static void test_twkb_out_collection(void)
187 {
188 	cu_twkb("GEOMETRYCOLLECTION(LINESTRING(1 1, 2 2), LINESTRING(3 3, 4 4), LINESTRING(5 5, 6 6))", 0, 0, 0, 0);
189 	// printf("TWKB: %s\n",s);
190 	CU_ASSERT_STRING_EQUAL(s,"07000302000202020202020002060602020200020A0A0202");
191 
192 	cu_twkb("GEOMETRYCOLLECTION(POLYGON((0 0 0, 0 1 0,1 1 0,1 0 0, 0 0 0)),POINT(1 1 1))", 0, 0, 0, 0);
193 	// printf("TWKB: %s\n",s);
194 	CU_ASSERT_STRING_EQUAL(s,"070801020308010105000000000200020000000100010000010801020202");
195 
196 	cu_twkb("GEOMETRYCOLLECTION EMPTY", 0, 0, 0, 0);
197 	CU_ASSERT_STRING_EQUAL(s,"0710");
198 }
199 
test_twkb_out_idlist(void)200 static void test_twkb_out_idlist(void)
201 {
202 	int64_t idlist[2];
203 
204 	idlist[0] = 2;
205 	idlist[1] = 4;
206 	cu_twkb_idlist("MULTIPOINT(1 1, 0 0)",idlist, 0, 0, 0, 0);
207 	// printf("TWKB: %s\n",s);
208 	// printf("WKT: %s\n",w);
209 	CU_ASSERT_STRING_EQUAL(s,"040402040802020101");
210 	CU_ASSERT_STRING_EQUAL(w,"MULTIPOINT(1 1,0 0)");
211 
212 	/*
213 	04 06 multipoint, size/idlist
214 	07 size 7 bytes
215 	02 two geometries
216 	0408 idlist (2, 4)
217 	0202 first point @ 1,1
218 	0101 second point offset -1,-1
219 	*/
220 	idlist[0] = 2;
221 	idlist[1] = 4;
222 	cu_twkb_idlist("MULTIPOINT(1 1, 0 0)",idlist, 0, 0, 0, TWKB_SIZE);
223 	// printf("TWKB: %s\n",s);
224 	// printf("WKT: %s\n",w);
225 	CU_ASSERT_STRING_EQUAL(s,"04060702040802020101");
226 	CU_ASSERT_STRING_EQUAL(w,"MULTIPOINT(1 1,0 0)");
227 
228 	/*
229 	04 07 multipoint, bbox/size/idlist
230 	0B size 11 bytes
231 	00020002 bbox x(0,1), y(0,1)
232 	02 two geometries
233 	0408 idlist (2,4)
234 	0202 first point @ 1,1
235 	0101 seconds point offset -1,-1
236 	*/
237 	idlist[0] = 2;
238 	idlist[1] = 4;
239 	cu_twkb_idlist("MULTIPOINT(1 1, 0 0)",idlist, 0, 0, 0, TWKB_SIZE | TWKB_BBOX);
240 	// printf("TWKB: %s\n",s);
241 	// printf("WKT: %s\n",w);
242 	CU_ASSERT_STRING_EQUAL(s,"04070B0002000202040802020101");
243 	CU_ASSERT_STRING_EQUAL(w,"MULTIPOINT(1 1,0 0)");
244 
245 	/*
246 	0704 geometrycollection, idlist
247 	02 two geometries
248 	0408 idlist (2,4)
249 	01000202 first point (type, meta, x, y)
250 	01000000 second point (type, meta, x, y)
251 	*/
252 	idlist[0] = 2;
253 	idlist[1] = 4;
254 	cu_twkb_idlist("GEOMETRYCOLLECTION(POINT(1 1),POINT(0 0))",idlist, 0, 0, 0, 0);
255 	// printf("TWKB: %s\n",s);
256 	CU_ASSERT_STRING_EQUAL(s,"07040204080100020201000000");
257 	CU_ASSERT_STRING_EQUAL(w,"GEOMETRYCOLLECTION(POINT(1 1),POINT(0 0))");
258 
259 	/*
260 	0706 geometrycollection, size/idlist
261 	0D size, 13 bytes
262 	02 two geometries
263 	0408 idlist (2,4)
264 	0102020202 first point (type, meta, size, x, y)
265 	0102020000 second point (type, meta, size, x, y)
266 	*/
267 	idlist[0] = 2;
268 	idlist[1] = 4;
269 	cu_twkb_idlist("GEOMETRYCOLLECTION(POINT(1 1),POINT(0 0))",idlist, 0, 0, 0, TWKB_SIZE);
270 	// printf("TWKB: %s\n",s);
271 	CU_ASSERT_STRING_EQUAL(s,"07060D02040801020202020102020000");
272 	CU_ASSERT_STRING_EQUAL(w,"GEOMETRYCOLLECTION(POINT(1 1),POINT(0 0))");
273 
274 }
275 
276 
277 /*
278 ** Used by test harness to register the tests in this file.
279 */
280 void twkb_out_suite_setup(void);
twkb_out_suite_setup(void)281 void twkb_out_suite_setup(void)
282 {
283 	CU_pSuite suite = CU_add_suite("twkb_output", init_twkb_out_suite, clean_twkb_out_suite);
284 	PG_ADD_TEST(suite, test_twkb_out_point);
285 	PG_ADD_TEST(suite, test_twkb_out_linestring);
286 	PG_ADD_TEST(suite, test_twkb_out_polygon);
287 	PG_ADD_TEST(suite, test_twkb_out_multipoint);
288 	PG_ADD_TEST(suite, test_twkb_out_multilinestring);
289 	PG_ADD_TEST(suite, test_twkb_out_multipolygon);
290 	PG_ADD_TEST(suite, test_twkb_out_collection);
291 	PG_ADD_TEST(suite, test_twkb_out_idlist);
292 }
293