PostGIS  3.3.9dev-r@@SVN_REVISION@@

◆ lwt_AddPolygon()

LWT_ELEMID* lwt_AddPolygon ( LWT_TOPOLOGY topo,
LWPOLY poly,
double  tol,
int *  nfaces 
)

Adds a polygon to the topology.

The boundary of the given polygon will snap to existing nodes or edges within given tolerance. Existing edges or faces may be split by the boundary of the polygon.

Parameters
topothe topology to operate on
polythe polygon to add
tolsnap tolerance, the topology tolerance will be used if 0
nfacesoutput parameter, will be set to number of faces the polygon was split into, or -1 on error (liblwgeom error handler will be invoked with error message)
Returns
an array of <nfaces> face identifiers that sewed togheter will build up the input polygon (after snapping). Caller will need to free the array using lwfree(), if not null.

Definition at line 6134 of file lwgeom_topo.c.

6135 {
6136  uint32_t i;
6137  *nfaces = -1; /* error condition, by default */
6138  int num;
6139  LWT_ISO_FACE *faces;
6140  uint64_t nfacesinbox;
6141  uint64_t j;
6142  LWT_ELEMID *ids = NULL;
6143  GBOX qbox;
6144  const GEOSPreparedGeometry *ppoly;
6145  GEOSGeometry *polyg;
6146 
6147  /* Nothing to add, in an empty polygon */
6148  if ( lwpoly_is_empty(poly) )
6149  {
6150  *nfaces = 0;
6151  return NULL;
6152  }
6153 
6154  /* Get tolerance, if 0 was given */
6155  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
6156  LWDEBUGF(1, "Working tolerance:%.15g", tol);
6157 
6158  /* Add each ring as an edge */
6159  for ( i=0; i<poly->nrings; ++i )
6160  {
6161  LWLINE *line;
6162  POINTARRAY *pa;
6163  LWT_ELEMID *eids;
6164  int nedges;
6165 
6166  pa = ptarray_clone(poly->rings[i]);
6167  line = lwline_construct(topo->srid, NULL, pa);
6168  eids = lwt_AddLine( topo, line, tol, &nedges );
6169  if ( nedges < 0 ) {
6170  /* probably too late as lwt_AddLine invoked lwerror */
6171  lwline_free(line);
6172  lwerror("Error adding ring %d of polygon", i);
6173  return NULL;
6174  }
6175  lwline_free(line);
6176  lwfree(eids);
6177  }
6178 
6179  /*
6180  -- Find faces covered by input polygon
6181  -- NOTE: potential snapping changed polygon edges
6182  */
6183  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
6184  gbox_expand(&qbox, tol);
6185  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
6186  LWT_COL_FACE_ALL, 0 );
6187  if (nfacesinbox == UINT64_MAX)
6188  {
6189  lwfree(ids);
6190  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
6191  return NULL;
6192  }
6193 
6194  num = 0;
6195  if ( nfacesinbox )
6196  {
6197  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
6198  if ( ! polyg )
6199  {
6200  _lwt_release_faces(faces, nfacesinbox);
6201  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
6202  return NULL;
6203  }
6204  ppoly = GEOSPrepare(polyg);
6205  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
6206  for ( j=0; j<nfacesinbox; ++j )
6207  {
6208  LWT_ISO_FACE *f = &(faces[j]);
6209  LWGEOM *fg;
6210  GEOSGeometry *fgg, *sp;
6211  int covers;
6212 
6213  /* check if a point on this face surface is covered by our polygon */
6214  fg = lwt_GetFaceGeometry( topo, f->face_id );
6215  if ( ! fg )
6216  {
6217  j = f->face_id; /* so we can destroy faces */
6218  GEOSPreparedGeom_destroy(ppoly);
6219  GEOSGeom_destroy(polyg);
6220  lwfree(ids);
6221  _lwt_release_faces(faces, nfacesinbox);
6222  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
6223  return NULL;
6224  }
6225  /* check if a point on this face's surface is covered by our polygon */
6226  fgg = LWGEOM2GEOS(fg, 0);
6227  lwgeom_free(fg);
6228  if ( ! fgg )
6229  {
6230  GEOSPreparedGeom_destroy(ppoly);
6231  GEOSGeom_destroy(polyg);
6232  _lwt_release_faces(faces, nfacesinbox);
6233  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
6234  return NULL;
6235  }
6236  sp = GEOSPointOnSurface(fgg);
6237  GEOSGeom_destroy(fgg);
6238  if ( ! sp )
6239  {
6240  GEOSPreparedGeom_destroy(ppoly);
6241  GEOSGeom_destroy(polyg);
6242  _lwt_release_faces(faces, nfacesinbox);
6243  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
6244  return NULL;
6245  }
6246  covers = GEOSPreparedCovers( ppoly, sp );
6247  GEOSGeom_destroy(sp);
6248  if (covers == 2)
6249  {
6250  GEOSPreparedGeom_destroy(ppoly);
6251  GEOSGeom_destroy(polyg);
6252  _lwt_release_faces(faces, nfacesinbox);
6253  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
6254  return NULL;
6255  }
6256  if ( ! covers )
6257  {
6258  continue; /* we're not composed by this face */
6259  }
6260 
6261  /* TODO: avoid duplicates ? */
6262  ids[num++] = f->face_id;
6263  }
6264  GEOSPreparedGeom_destroy(ppoly);
6265  GEOSGeom_destroy(polyg);
6266  _lwt_release_faces(faces, nfacesinbox);
6267  }
6268 
6269  /* possibly 0 if non face's surface point was found
6270  * to be covered by input polygon */
6271  *nfaces = num;
6272 
6273  return ids;
6274 }
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition: gbox.c:97
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:329
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
void lwfree(void *mem)
Definition: lwutil.c:242
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition: lwgeom.c:743
void * lwalloc(size_t size)
Definition: lwutil.c:227
void lwline_free(LWLINE *line)
Definition: lwline.c:67
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition: ptarray.c:665
int lwpoly_is_empty(const LWPOLY *poly)
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_FACE_ALL
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
static LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
Definition: lwgeom_topo.c:184
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:119
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
Definition: lwgeom_topo.c:2847
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:6122
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:455
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:5064
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:43
Datum covers(PG_FUNCTION_ARGS)
POINTARRAY ** rings
Definition: liblwgeom.h:534
uint32_t nrings
Definition: liblwgeom.h:539
LWT_ELEMID face_id
const LWT_BE_IFACE * be_iface

References _LWT_MINTOLERANCE, _lwt_release_faces(), LWT_TOPOLOGY_T::be_iface, covers(), LWT_ISO_FACE::face_id, gbox_expand(), lwalloc(), LWDEBUGF, lwerror(), lwfree(), LWGEOM2GEOS(), lwgeom_free(), lwgeom_geos_errmsg, lwgeom_get_bbox(), lwline_construct(), lwline_free(), lwpoly_as_lwgeom(), lwpoly_is_empty(), lwt_AddLine(), lwt_be_getFaceWithinBox2D(), lwt_be_lastErrorMessage(), LWT_COL_FACE_ALL, lwt_GetFaceGeometry(), LWTFMT_ELEMID, LWPOLY::nrings, ptarray_clone(), LWPOLY::rings, and LWT_TOPOLOGY_T::srid.

Here is the call graph for this function: