/src/postgis/liblwgeom/lwcollection.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 | | #include <stdio.h> |
27 | | #include <stdlib.h> |
28 | | #include <string.h> |
29 | | #include "liblwgeom_internal.h" |
30 | | #include "lwgeom_log.h" |
31 | | |
32 | | |
33 | | #define CHECK_LWGEOM_ZM 1 |
34 | | |
35 | | void |
36 | | lwcollection_release(LWCOLLECTION *lwcollection) |
37 | 0 | { |
38 | 0 | lwgeom_release(lwcollection_as_lwgeom(lwcollection)); |
39 | 0 | } |
40 | | |
41 | | LWCOLLECTION * |
42 | | lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms) |
43 | 67.9k | { |
44 | 67.9k | LWCOLLECTION *ret; |
45 | 67.9k | int hasz, hasm; |
46 | 67.9k | #ifdef CHECK_LWGEOM_ZM |
47 | 67.9k | char zm; |
48 | 67.9k | uint32_t i; |
49 | 67.9k | #endif |
50 | | |
51 | 67.9k | LWDEBUGF(2, "lwcollection_construct called with %d, %d, %p, %d, %p.", type, srid, bbox, ngeoms, geoms); |
52 | | |
53 | 67.9k | if( ! lwtype_is_collection(type) ) |
54 | 0 | lwerror("Non-collection type specified in collection constructor!"); |
55 | | |
56 | 67.9k | hasz = 0; |
57 | 67.9k | hasm = 0; |
58 | 67.9k | if ( ngeoms > 0 ) |
59 | 67.9k | { |
60 | 67.9k | hasz = FLAGS_GET_Z(geoms[0]->flags); |
61 | 67.9k | hasm = FLAGS_GET_M(geoms[0]->flags); |
62 | 67.9k | #ifdef CHECK_LWGEOM_ZM |
63 | 67.9k | zm = FLAGS_GET_ZM(geoms[0]->flags); |
64 | | |
65 | 67.9k | LWDEBUGF(3, "lwcollection_construct type[0]=%d", geoms[0]->type); |
66 | | |
67 | 226k | for (i=1; i<ngeoms; i++) |
68 | 158k | { |
69 | 158k | LWDEBUGF(3, "lwcollection_construct type=[%d]=%d", i, geoms[i]->type); |
70 | | |
71 | 158k | if ( zm != FLAGS_GET_ZM(geoms[i]->flags) ) |
72 | 0 | lwerror("lwcollection_construct: mixed dimension geometries: %d/%d", zm, FLAGS_GET_ZM(geoms[i]->flags)); |
73 | 158k | } |
74 | 67.9k | #endif |
75 | 67.9k | } |
76 | | |
77 | | |
78 | 67.9k | ret = lwalloc(sizeof(LWCOLLECTION)); |
79 | 67.9k | ret->type = type; |
80 | 67.9k | ret->flags = lwflags(hasz,hasm,0); |
81 | 67.9k | FLAGS_SET_BBOX(ret->flags, bbox?1:0); |
82 | 67.9k | ret->srid = srid; |
83 | 67.9k | ret->ngeoms = ngeoms; |
84 | 67.9k | ret->maxgeoms = ngeoms; |
85 | 67.9k | ret->geoms = geoms; |
86 | 67.9k | ret->bbox = bbox; |
87 | | |
88 | 67.9k | return ret; |
89 | 67.9k | } |
90 | | |
91 | | LWCOLLECTION * |
92 | | lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm) |
93 | 60.3k | { |
94 | 60.3k | LWCOLLECTION *ret; |
95 | | |
96 | 60.3k | if( ! lwtype_is_collection(type) ) |
97 | 0 | { |
98 | 0 | lwerror("Non-collection type specified in collection constructor!"); |
99 | 0 | return NULL; |
100 | 0 | } |
101 | | |
102 | 60.3k | ret = lwalloc(sizeof(LWCOLLECTION)); |
103 | 60.3k | ret->type = type; |
104 | 60.3k | ret->flags = lwflags(hasz,hasm,0); |
105 | 60.3k | ret->srid = srid; |
106 | 60.3k | ret->ngeoms = 0; |
107 | 60.3k | ret->maxgeoms = 1; /* Allocate room for sub-members, just in case. */ |
108 | 60.3k | ret->geoms = lwalloc(ret->maxgeoms * sizeof(LWGEOM*)); |
109 | 60.3k | ret->bbox = NULL; |
110 | | |
111 | 60.3k | return ret; |
112 | 60.3k | } |
113 | | |
114 | | const LWGEOM * |
115 | | lwcollection_getsubgeom(LWCOLLECTION *col, uint32_t gnum) |
116 | 0 | { |
117 | 0 | return (const LWGEOM *)col->geoms[gnum]; |
118 | 0 | } |
119 | | |
120 | | /** |
121 | | * @brief Clone #LWCOLLECTION object. #POINTARRAY are not copied. |
122 | | * Bbox is cloned if present in input. |
123 | | */ |
124 | | LWCOLLECTION * |
125 | | lwcollection_clone(const LWCOLLECTION *g) |
126 | 0 | { |
127 | 0 | uint32_t i; |
128 | 0 | LWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION)); |
129 | 0 | memcpy(ret, g, sizeof(LWCOLLECTION)); |
130 | 0 | if ( g->ngeoms > 0 ) |
131 | 0 | { |
132 | 0 | ret->geoms = lwalloc(sizeof(LWGEOM *)*g->ngeoms); |
133 | 0 | for (i=0; i<g->ngeoms; i++) |
134 | 0 | { |
135 | 0 | ret->geoms[i] = lwgeom_clone(g->geoms[i]); |
136 | 0 | } |
137 | 0 | if ( g->bbox ) ret->bbox = gbox_copy(g->bbox); |
138 | 0 | } |
139 | 0 | else |
140 | 0 | { |
141 | 0 | ret->bbox = NULL; /* empty collection */ |
142 | 0 | ret->geoms = NULL; |
143 | 0 | } |
144 | 0 | return ret; |
145 | 0 | } |
146 | | |
147 | | /** |
148 | | * @brief Deep clone #LWCOLLECTION object. #POINTARRAY are copied. |
149 | | */ |
150 | | LWCOLLECTION * |
151 | | lwcollection_clone_deep(const LWCOLLECTION *g) |
152 | 0 | { |
153 | 0 | uint32_t i; |
154 | 0 | LWCOLLECTION *ret = lwalloc(sizeof(LWCOLLECTION)); |
155 | 0 | memcpy(ret, g, sizeof(LWCOLLECTION)); |
156 | 0 | if ( g->ngeoms > 0 ) |
157 | 0 | { |
158 | 0 | ret->geoms = lwalloc(sizeof(LWGEOM *)*g->ngeoms); |
159 | 0 | for (i=0; i<g->ngeoms; i++) |
160 | 0 | { |
161 | 0 | ret->geoms[i] = lwgeom_clone_deep(g->geoms[i]); |
162 | 0 | } |
163 | 0 | if ( g->bbox ) ret->bbox = gbox_copy(g->bbox); |
164 | 0 | } |
165 | 0 | else |
166 | 0 | { |
167 | 0 | ret->bbox = NULL; /* empty collection */ |
168 | 0 | ret->geoms = NULL; |
169 | 0 | } |
170 | 0 | return ret; |
171 | 0 | } |
172 | | |
173 | | /** |
174 | | * Ensure the collection can hold up at least ngeoms |
175 | | */ |
176 | | void lwcollection_reserve(LWCOLLECTION *col, uint32_t ngeoms) |
177 | 905k | { |
178 | 905k | if ( ngeoms <= col->maxgeoms ) return; |
179 | | |
180 | | /* Allocate more space if we need it */ |
181 | 25.2k | do { col->maxgeoms *= 2; } while ( col->maxgeoms < ngeoms ); |
182 | 25.2k | col->geoms = lwrealloc(col->geoms, sizeof(LWGEOM*) * col->maxgeoms); |
183 | 25.2k | } |
184 | | |
185 | | /** |
186 | | * Appends geom to the collection managed by col. Does not copy or |
187 | | * clone, simply takes a reference on the passed geom. |
188 | | */ |
189 | | LWCOLLECTION* lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom) |
190 | 905k | { |
191 | 905k | if (!col || !geom) return NULL; |
192 | | |
193 | 905k | if (!col->geoms && (col->ngeoms || col->maxgeoms)) |
194 | 0 | { |
195 | 0 | lwerror("Collection is in inconsistent state. Null memory but non-zero collection counts."); |
196 | 0 | return NULL; |
197 | 0 | } |
198 | | |
199 | | /* Check type compatibility */ |
200 | 905k | if ( ! lwcollection_allows_subtype(col->type, geom->type) ) { |
201 | 0 | lwerror("%s cannot contain %s element", lwtype_name(col->type), lwtype_name(geom->type)); |
202 | 0 | return NULL; |
203 | 0 | } |
204 | | |
205 | | /* In case this is a truly empty, make some initial space */ |
206 | 905k | if (!col->geoms) |
207 | 0 | { |
208 | 0 | col->maxgeoms = 2; |
209 | 0 | col->ngeoms = 0; |
210 | 0 | col->geoms = lwalloc(col->maxgeoms * sizeof(LWGEOM*)); |
211 | 0 | } |
212 | | |
213 | | /* Allocate more space if we need it */ |
214 | 905k | lwcollection_reserve(col, col->ngeoms + 1); |
215 | | |
216 | | #ifndef NDEBUG |
217 | | /* See http://trac.osgeo.org/postgis/ticket/2933 */ |
218 | | /* Make sure we don't already have a reference to this geom */ |
219 | | { |
220 | | for (uint32_t i = 0; i < col->ngeoms; i++) |
221 | | { |
222 | | if (col->geoms[i] == geom) |
223 | | { |
224 | | lwerror("%s [%d] found duplicate geometry in collection %p == %p", __FILE__, __LINE__, col->geoms[i], geom); |
225 | | return col; |
226 | | } |
227 | | } |
228 | | } |
229 | | #endif |
230 | | |
231 | 905k | col->geoms[col->ngeoms] = (LWGEOM*)geom; |
232 | 905k | col->ngeoms++; |
233 | 905k | return col; |
234 | 905k | } |
235 | | |
236 | | /** |
237 | | * Appends all geometries from col2 to col1 in place. |
238 | | * Caller is responsible to release col2. |
239 | | */ |
240 | | LWCOLLECTION * |
241 | | lwcollection_concat_in_place(LWCOLLECTION *col1, const LWCOLLECTION *col2) |
242 | 0 | { |
243 | 0 | uint32_t i; |
244 | 0 | if (!col1 || !col2) return NULL; |
245 | 0 | for (i = 0; i < col2->ngeoms; i++) |
246 | 0 | col1 = lwcollection_add_lwgeom(col1, col2->geoms[i]); |
247 | 0 | return col1; |
248 | 0 | } |
249 | | |
250 | | LWCOLLECTION* |
251 | | lwcollection_segmentize2d(const LWCOLLECTION* col, double dist) |
252 | 0 | { |
253 | 0 | uint32_t i, j; |
254 | 0 | LWGEOM** newgeoms; |
255 | |
|
256 | 0 | if (!col->ngeoms) return lwcollection_clone(col); |
257 | | |
258 | 0 | newgeoms = lwalloc(sizeof(LWGEOM*) * col->ngeoms); |
259 | 0 | for (i = 0; i < col->ngeoms; i++) |
260 | 0 | { |
261 | 0 | newgeoms[i] = lwgeom_segmentize2d(col->geoms[i], dist); |
262 | 0 | if (!newgeoms[i]) |
263 | 0 | { |
264 | 0 | for (j = 0; j < i; j++) |
265 | 0 | lwgeom_free(newgeoms[j]); |
266 | 0 | lwfree(newgeoms); |
267 | 0 | return NULL; |
268 | 0 | } |
269 | 0 | } |
270 | | |
271 | 0 | return lwcollection_construct( |
272 | 0 | col->type, col->srid, NULL, col->ngeoms, newgeoms); |
273 | 0 | } |
274 | | |
275 | | /** @brief check for same geometry composition |
276 | | * |
277 | | */ |
278 | | char |
279 | | lwcollection_same(const LWCOLLECTION *c1, const LWCOLLECTION *c2) |
280 | 0 | { |
281 | 0 | uint32_t i; |
282 | |
|
283 | 0 | LWDEBUG(2, "lwcollection_same called"); |
284 | |
|
285 | 0 | if ( c1->type != c2->type ) return LW_FALSE; |
286 | 0 | if ( c1->ngeoms != c2->ngeoms ) return LW_FALSE; |
287 | | |
288 | 0 | for ( i = 0; i < c1->ngeoms; i++ ) |
289 | 0 | { |
290 | 0 | if ( ! lwgeom_same(c1->geoms[i], c2->geoms[i]) ) |
291 | 0 | return LW_FALSE; |
292 | 0 | } |
293 | | |
294 | | /* Former method allowed out-of-order equality between collections |
295 | | |
296 | | hit = lwalloc(sizeof(uint32_t)*c1->ngeoms); |
297 | | memset(hit, 0, sizeof(uint32_t)*c1->ngeoms); |
298 | | |
299 | | for (i=0; i<c1->ngeoms; i++) |
300 | | { |
301 | | char found=0; |
302 | | for (j=0; j<c2->ngeoms; j++) |
303 | | { |
304 | | if ( hit[j] ) continue; |
305 | | if ( lwgeom_same(c1->geoms[i], c2->geoms[j]) ) |
306 | | { |
307 | | hit[j] = 1; |
308 | | found=1; |
309 | | break; |
310 | | } |
311 | | } |
312 | | if ( ! found ) return LW_FALSE; |
313 | | } |
314 | | */ |
315 | | |
316 | 0 | return LW_TRUE; |
317 | 0 | } |
318 | | |
319 | | int lwcollection_ngeoms(const LWCOLLECTION *col) |
320 | 0 | { |
321 | 0 | uint32_t i; |
322 | 0 | int ngeoms = 0; |
323 | |
|
324 | 0 | if ( ! col ) |
325 | 0 | { |
326 | 0 | lwerror("Null input geometry."); |
327 | 0 | return 0; |
328 | 0 | } |
329 | | |
330 | 0 | for ( i = 0; i < col->ngeoms; i++ ) |
331 | 0 | { |
332 | 0 | if ( col->geoms[i]) |
333 | 0 | { |
334 | 0 | switch (col->geoms[i]->type) |
335 | 0 | { |
336 | 0 | case POINTTYPE: |
337 | 0 | case LINETYPE: |
338 | 0 | case CIRCSTRINGTYPE: |
339 | 0 | case POLYGONTYPE: |
340 | 0 | ngeoms += 1; |
341 | 0 | break; |
342 | 0 | case MULTIPOINTTYPE: |
343 | 0 | case MULTILINETYPE: |
344 | 0 | case MULTICURVETYPE: |
345 | 0 | case MULTIPOLYGONTYPE: |
346 | 0 | ngeoms += col->ngeoms; |
347 | 0 | break; |
348 | 0 | case COLLECTIONTYPE: |
349 | 0 | ngeoms += lwcollection_ngeoms((LWCOLLECTION*)col->geoms[i]); |
350 | 0 | break; |
351 | 0 | } |
352 | 0 | } |
353 | 0 | } |
354 | 0 | return ngeoms; |
355 | 0 | } |
356 | | |
357 | | void lwcollection_free(LWCOLLECTION *col) |
358 | 74.6k | { |
359 | 74.6k | uint32_t i; |
360 | 74.6k | if ( ! col ) return; |
361 | | |
362 | 74.6k | if ( col->bbox ) |
363 | 635 | { |
364 | 635 | lwfree(col->bbox); |
365 | 635 | } |
366 | 385k | for ( i = 0; i < col->ngeoms; i++ ) |
367 | 311k | { |
368 | 311k | LWDEBUGF(4,"freeing geom[%d]", i); |
369 | 311k | if ( col->geoms && col->geoms[i] ) |
370 | 311k | lwgeom_free(col->geoms[i]); |
371 | 311k | } |
372 | 74.6k | if ( col->geoms ) |
373 | 74.6k | { |
374 | 74.6k | lwfree(col->geoms); |
375 | 74.6k | } |
376 | 74.6k | lwfree(col); |
377 | 74.6k | } |
378 | | |
379 | | /** |
380 | | * Examines contents of collection and finds the largest coordinate |
381 | | * dimension of all components. Areal > linear > puntal. |
382 | | */ |
383 | | static uint32_t |
384 | | lwcollection_largest_dimension(const LWCOLLECTION *col) |
385 | 0 | { |
386 | 0 | int largest_type = 0; |
387 | 0 | size_t i; |
388 | 0 | for (i = 0; i < col->ngeoms; i++) |
389 | 0 | { |
390 | 0 | LWGEOM *g = col->geoms[i]; |
391 | 0 | int gtype = lwgeom_get_type(g); |
392 | 0 | if (lwgeom_is_collection(g)) |
393 | 0 | { |
394 | 0 | gtype = lwcollection_largest_dimension((LWCOLLECTION*)g); |
395 | 0 | } |
396 | |
|
397 | 0 | if (gtype == POINTTYPE || gtype == LINETYPE || gtype == POLYGONTYPE) |
398 | 0 | { |
399 | 0 | if (gtype > largest_type) |
400 | 0 | largest_type = gtype; |
401 | 0 | } |
402 | 0 | } |
403 | 0 | return largest_type; |
404 | 0 | } |
405 | | |
406 | | |
407 | | static int |
408 | | lwcollection_extract_recursive(const LWCOLLECTION* col, uint32_t type, LWCOLLECTION *col_out) |
409 | 0 | { |
410 | 0 | size_t i; |
411 | 0 | size_t geoms_added = 0; |
412 | |
|
413 | 0 | for (i = 0; i < col->ngeoms; i++) |
414 | 0 | { |
415 | 0 | LWGEOM *g = col->geoms[i]; |
416 | 0 | if (lwgeom_is_collection(g)) |
417 | 0 | { |
418 | 0 | LWCOLLECTION *col_part = lwgeom_as_lwcollection(g); |
419 | 0 | geoms_added += lwcollection_extract_recursive(col_part, type, col_out); |
420 | 0 | } |
421 | |
|
422 | 0 | if (lwgeom_get_type(g) == type && !lwgeom_is_empty(g)) |
423 | 0 | { |
424 | 0 | lwcollection_add_lwgeom(col_out, lwgeom_clone(col->geoms[i])); |
425 | 0 | geoms_added++; |
426 | 0 | } |
427 | 0 | } |
428 | 0 | return geoms_added; |
429 | 0 | } |
430 | | |
431 | | LWCOLLECTION* |
432 | | lwcollection_extract(const LWCOLLECTION* col, uint32_t type) |
433 | 0 | { |
434 | 0 | LWCOLLECTION* outcol; |
435 | |
|
436 | 0 | if (!col) return NULL; |
437 | | |
438 | | /* Self-discover output type when it is not specified */ |
439 | 0 | if (!type) |
440 | 0 | type = lwcollection_largest_dimension(col); |
441 | | |
442 | | /* |
443 | | * If self-discovery failed, there were no primitive points |
444 | | * lines or polygons in the collection, so send back an |
445 | | * empty collection. |
446 | | */ |
447 | 0 | if (!type) |
448 | 0 | { |
449 | 0 | return lwcollection_construct_empty(COLLECTIONTYPE, |
450 | 0 | col->srid, |
451 | 0 | FLAGS_GET_Z(col->flags), |
452 | 0 | FLAGS_GET_M(col->flags)); |
453 | 0 | } |
454 | | |
455 | 0 | if (!(type == POINTTYPE || type == LINETYPE || type == POLYGONTYPE)) |
456 | 0 | { |
457 | 0 | lwerror( |
458 | 0 | "Only POLYGON, LINESTRING and POINT are supported by " |
459 | 0 | "lwcollection_extract. %s requested.", |
460 | 0 | lwtype_name(type)); |
461 | 0 | return NULL; |
462 | 0 | } |
463 | | |
464 | 0 | outcol = lwcollection_construct_empty(lwtype_multitype(type), |
465 | 0 | col->srid, |
466 | 0 | FLAGS_GET_Z(col->flags), |
467 | 0 | FLAGS_GET_M(col->flags)); |
468 | |
|
469 | 0 | lwcollection_extract_recursive(col, type, outcol); |
470 | 0 | lwgeom_add_bbox(lwcollection_as_lwgeom(outcol)); |
471 | 0 | return outcol; |
472 | 0 | } |
473 | | |
474 | | |
475 | | LWCOLLECTION* |
476 | | lwcollection_force_dims(const LWCOLLECTION *col, int hasz, int hasm, double zval, double mval) |
477 | 4.11k | { |
478 | 4.11k | LWCOLLECTION *colout; |
479 | | |
480 | | /* Return 2D empty */ |
481 | 4.11k | if( lwcollection_is_empty(col) ) |
482 | 2.42k | { |
483 | 2.42k | colout = lwcollection_construct_empty(col->type, col->srid, hasz, hasm); |
484 | 2.42k | } |
485 | 1.68k | else |
486 | 1.68k | { |
487 | 1.68k | uint32_t i; |
488 | 1.68k | LWGEOM **geoms = NULL; |
489 | 1.68k | geoms = lwalloc(sizeof(LWGEOM*) * col->ngeoms); |
490 | 161k | for( i = 0; i < col->ngeoms; i++ ) |
491 | 159k | { |
492 | 159k | geoms[i] = lwgeom_force_dims(col->geoms[i], hasz, hasm, zval, mval); |
493 | 159k | } |
494 | 1.68k | colout = lwcollection_construct(col->type, col->srid, NULL, col->ngeoms, geoms); |
495 | 1.68k | } |
496 | 4.11k | return colout; |
497 | 4.11k | } |
498 | | |
499 | | |
500 | | uint32_t lwcollection_count_vertices(const LWCOLLECTION *col) |
501 | 0 | { |
502 | 0 | uint32_t i = 0; |
503 | 0 | uint32_t v = 0; /* vertices */ |
504 | 0 | assert(col); |
505 | 0 | for ( i = 0; i < col->ngeoms; i++ ) |
506 | 0 | { |
507 | 0 | v += lwgeom_count_vertices(col->geoms[i]); |
508 | 0 | } |
509 | 0 | return v; |
510 | 0 | } |
511 | | |
512 | | |
513 | | int lwcollection_allows_subtype(int collectiontype, int subtype) |
514 | 905k | { |
515 | 905k | if ( collectiontype == COLLECTIONTYPE ) |
516 | 334k | return LW_TRUE; |
517 | 571k | if ( collectiontype == MULTIPOINTTYPE && |
518 | 428k | subtype == POINTTYPE ) |
519 | 428k | return LW_TRUE; |
520 | 143k | if ( collectiontype == MULTILINETYPE && |
521 | 69.5k | subtype == LINETYPE ) |
522 | 69.5k | return LW_TRUE; |
523 | 73.5k | if ( collectiontype == MULTIPOLYGONTYPE && |
524 | 73.5k | subtype == POLYGONTYPE ) |
525 | 73.5k | return LW_TRUE; |
526 | 0 | if ( collectiontype == COMPOUNDTYPE && |
527 | 0 | (subtype == LINETYPE || subtype == CIRCSTRINGTYPE || subtype == NURBSCURVETYPE) ) |
528 | 0 | return LW_TRUE; |
529 | 0 | if ( collectiontype == CURVEPOLYTYPE && |
530 | 0 | (subtype == CIRCSTRINGTYPE || subtype == LINETYPE || subtype == COMPOUNDTYPE || |
531 | 0 | subtype == NURBSCURVETYPE) ) |
532 | 0 | return LW_TRUE; |
533 | 0 | if ( collectiontype == MULTICURVETYPE && |
534 | 0 | (subtype == CIRCSTRINGTYPE || subtype == LINETYPE || subtype == COMPOUNDTYPE || |
535 | 0 | subtype == NURBSCURVETYPE) ) |
536 | 0 | return LW_TRUE; |
537 | 0 | if ( collectiontype == MULTISURFACETYPE && |
538 | 0 | (subtype == POLYGONTYPE || subtype == CURVEPOLYTYPE) ) |
539 | 0 | return LW_TRUE; |
540 | 0 | if ( collectiontype == POLYHEDRALSURFACETYPE && |
541 | 0 | subtype == POLYGONTYPE ) |
542 | 0 | return LW_TRUE; |
543 | 0 | if ( collectiontype == TINTYPE && |
544 | 0 | subtype == TRIANGLETYPE ) |
545 | 0 | return LW_TRUE; |
546 | | |
547 | | /* Must be a bad combination! */ |
548 | 0 | return LW_FALSE; |
549 | 0 | } |
550 | | |
551 | | int |
552 | | lwcollection_startpoint(const LWCOLLECTION* col, POINT4D* pt) |
553 | 0 | { |
554 | 0 | if ( col->ngeoms < 1 ) |
555 | 0 | return LW_FAILURE; |
556 | | |
557 | 0 | return lwgeom_startpoint(col->geoms[0], pt); |
558 | 0 | } |