/src/postgis/liblwgeom/lwcircstring.c
Line | Count | Source |
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, const 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 | | * Construct a new LWCIRCSTRING. points will *NOT* be copied |
46 | | * use SRID=SRID_UNKNOWN for unknown SRID (will have 8bit type's S = 0) |
47 | | */ |
48 | | LWCIRCSTRING * |
49 | | lwcircstring_construct(int32_t srid, GBOX *bbox, POINTARRAY *points) |
50 | 2.56k | { |
51 | 2.56k | LWCIRCSTRING *result; |
52 | | |
53 | | /* |
54 | | * The first arc requires three points. Each additional |
55 | | * arc requires two more points. Thus the minimum point count |
56 | | * is three, and the count must be odd. |
57 | | */ |
58 | 2.56k | if (points->npoints % 2 != 1 || points->npoints < 3) |
59 | 2.35k | { |
60 | 2.35k | lwnotice("lwcircstring_construct: invalid point count %d", points->npoints); |
61 | 2.35k | } |
62 | | |
63 | 2.56k | result = (LWCIRCSTRING*) lwalloc(sizeof(LWCIRCSTRING)); |
64 | | |
65 | 2.56k | result->type = CIRCSTRINGTYPE; |
66 | | |
67 | 2.56k | result->flags = points->flags; |
68 | 2.56k | FLAGS_SET_BBOX(result->flags, bbox?1:0); |
69 | | |
70 | 2.56k | result->srid = srid; |
71 | 2.56k | result->points = points; |
72 | 2.56k | result->bbox = bbox; |
73 | | |
74 | 2.56k | return result; |
75 | 2.56k | } |
76 | | |
77 | | LWCIRCSTRING * |
78 | | lwcircstring_construct_empty(int32_t srid, char hasz, char hasm) |
79 | 1.17k | { |
80 | 1.17k | LWCIRCSTRING *result = lwalloc(sizeof(LWCIRCSTRING)); |
81 | 1.17k | result->type = CIRCSTRINGTYPE; |
82 | 1.17k | result->flags = lwflags(hasz,hasm,0); |
83 | 1.17k | result->srid = srid; |
84 | 1.17k | result->points = ptarray_construct_empty(hasz, hasm, 1); |
85 | 1.17k | result->bbox = NULL; |
86 | 1.17k | return result; |
87 | 1.17k | } |
88 | | |
89 | | void |
90 | | lwcircstring_release(LWCIRCSTRING *lwcirc) |
91 | 0 | { |
92 | 0 | lwgeom_release(lwcircstring_as_lwgeom(lwcirc)); |
93 | 0 | } |
94 | | |
95 | | |
96 | | void lwcircstring_free(LWCIRCSTRING *curve) |
97 | 3.73k | { |
98 | 3.73k | if ( ! curve ) return; |
99 | | |
100 | 3.73k | if ( curve->bbox ) |
101 | 0 | lwfree(curve->bbox); |
102 | 3.73k | if ( curve->points ) |
103 | 3.73k | ptarray_free(curve->points); |
104 | 3.73k | lwfree(curve); |
105 | 3.73k | } |
106 | | |
107 | | |
108 | | |
109 | | void printLWCIRCSTRING(LWCIRCSTRING *curve) |
110 | 0 | { |
111 | 0 | lwnotice("LWCIRCSTRING {"); |
112 | 0 | lwnotice(" ndims = %i", (int)FLAGS_NDIMS(curve->flags)); |
113 | 0 | lwnotice(" srid = %i", (int)curve->srid); |
114 | 0 | printPA(curve->points); |
115 | 0 | lwnotice("}"); |
116 | 0 | } |
117 | | |
118 | | /* @brief Clone LWCIRCSTRING object. Serialized point lists are not copied. |
119 | | * |
120 | | * @see ptarray_clone |
121 | | */ |
122 | | LWCIRCSTRING * |
123 | | lwcircstring_clone(const LWCIRCSTRING *g) |
124 | 0 | { |
125 | 0 | return (LWCIRCSTRING *)lwline_clone((LWLINE *)g); |
126 | 0 | } |
127 | | |
128 | | /* check coordinate equality */ |
129 | | char |
130 | | lwcircstring_same(const LWCIRCSTRING *me, const LWCIRCSTRING *you) |
131 | 0 | { |
132 | 0 | return ptarray_same(me->points, you->points); |
133 | 0 | } |
134 | | |
135 | | /* |
136 | | * Construct a LWCIRCSTRING from an array of LWPOINTs |
137 | | * LWCIRCSTRING dimensions are large enough to host all input dimensions. |
138 | | */ |
139 | | LWCIRCSTRING * |
140 | | lwcircstring_from_lwpointarray(int32_t srid, uint32_t npoints, const LWPOINT **points) |
141 | 0 | { |
142 | 0 | uint32_t i; |
143 | 0 | POINTARRAY *pa; |
144 | 0 | int has_z = 0, has_m = 0; |
145 | 0 | POINT4D pt; |
146 | | |
147 | | /* |
148 | | * Find output dimensions, check integrity |
149 | | */ |
150 | 0 | for (i = 0; i < npoints; i++) |
151 | 0 | { |
152 | 0 | const LWGEOM *lwg = (LWGEOM*)points[i]; |
153 | 0 | if (lwg->type != POINTTYPE) |
154 | 0 | { |
155 | 0 | lwerror("%s: invalid input type: %s", __func__, lwtype_name(lwg->type)); |
156 | 0 | return NULL; |
157 | 0 | } |
158 | 0 | has_z |= lwgeom_has_z(lwg); |
159 | 0 | has_m |= lwgeom_has_m(lwg); |
160 | 0 | if (has_z && has_m) break; |
161 | 0 | } |
162 | | |
163 | | /* |
164 | | * Allocate output points array |
165 | | */ |
166 | 0 | pa = ptarray_construct(has_z, has_m, npoints); |
167 | |
|
168 | 0 | for (i = 0; i < npoints; i++) |
169 | 0 | { |
170 | 0 | const LWPOINT *lwpt = points[i]; |
171 | 0 | if (!getPoint4d_p(lwpt->point, 0, &pt)) |
172 | 0 | { |
173 | 0 | lwerror("%s: failed getPoint4d_p", __func__); |
174 | 0 | return NULL; |
175 | 0 | } |
176 | 0 | ptarray_set_point4d(pa, i, &pt); |
177 | 0 | } |
178 | | |
179 | 0 | return lwcircstring_construct(srid, NULL, pa); |
180 | 0 | } |
181 | | |
182 | | /* |
183 | | * Construct a LWCIRCSTRING from a LWMPOINT |
184 | | */ |
185 | | LWCIRCSTRING * |
186 | | lwcircstring_from_lwmpoint(int32_t srid, LWMPOINT *mpoint) |
187 | 0 | { |
188 | 0 | uint32_t i; |
189 | 0 | POINTARRAY *pa; |
190 | 0 | char zmflag = FLAGS_GET_ZM(mpoint->flags); |
191 | 0 | size_t ptsize, size; |
192 | 0 | uint8_t *newpoints, *ptr; |
193 | |
|
194 | 0 | if (zmflag == 0) ptsize = 2 * sizeof(double); |
195 | 0 | else if (zmflag == 3) ptsize = 4 * sizeof(double); |
196 | 0 | else ptsize = 3 * sizeof(double); |
197 | | |
198 | | /* Allocate space for output points */ |
199 | 0 | size = ptsize * mpoint->ngeoms; |
200 | 0 | newpoints = lwalloc(size); |
201 | 0 | memset(newpoints, 0, size); |
202 | |
|
203 | 0 | ptr = newpoints; |
204 | 0 | for (i = 0; i < mpoint->ngeoms; i++) |
205 | 0 | { |
206 | 0 | memcpy(ptr, |
207 | 0 | getPoint_internal(mpoint->geoms[i]->point, 0), |
208 | 0 | ptsize); |
209 | 0 | ptr += ptsize; |
210 | 0 | } |
211 | |
|
212 | 0 | pa = ptarray_construct_reference_data(zmflag&2, zmflag&1, mpoint->ngeoms, newpoints); |
213 | |
|
214 | 0 | LWDEBUGF(3, "lwcurve_from_lwmpoint: constructed pointarray for %d points, %d zmflag", mpoint->ngeoms, zmflag); |
215 | |
|
216 | 0 | return lwcircstring_construct(srid, NULL, pa); |
217 | 0 | } |
218 | | |
219 | | LWCIRCSTRING * |
220 | | lwcircstring_addpoint(LWCIRCSTRING *curve, LWPOINT *point, uint32_t where) |
221 | 0 | { |
222 | 0 | POINTARRAY *newpa; |
223 | 0 | LWCIRCSTRING *ret; |
224 | |
|
225 | 0 | newpa = ptarray_addPoint(curve->points, |
226 | 0 | getPoint_internal(point->point, 0), |
227 | 0 | FLAGS_NDIMS(point->flags), where); |
228 | 0 | ret = lwcircstring_construct(curve->srid, NULL, newpa); |
229 | |
|
230 | 0 | return ret; |
231 | 0 | } |
232 | | |
233 | | LWCIRCSTRING * |
234 | | lwcircstring_removepoint(LWCIRCSTRING *curve, uint32_t index) |
235 | 0 | { |
236 | 0 | POINTARRAY *newpa; |
237 | 0 | LWCIRCSTRING *ret; |
238 | |
|
239 | 0 | newpa = ptarray_removePoint(curve->points, index); |
240 | 0 | ret = lwcircstring_construct(curve->srid, NULL, newpa); |
241 | |
|
242 | 0 | return ret; |
243 | 0 | } |
244 | | |
245 | | /* |
246 | | * Note: input will be changed, make sure you have permissions for this. |
247 | | * */ |
248 | | void |
249 | | lwcircstring_setPoint4d(LWCIRCSTRING *curve, uint32_t index, POINT4D *newpoint) |
250 | 0 | { |
251 | 0 | ptarray_set_point4d(curve->points, index, newpoint); |
252 | 0 | } |
253 | | |
254 | | int |
255 | | lwcircstring_is_closed(const LWCIRCSTRING *curve) |
256 | 0 | { |
257 | 0 | if (lwgeom_has_z((LWGEOM*)curve)) |
258 | 0 | return ptarray_is_closed_3d(curve->points); |
259 | | |
260 | 0 | return ptarray_is_closed_2d(curve->points); |
261 | 0 | } |
262 | | |
263 | | double lwcircstring_length(const LWCIRCSTRING *circ) |
264 | 0 | { |
265 | 0 | return lwcircstring_length_2d(circ); |
266 | 0 | } |
267 | | |
268 | | double lwcircstring_length_2d(const LWCIRCSTRING *circ) |
269 | 0 | { |
270 | 0 | if ( lwcircstring_is_empty(circ) ) |
271 | 0 | return 0.0; |
272 | | |
273 | 0 | return ptarray_arc_length_2d(circ->points); |
274 | 0 | } |
275 | | |
276 | | /* |
277 | | * Returns freshly allocated #LWPOINT that corresponds to the index where. |
278 | | * Returns NULL if the geometry is empty or the index invalid. |
279 | | */ |
280 | 0 | LWPOINT* lwcircstring_get_lwpoint(const LWCIRCSTRING *circ, uint32_t where) { |
281 | 0 | POINT4D pt; |
282 | 0 | LWPOINT *lwpoint; |
283 | 0 | POINTARRAY *pa; |
284 | |
|
285 | 0 | if ( lwcircstring_is_empty(circ) || where >= circ->points->npoints ) |
286 | 0 | return NULL; |
287 | | |
288 | 0 | pa = ptarray_construct_empty(FLAGS_GET_Z(circ->flags), FLAGS_GET_M(circ->flags), 1); |
289 | 0 | pt = getPoint4d(circ->points, where); |
290 | 0 | ptarray_append_point(pa, &pt, LW_TRUE); |
291 | | lwpoint = lwpoint_construct(circ->srid, NULL, pa); |
292 | 0 | return lwpoint; |
293 | 0 | } |
294 | | |
295 | | |