PostGIS  2.2.8dev-r@@SVN_REVISION@@

◆ lwgeom_node()

LWGEOM* lwgeom_node ( const LWGEOM lwgeom_in)

Definition at line 129 of file lwgeom_geos_node.c.

References LWGEOM::flags, FLAGS_GET_M, FLAGS_GET_Z, LWMLINE::geoms, 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, LWMLINE::ngeoms, LWCOLLECTION::ngeoms, UnionIfDWithinContext::p, POSTGIS_GEOS_VERSION, s, and LWGEOM::srid.

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

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