PostGIS  2.3.7dev-r@@SVN_REVISION@@
LWGEOM* lwgeom_node ( const LWGEOM lwgeom_in)

Definition at line 130 of file lwgeom_geos_node.c.

References LWGEOM::flags, FLAGS_GET_M, FLAGS_GET_Z, LWCOLLECTION::geoms, GEOS2LWGEOM(), lwcollection_clone_deep(), lwcollection_construct_empty(), lwcollection_free(), lwcollection_reserve(), lwerror(), LWGEOM2GEOS(), lwgeom_dimension(), lwgeom_extract_unique_endpoints(), lwgeom_free(), lwgeom_geos_errmsg, lwgeom_geos_error(), lwgeom_is_collection(), lwgeom_ngeoms(), lwgeom_subgeom(), lwline_split_by_point_to(), MULTILINETYPE, LWCOLLECTION::ngeoms, s, and LWGEOM::srid.

Referenced by lwt_AddLine(), ST_Node(), and test_lwgeom_node().

131 {
132  GEOSGeometry *g1, *gu, *gm;
133  LWGEOM *ep, *lines;
134  LWCOLLECTION *col, *tc;
135  int pn, ln, np, nl;
136 
137  if ( lwgeom_dimension(lwgeom_in) != 1 ) {
138  lwerror("Noding geometries of dimension != 1 is unsupported");
139  return NULL;
140  }
141 
143  g1 = LWGEOM2GEOS(lwgeom_in, 1);
144  if ( ! g1 ) {
145  lwerror("LWGEOM2GEOS: %s", lwgeom_geos_errmsg);
146  return NULL;
147  }
148 
149  ep = lwgeom_extract_unique_endpoints(lwgeom_in);
150  if ( ! ep ) {
151  GEOSGeom_destroy(g1);
152  lwerror("Error extracting unique endpoints from input");
153  return NULL;
154  }
155 
156  /* Unary union input to fully node */
157  gu = GEOSUnaryUnion(g1);
158  GEOSGeom_destroy(g1);
159  if ( ! gu ) {
160  lwgeom_free(ep);
161  lwerror("GEOSUnaryUnion: %s", lwgeom_geos_errmsg);
162  return NULL;
163  }
164 
165  /* Linemerge (in case of overlaps) */
166  gm = GEOSLineMerge(gu);
167  GEOSGeom_destroy(gu);
168  if ( ! gm ) {
169  lwgeom_free(ep);
170  lwerror("GEOSLineMerge: %s", lwgeom_geos_errmsg);
171  return NULL;
172  }
173 
174  lines = GEOS2LWGEOM(gm, FLAGS_GET_Z(lwgeom_in->flags));
175  GEOSGeom_destroy(gm);
176  if ( ! lines ) {
177  lwgeom_free(ep);
178  lwerror("Error during GEOS2LWGEOM");
179  return NULL;
180  }
181 
182  /*
183  * Reintroduce endpoints from input, using split-line-by-point.
184  * Note that by now we can be sure that each point splits at
185  * most _one_ segment as any point shared by multiple segments
186  * would already be a node. Also we can be sure that any of
187  * the segments endpoints won't split any other segment.
188  * We can use the above 2 assertions to early exit the loop.
189  */
190 
192  FLAGS_GET_Z(lwgeom_in->flags),
193  FLAGS_GET_M(lwgeom_in->flags));
194 
195  np = lwgeom_ngeoms(ep);
196  for (pn=0; pn<np; ++pn) { /* for each point */
197 
198  const LWPOINT* p = (LWPOINT*)lwgeom_subgeom(ep, pn);
199 
200  nl = lwgeom_ngeoms(lines);
201  for (ln=0; ln<nl; ++ln) { /* for each line */
202 
203  const LWLINE* l = (LWLINE*)lwgeom_subgeom(lines, ln);
204 
205  int s = lwline_split_by_point_to(l, p, (LWMLINE*)col);
206 
207  if ( ! s ) continue; /* not on this line */
208 
209  if ( s == 1 ) {
210  /* found on this line, but not splitting it */
211  break;
212  }
213 
214  /* splits this line */
215 
216  /* replace this line with the two splits */
217  if ( lwgeom_is_collection(lines) ) {
218  tc = (LWCOLLECTION*)lines;
219  lwcollection_reserve(tc, nl + 1);
220  while (nl > ln+1) {
221  tc->geoms[nl] = tc->geoms[nl-1];
222  --nl;
223  }
224  lwgeom_free(tc->geoms[ln]);
225  tc->geoms[ln] = col->geoms[0];
226  tc->geoms[ln+1] = col->geoms[1];
227  tc->ngeoms++;
228  } else {
229  lwgeom_free(lines);
230  /* transfer ownership rather than cloning */
231  lines = (LWGEOM*)lwcollection_clone_deep(col);
232  assert(col->ngeoms == 2);
233  lwgeom_free(col->geoms[0]);
234  lwgeom_free(col->geoms[1]);
235  }
236 
237  /* reset the vector */
238  assert(col->ngeoms == 2);
239  col->ngeoms = 0;
240 
241  break;
242  }
243 
244  }
245 
246  lwgeom_free(ep);
247  lwcollection_free(col);
248 
249  lines->srid = lwgeom_in->srid;
250  return (LWGEOM*)lines;
251 }
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition: lwgeom.c:1004
static LWGEOM * lwgeom_extract_unique_endpoints(const LWGEOM *lwg)
uint8_t flags
Definition: liblwgeom.h:396
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1063
static int lwgeom_ngeoms(const LWGEOM *n)
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
int32_t srid
Definition: liblwgeom.h:398
void lwgeom_geos_error(const char *fmt,...)
static const LWGEOM * lwgeom_subgeom(const LWGEOM *g, int n)
LWGEOM ** geoms
Definition: liblwgeom.h:508
char * s
Definition: cu_in_wkt.c:23
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:139
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, int autofix)
LWCOLLECTION * lwcollection_clone_deep(const LWCOLLECTION *lwgeom)
Deep clone LWCOLLECTION object.
Definition: lwcollection.c:149
int lwgeom_dimension(const LWGEOM *geom)
For an LWGEOM, returns 0 for points, 1 for lines, 2 for polygons, 3 for volume, and the max dimension...
Definition: lwgeom.c:1205
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:140
LWGEOM * GEOS2LWGEOM(const GEOSGeometry *geom, char want3d)
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:339
#define MULTILINETYPE
Definition: liblwgeom.h:88
LWCOLLECTION * lwcollection_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwcollection.c:94
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:102
void lwcollection_reserve(LWCOLLECTION *col, int ngeoms)
Ensure the collection can hold at least up to ngeoms geometries.
Definition: lwcollection.c:174
int lwline_split_by_point_to(const LWLINE *ln, const LWPOINT *pt, LWMLINE *to)
Split a line by a point and push components to the provided multiline.

Here is the call graph for this function:

Here is the caller graph for this function: