PostGIS  3.7.0dev-r@@SVN_REVISION@@
lwcompound.c
Go to the documentation of this file.
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 uint32_t
35 {
36  if ( compound->type != COMPOUNDTYPE )
37  lwerror("%s only supports compound curves", __func__);
38  return compound->ngeoms;
39 }
40 
41 const LWGEOM *
42 lwcollection_getsubcurve(const LWCOMPOUND *compound, uint32_t curvenum)
43 {
44  return (const LWGEOM *)compound->geoms[curvenum];
45 }
46 
47 int
49 {
50  int hasz = lwgeom_has_z(lwcompound_as_lwgeom(compound));
52  return LW_FALSE;
53 
54  for (uint32_t i = 0; i < compound->ngeoms; i++)
55  {
56  uint32_t i_end = i == 0 ? compound->ngeoms - 1 : i - 1;
57  const LWLINE *geom_start = (LWLINE *)(compound->geoms[i]);
58  const LWLINE *geom_end = (LWLINE *)(compound->geoms[i_end]);
59  const POINTARRAY *pa_start = geom_start->points;
60  const POINTARRAY *pa_end = geom_end->points;
61  if (hasz)
62  {
63  const POINT3D *pt_start = getPoint3d_cp(pa_start, 0);
64  const POINT3D *pt_end = getPoint3d_cp(pa_end, pa_end->npoints-1);
65  if (!p3d_same(pt_start, pt_end))
66  return LW_FALSE;
67  }
68  else
69  {
70  const POINT2D *pt_start = getPoint2d_cp(pa_start, 0);
71  const POINT2D *pt_end = getPoint2d_cp(pa_end, pa_end->npoints-1);
72  if (!p2d_same(pt_start, pt_end))
73  return LW_FALSE;
74  }
75  }
76 
77  return LW_TRUE;
78 }
79 
80 int
82 {
83  int hasz = lwgeom_has_z(lwcompound_as_lwgeom(compound));
85  return LW_TRUE;
86 
87  for (uint32_t i = 1; i < compound->ngeoms; i++)
88  {
89  const LWLINE *geom_start = (LWLINE *)(compound->geoms[i]);
90  const LWLINE *geom_end = (LWLINE *)(compound->geoms[i-1]);
91  const POINTARRAY *pa_start = geom_start->points;
92  const POINTARRAY *pa_end = geom_end->points;
93  if (hasz)
94  {
95  const POINT3D *pt_start = getPoint3d_cp(pa_start, 0);
96  const POINT3D *pt_end = getPoint3d_cp(pa_end, pa_end->npoints-1);
97  if (!p3d_same(pt_start, pt_end))
98  return LW_FALSE;
99  }
100  else
101  {
102  const POINT2D *pt_start = getPoint2d_cp(pa_start, 0);
103  const POINT2D *pt_end = getPoint2d_cp(pa_end, pa_end->npoints-1);
104  if (!p2d_same(pt_start, pt_end))
105  return LW_FALSE;
106  }
107  }
108 
109  return LW_TRUE;
110 }
111 
112 double lwcompound_length(const LWCOMPOUND *comp)
113 {
114  return lwcompound_length_2d(comp);
115 }
116 
117 double lwcompound_length_2d(const LWCOMPOUND *comp)
118 {
119  uint32_t i;
120  double length = 0.0;
121  if ( lwgeom_is_empty((LWGEOM*)comp) )
122  return 0.0;
123 
124  for (i = 0; i < comp->ngeoms; i++)
125  {
126  length += lwgeom_length_2d(comp->geoms[i]);
127  }
128  return length;
129 }
130 
132 {
133  LWCOLLECTION *col = (LWCOLLECTION*)comp;
134 
135  /* Empty things can't continuously join up with other things */
136  if ( lwgeom_is_empty(geom) )
137  {
138  LWDEBUG(4, "Got an empty component for a compound curve!");
139  return LW_FAILURE;
140  }
141 
142  if( col->ngeoms > 0 )
143  {
144  POINT4D last, first;
145  /* First point of the component we are adding */
146  LWLINE *newline = (LWLINE*)geom;
147  /* Last point of the previous component */
148  LWLINE *prevline = (LWLINE*)(col->geoms[col->ngeoms-1]);
149 
150  getPoint4d_p(newline->points, 0, &first);
151  getPoint4d_p(prevline->points, prevline->points->npoints-1, &last);
152 
153  if ( !(FP_EQUALS(first.x,last.x) && FP_EQUALS(first.y,last.y)) )
154  {
155  LWDEBUG(4, "Components don't join up end-to-end!");
156  LWDEBUGF(4, "first pt (%g %g %g %g) last pt (%g %g %g %g)", first.x, first.y, first.z, first.m, last.x, last.y, last.z, last.m);
157  return LW_FAILURE;
158  }
159  }
160 
161  col = lwcollection_add_lwgeom(col, geom);
162  return LW_SUCCESS;
163 }
164 
165 LWCOMPOUND *
166 lwcompound_construct_empty(int32_t srid, char hasz, char hasm)
167 {
169  return ret;
170 }
171 
172 int lwgeom_contains_point(const LWGEOM *geom, const POINT2D *pt)
173 {
174  switch( geom->type )
175  {
176  case LINETYPE:
177  return ptarray_contains_point(((LWLINE*)geom)->points, pt);
178  case CIRCSTRINGTYPE:
179  return ptarrayarc_contains_point(((LWCIRCSTRING*)geom)->points, pt);
180  case COMPOUNDTYPE:
181  return lwcompound_contains_point((LWCOMPOUND*)geom, pt);
182  }
183  lwerror("lwgeom_contains_point failed");
184  return LW_FAILURE;
185 }
186 
187 int
189 {
190  uint32_t i;
191  LWLINE *lwline;
192  LWCIRCSTRING *lwcirc;
193  int wn = 0;
194  int winding_number = 0;
195  int result;
196 
197  for ( i = 0; i < comp->ngeoms; i++ )
198  {
199  LWGEOM *lwgeom = comp->geoms[i];
200  if ( lwgeom->type == LINETYPE )
201  {
202  lwline = lwgeom_as_lwline(lwgeom);
203  if ( comp->ngeoms == 1 )
204  {
205  return ptarray_contains_point(lwline->points, pt);
206  }
207  else
208  {
209  /* Don't check closure while doing p-i-p test */
210  result = ptarray_contains_point_partial(lwline->points, pt, LW_FALSE, &winding_number);
211  }
212  }
213  else
214  {
215  lwcirc = lwgeom_as_lwcircstring(lwgeom);
216  if ( ! lwcirc ) {
217  lwerror("Unexpected component of type %s in compound curve", lwtype_name(lwgeom->type));
218  return 0;
219  }
220  if ( comp->ngeoms == 1 )
221  {
222  return ptarrayarc_contains_point(lwcirc->points, pt);
223  }
224  else
225  {
226  /* Don't check closure while doing p-i-p test */
227  result = ptarrayarc_contains_point_partial(lwcirc->points, pt, LW_FALSE, &winding_number);
228  }
229  }
230 
231  /* Propagate boundary condition */
232  if ( result == LW_BOUNDARY )
233  return LW_BOUNDARY;
234 
235  wn += winding_number;
236  }
237 
238  /* Outside */
239  if (wn == 0)
240  return LW_OUTSIDE;
241 
242  /* Inside */
243  return LW_INSIDE;
244 }
245 
246 LWCOMPOUND *
248 {
249  LWCOMPOUND* ogeom = lwcompound_construct_empty(lwline->srid, FLAGS_GET_Z(lwline->flags), FLAGS_GET_M(lwline->flags));
250  lwcompound_add_lwgeom(ogeom, lwgeom_clone((LWGEOM*)lwline));
251  /* ogeom->bbox = lwline->bbox; */
252  return ogeom;
253 }
254 
255 LWPOINT*
256 lwcompound_get_lwpoint(const LWCOMPOUND *lwcmp, uint32_t where)
257 {
258  uint32_t i;
259  uint32_t count = 0;
260  uint32_t npoints = 0;
261  if ( lwgeom_is_empty((LWGEOM*)lwcmp) )
262  return NULL;
263 
264  npoints = lwgeom_count_vertices((LWGEOM*)lwcmp);
265  if ( where >= npoints )
266  {
267  lwerror("%s: index %d is not in range of number of vertices (%d) in input", __func__, where, npoints);
268  return NULL;
269  }
270 
271  for ( i = 0; i < lwcmp->ngeoms; i++ )
272  {
273  LWGEOM* part = lwcmp->geoms[i];
274  uint32_t npoints_part = lwgeom_count_vertices(part);
275  if ( where >= count && where < count + npoints_part )
276  {
277  return lwline_get_lwpoint((LWLINE*)part, where - count);
278  }
279  else
280  {
281  count += npoints_part;
282  }
283  }
284 
285  return NULL;
286 }
287 
288 
289 
290 LWPOINT *
292 {
293  return lwcompound_get_lwpoint(lwcmp, 0);
294 }
295 
296 LWPOINT *
298 {
299  LWLINE *lwline;
300  if ( lwcmp->ngeoms < 1 )
301  {
302  return NULL;
303  }
304 
305  lwline = (LWLINE*)(lwcmp->geoms[lwcmp->ngeoms-1]);
306 
307  if ( (!lwline) || (!lwline->points) || (lwline->points->npoints < 1) )
308  {
309  return NULL;
310  }
311 
312  return lwline_get_lwpoint(lwline, lwline->points->npoints-1);
313 }
314 
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:179
LWGEOM * lwcompound_as_lwgeom(const LWCOMPOUND *obj)
Definition: lwgeom.c:324
#define LW_FALSE
Definition: liblwgeom.h:94
#define COMPOUNDTYPE
Definition: liblwgeom.h:110
#define LW_FAILURE
Definition: liblwgeom.h:96
#define LINETYPE
Definition: liblwgeom.h:103
#define LW_SUCCESS
Definition: liblwgeom.h:97
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
#define FLAGS_GET_Z(flags)
Definition: liblwgeom.h:165
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
Definition: lwgeom.c:1309
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:109
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition: lwcollection.c:92
double lwgeom_length_2d(const LWGEOM *geom)
Definition: lwgeom.c:2060
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:166
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition: lwgeom_api.c:125
LWGEOM * lwgeom_clone(const LWGEOM *lwgeom)
Clone LWGEOM object.
Definition: lwgeom.c:491
LWCOLLECTION * lwcollection_add_lwgeom(LWCOLLECTION *col, const LWGEOM *geom)
Appends geom to the collection managed by col.
Definition: lwcollection.c:189
LWCIRCSTRING * lwgeom_as_lwcircstring(const LWGEOM *lwgeom)
Definition: lwgeom.c:188
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
Definition: lwline.c:309
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:763
#define LW_INSIDE
Constants for point-in-polygon return values.
#define LW_BOUNDARY
int ptarrayarc_contains_point(const POINTARRAY *pa, const POINT2D *pt)
For POINTARRAYs representing CIRCULARSTRINGS.
Definition: ptarray.c:856
int p3d_same(const POINT3D *p1, const POINT3D *p2)
Definition: lwalgorithm.c:41
#define FP_EQUALS(A, B)
int ptarray_contains_point(const POINTARRAY *pa, const POINT2D *pt)
Return LW_INSIDE if the point is inside the POINTARRAY, LW_OUTSIDE if it is outside,...
Definition: ptarray.c:751
int ptarrayarc_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:862
#define LW_OUTSIDE
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:57
uint32_t lwcompound_num_curves(const LWCOMPOUND *compound)
Definition: lwcompound.c:34
double lwcompound_length_2d(const LWCOMPOUND *comp)
Definition: lwcompound.c:117
int lwcompound_contains_point(const LWCOMPOUND *comp, const POINT2D *pt)
Definition: lwcompound.c:188
LWPOINT * lwcompound_get_lwpoint(const LWCOMPOUND *lwcmp, uint32_t where)
Definition: lwcompound.c:256
const LWGEOM * lwcollection_getsubcurve(const LWCOMPOUND *compound, uint32_t curvenum)
Definition: lwcompound.c:42
int lwcompound_is_closed(const LWCOMPOUND *compound)
Definition: lwcompound.c:48
LWCOMPOUND * lwcompound_construct_from_lwline(const LWLINE *lwline)
Construct an equivalent compound curve from a linestring.
Definition: lwcompound.c:247
LWPOINT * lwcompound_get_startpoint(const LWCOMPOUND *lwcmp)
Definition: lwcompound.c:291
double lwcompound_length(const LWCOMPOUND *comp)
Definition: lwcompound.c:112
int lwcompound_is_valid(const LWCOMPOUND *compound)
Definition: lwcompound.c:81
int lwgeom_contains_point(const LWGEOM *geom, const POINT2D *pt)
Definition: lwcompound.c:172
LWCOMPOUND * lwcompound_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwcompound.c:166
int lwcompound_add_lwgeom(LWCOMPOUND *comp, LWGEOM *geom)
Add a component, allocating extra space if necessary.
Definition: lwcompound.c:131
LWPOINT * lwcompound_get_endpoint(const LWCOMPOUND *lwcmp)
Definition: lwcompound.c:297
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:97
static const POINT3D * getPoint3d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT3D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:109
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:199
int count
Definition: genraster.py:57
POINTARRAY * points
Definition: liblwgeom.h:507
uint32_t ngeoms
Definition: liblwgeom.h:580
LWGEOM ** geoms
Definition: liblwgeom.h:575
uint32_t ngeoms
Definition: liblwgeom.h:594
uint8_t type
Definition: liblwgeom.h:592
LWGEOM ** geoms
Definition: liblwgeom.h:589
uint8_t type
Definition: liblwgeom.h:462
lwflags_t flags
Definition: liblwgeom.h:485
POINTARRAY * points
Definition: liblwgeom.h:483
int32_t srid
Definition: liblwgeom.h:484
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
uint32_t npoints
Definition: liblwgeom.h:427