1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2001-2006 Refractions Research Inc.
22  *
23  **********************************************************************/
24 
25 
26 /* basic LWCIRCSTRING functions */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include "liblwgeom_internal.h"
32 #include "lwgeom_log.h"
33 
34 void printLWCIRCSTRING(LWCIRCSTRING *curve);
35 void lwcircstring_release(LWCIRCSTRING *lwcirc);
36 char lwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you);
37 LWCIRCSTRING *lwcircstring_from_lwpointarray(int32_t srid, uint32_t npoints, LWPOINT **points);
38 LWCIRCSTRING *lwcircstring_from_lwmpoint(int32_t srid, LWMPOINT *mpoint);
39 LWCIRCSTRING *lwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, uint32_t where);
40 LWCIRCSTRING *lwcircstring_removepoint(LWCIRCSTRING *curve, uint32_t index);
41 void lwcircstring_setPoint4d(LWCIRCSTRING *curve, uint32_t index, POINT4D *newpoint);
42 
43 
44 
45 /*
46  * Construct a new LWCIRCSTRING.  points will *NOT* be copied
47  * use SRID=SRID_UNKNOWN for unknown SRID (will have 8bit type's S = 0)
48  */
49 LWCIRCSTRING *
lwcircstring_construct(int32_t srid,GBOX * bbox,POINTARRAY * points)50 lwcircstring_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
51 {
52 	LWCIRCSTRING *result;
53 
54 	/*
55 	* The first arc requires three points.  Each additional
56 	* arc requires two more points.  Thus the minimum point count
57 	* is three, and the count must be odd.
58 	*/
59 	if (points->npoints % 2 != 1 || points->npoints < 3)
60 	{
61 		lwnotice("lwcircstring_construct: invalid point count %d", points->npoints);
62 	}
63 
64 	result = (LWCIRCSTRING*) lwalloc(sizeof(LWCIRCSTRING));
65 
66 	result->type = CIRCSTRINGTYPE;
67 
68 	result->flags = points->flags;
69 	FLAGS_SET_BBOX(result->flags, bbox?1:0);
70 
71 	result->srid = srid;
72 	result->points = points;
73 	result->bbox = bbox;
74 
75 	return result;
76 }
77 
78 LWCIRCSTRING *
lwcircstring_construct_empty(int32_t srid,char hasz,char hasm)79 lwcircstring_construct_empty(int32_t srid, char hasz, char hasm)
80 {
81 	LWCIRCSTRING *result = lwalloc(sizeof(LWCIRCSTRING));
82 	result->type = CIRCSTRINGTYPE;
83 	result->flags = lwflags(hasz,hasm,0);
84 	result->srid = srid;
85 	result->points = ptarray_construct_empty(hasz, hasm, 1);
86 	result->bbox = NULL;
87 	return result;
88 }
89 
90 void
lwcircstring_release(LWCIRCSTRING * lwcirc)91 lwcircstring_release(LWCIRCSTRING *lwcirc)
92 {
93 	lwgeom_release(lwcircstring_as_lwgeom(lwcirc));
94 }
95 
96 
lwcircstring_free(LWCIRCSTRING * curve)97 void lwcircstring_free(LWCIRCSTRING *curve)
98 {
99 	if ( ! curve ) return;
100 
101 	if ( curve->bbox )
102 		lwfree(curve->bbox);
103 	if ( curve->points )
104 		ptarray_free(curve->points);
105 	lwfree(curve);
106 }
107 
108 
109 
printLWCIRCSTRING(LWCIRCSTRING * curve)110 void printLWCIRCSTRING(LWCIRCSTRING *curve)
111 {
112 	lwnotice("LWCIRCSTRING {");
113 	lwnotice("    ndims = %i", (int)FLAGS_NDIMS(curve->flags));
114 	lwnotice("    srid = %i", (int)curve->srid);
115 	printPA(curve->points);
116 	lwnotice("}");
117 }
118 
119 /* @brief Clone LWCIRCSTRING object. Serialized point lists are not copied.
120  *
121  * @see ptarray_clone
122  */
123 LWCIRCSTRING *
lwcircstring_clone(const LWCIRCSTRING * g)124 lwcircstring_clone(const LWCIRCSTRING *g)
125 {
126 	return (LWCIRCSTRING *)lwline_clone((LWLINE *)g);
127 }
128 
129 /* check coordinate equality */
130 char
lwcircstring_same(const LWCIRCSTRING * me,const LWCIRCSTRING * you)131 lwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you)
132 {
133 	return ptarray_same(me->points, you->points);
134 }
135 
136 /*
137  * Construct a LWCIRCSTRING from an array of LWPOINTs
138  * LWCIRCSTRING dimensions are large enough to host all input dimensions.
139  */
140 LWCIRCSTRING *
lwcircstring_from_lwpointarray(int32_t srid,uint32_t npoints,LWPOINT ** points)141 lwcircstring_from_lwpointarray(int32_t srid, uint32_t npoints, LWPOINT **points)
142 {
143 	int zmflag=0;
144 	uint32_t i;
145 	POINTARRAY *pa;
146 	uint8_t *newpoints, *ptr;
147 	size_t ptsize, size;
148 
149 	/*
150 	 * Find output dimensions, check integrity
151 	 */
152 	for (i = 0; i < npoints; i++)
153 	{
154 		if (points[i]->type != POINTTYPE)
155 		{
156 			lwerror("lwcurve_from_lwpointarray: invalid input type: %s",
157 			        lwtype_name(points[i]->type));
158 			return NULL;
159 		}
160 		if (FLAGS_GET_Z(points[i]->flags)) zmflag |= 2;
161 		if (FLAGS_GET_M(points[i]->flags)) zmflag |= 1;
162 		if (zmflag == 3) break;
163 	}
164 
165 	if (zmflag == 0) ptsize = 2 * sizeof(double);
166 	else if (zmflag == 3) ptsize = 4 * sizeof(double);
167 	else ptsize = 3 * sizeof(double);
168 
169 	/*
170 	 * Allocate output points array
171 	 */
172 	size = ptsize * npoints;
173 	newpoints = lwalloc(size);
174 	memset(newpoints, 0, size);
175 
176 	ptr = newpoints;
177 	for (i = 0; i < npoints; i++)
178 	{
179 		size = ptarray_point_size(points[i]->point);
180 		memcpy(ptr, getPoint_internal(points[i]->point, 0), size);
181 		ptr += ptsize;
182 	}
183 	pa = ptarray_construct_reference_data(zmflag&2, zmflag&1, npoints, newpoints);
184 
185 	return lwcircstring_construct(srid, NULL, pa);
186 }
187 
188 /*
189  * Construct a LWCIRCSTRING from a LWMPOINT
190  */
191 LWCIRCSTRING *
lwcircstring_from_lwmpoint(int32_t srid,LWMPOINT * mpoint)192 lwcircstring_from_lwmpoint(int32_t srid, LWMPOINT *mpoint)
193 {
194 	uint32_t i;
195 	POINTARRAY *pa;
196 	char zmflag = FLAGS_GET_ZM(mpoint->flags);
197 	size_t ptsize, size;
198 	uint8_t *newpoints, *ptr;
199 
200 	if (zmflag == 0) ptsize = 2 * sizeof(double);
201 	else if (zmflag == 3) ptsize = 4 * sizeof(double);
202 	else ptsize = 3 * sizeof(double);
203 
204 	/* Allocate space for output points */
205 	size = ptsize * mpoint->ngeoms;
206 	newpoints = lwalloc(size);
207 	memset(newpoints, 0, size);
208 
209 	ptr = newpoints;
210 	for (i = 0; i < mpoint->ngeoms; i++)
211 	{
212 		memcpy(ptr,
213 		       getPoint_internal(mpoint->geoms[i]->point, 0),
214 		       ptsize);
215 		ptr += ptsize;
216 	}
217 
218 	pa = ptarray_construct_reference_data(zmflag&2, zmflag&1, mpoint->ngeoms, newpoints);
219 
220 	LWDEBUGF(3, "lwcurve_from_lwmpoint: constructed pointarray for %d points, %d zmflag", mpoint->ngeoms, zmflag);
221 
222 	return lwcircstring_construct(srid, NULL, pa);
223 }
224 
225 LWCIRCSTRING *
lwcircstring_addpoint(LWCIRCSTRING * curve,LWPOINT * point,uint32_t where)226 lwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, uint32_t where)
227 {
228 	POINTARRAY *newpa;
229 	LWCIRCSTRING *ret;
230 
231 	newpa = ptarray_addPoint(curve->points,
232 	                         getPoint_internal(point->point, 0),
233 	                         FLAGS_NDIMS(point->flags), where);
234 	ret = lwcircstring_construct(curve->srid, NULL, newpa);
235 
236 	return ret;
237 }
238 
239 LWCIRCSTRING *
lwcircstring_removepoint(LWCIRCSTRING * curve,uint32_t index)240 lwcircstring_removepoint(LWCIRCSTRING *curve, uint32_t index)
241 {
242 	POINTARRAY *newpa;
243 	LWCIRCSTRING *ret;
244 
245 	newpa = ptarray_removePoint(curve->points, index);
246 	ret = lwcircstring_construct(curve->srid, NULL, newpa);
247 
248 	return ret;
249 }
250 
251 /*
252  * Note: input will be changed, make sure you have permissions for this.
253  * */
254 void
lwcircstring_setPoint4d(LWCIRCSTRING * curve,uint32_t index,POINT4D * newpoint)255 lwcircstring_setPoint4d(LWCIRCSTRING *curve, uint32_t index, POINT4D *newpoint)
256 {
257 	ptarray_set_point4d(curve->points, index, newpoint);
258 }
259 
260 int
lwcircstring_is_closed(const LWCIRCSTRING * curve)261 lwcircstring_is_closed(const LWCIRCSTRING *curve)
262 {
263 	if (lwgeom_has_z((LWGEOM*)curve))
264 		return ptarray_is_closed_3d(curve->points);
265 
266 	return ptarray_is_closed_2d(curve->points);
267 }
268 
lwcircstring_length(const LWCIRCSTRING * circ)269 double lwcircstring_length(const LWCIRCSTRING *circ)
270 {
271 	return lwcircstring_length_2d(circ);
272 }
273 
lwcircstring_length_2d(const LWCIRCSTRING * circ)274 double lwcircstring_length_2d(const LWCIRCSTRING *circ)
275 {
276 	if ( lwcircstring_is_empty(circ) )
277 		return 0.0;
278 
279 	return ptarray_arc_length_2d(circ->points);
280 }
281 
282 /*
283  * Returns freshly allocated #LWPOINT that corresponds to the index where.
284  * Returns NULL if the geometry is empty or the index invalid.
285  */
lwcircstring_get_lwpoint(const LWCIRCSTRING * circ,uint32_t where)286 LWPOINT* lwcircstring_get_lwpoint(const LWCIRCSTRING *circ, uint32_t where) {
287 	POINT4D pt;
288 	LWPOINT *lwpoint;
289 	POINTARRAY *pa;
290 
291 	if ( lwcircstring_is_empty(circ) || where >= circ->points->npoints )
292 		return NULL;
293 
294 	pa = ptarray_construct_empty(FLAGS_GET_Z(circ->flags), FLAGS_GET_M(circ->flags), 1);
295 	pt = getPoint4d(circ->points, where);
296 	ptarray_append_point(pa, &pt, LW_TRUE);
297 	lwpoint = lwpoint_construct(circ->srid, NULL, pa);
298 	return lwpoint;
299 }
300 
301 
302