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