PostGIS  2.5.0dev-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 6009 of file lwgeom_topo.c.

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(), lwt_AddLine(), lwt_be_getFaceWithinBox2D(), lwt_be_lastErrorMessage(), LWT_COL_FACE_ALL, lwt_GetFaceGeometry(), LWTFMT_ELEMID, ptarray_clone(), and LWT_TOPOLOGY_T::srid.

6010 {
6011  uint32_t i;
6012  *nfaces = -1; /* error condition, by default */
6013  int num;
6014  LWT_ISO_FACE *faces;
6015  int nfacesinbox;
6016  int j;
6017  LWT_ELEMID *ids = NULL;
6018  GBOX qbox;
6019  const GEOSPreparedGeometry *ppoly;
6020  GEOSGeometry *polyg;
6021 
6022  /* Get tolerance, if 0 was given */
6023  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
6024  LWDEBUGF(1, "Working tolerance:%.15g", tol);
6025 
6026  /* Add each ring as an edge */
6027  for ( i=0; i<poly->nrings; ++i )
6028  {
6029  LWLINE *line;
6030  POINTARRAY *pa;
6031  LWT_ELEMID *eids;
6032  int nedges;
6033 
6034  pa = ptarray_clone(poly->rings[i]);
6035  line = lwline_construct(topo->srid, NULL, pa);
6036  eids = lwt_AddLine( topo, line, tol, &nedges );
6037  if ( nedges < 0 ) {
6038  /* probably too late as lwt_AddLine invoked lwerror */
6039  lwline_free(line);
6040  lwerror("Error adding ring %d of polygon", i);
6041  return NULL;
6042  }
6043  lwline_free(line);
6044  lwfree(eids);
6045  }
6046 
6047  /*
6048  -- Find faces covered by input polygon
6049  -- NOTE: potential snapping changed polygon edges
6050  */
6051  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
6052  gbox_expand(&qbox, tol);
6053  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
6054  LWT_COL_FACE_ALL, 0 );
6055  if ( nfacesinbox == -1 )
6056  {
6057  lwfree(ids);
6058  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
6059  return NULL;
6060  }
6061 
6062  num = 0;
6063  if ( nfacesinbox )
6064  {
6065  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
6066  if ( ! polyg )
6067  {
6068  _lwt_release_faces(faces, nfacesinbox);
6069  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
6070  return NULL;
6071  }
6072  ppoly = GEOSPrepare(polyg);
6073  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
6074  for ( j=0; j<nfacesinbox; ++j )
6075  {
6076  LWT_ISO_FACE *f = &(faces[j]);
6077  LWGEOM *fg;
6078  GEOSGeometry *fgg, *sp;
6079  int covers;
6080 
6081  /* check if a point on this face surface is covered by our polygon */
6082  fg = lwt_GetFaceGeometry( topo, f->face_id );
6083  if ( ! fg )
6084  {
6085  j = f->face_id; /* so we can destroy faces */
6086  GEOSPreparedGeom_destroy(ppoly);
6087  GEOSGeom_destroy(polyg);
6088  lwfree(ids);
6089  _lwt_release_faces(faces, nfacesinbox);
6090  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
6091  return NULL;
6092  }
6093  /* check if a point on this face's surface is covered by our polygon */
6094  fgg = LWGEOM2GEOS(fg, 0);
6095  lwgeom_free(fg);
6096  if ( ! fgg )
6097  {
6098  GEOSPreparedGeom_destroy(ppoly);
6099  GEOSGeom_destroy(polyg);
6100  _lwt_release_faces(faces, nfacesinbox);
6101  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
6102  return NULL;
6103  }
6104  sp = GEOSPointOnSurface(fgg);
6105  GEOSGeom_destroy(fgg);
6106  if ( ! sp )
6107  {
6108  GEOSPreparedGeom_destroy(ppoly);
6109  GEOSGeom_destroy(polyg);
6110  _lwt_release_faces(faces, nfacesinbox);
6111  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
6112  return NULL;
6113  }
6114  covers = GEOSPreparedCovers( ppoly, sp );
6115  GEOSGeom_destroy(sp);
6116  if (covers == 2)
6117  {
6118  GEOSPreparedGeom_destroy(ppoly);
6119  GEOSGeom_destroy(polyg);
6120  _lwt_release_faces(faces, nfacesinbox);
6121  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
6122  return NULL;
6123  }
6124  if ( ! covers )
6125  {
6126  continue; /* we're not composed by this face */
6127  }
6128 
6129  /* TODO: avoid duplicates ? */
6130  ids[num++] = f->face_id;
6131  }
6132  GEOSPreparedGeom_destroy(ppoly);
6133  GEOSGeom_destroy(polyg);
6134  _lwt_release_faces(faces, nfacesinbox);
6135  }
6136 
6137  /* possibly 0 if non face's surface point was found
6138  * to be covered by input polygon */
6139  *nfaces = num;
6140 
6141  return ids;
6142 }
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition: ptarray.c:652
Datum covers(PG_FUNCTION_ARGS)
void lwfree(void *mem)
Definition: lwutil.c:244
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition: g_box.c:104
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1144
void lwline_free(LWLINE *line)
Definition: lwline.c:76
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
#define _LWT_MINTOLERANCE(topo, geom)
Definition: lwgeom_topo.c:5063
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:5997
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:320
uint32_t nrings
Definition: liblwgeom.h:457
unsigned int uint32_t
Definition: uthash.h:78
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
const LWT_BE_IFACE * be_iface
LWT_ELEMID face_id
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:734
POINTARRAY ** rings
Definition: liblwgeom.h:459
static LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
Definition: lwgeom_topo.c:187
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
#define LWT_COL_FACE_ALL
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
Definition: lwgeom_topo.c:2882
LWT_INT64 LWT_ELEMID
Identifier of topology element.
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:447
void * lwalloc(size_t size)
Definition: lwutil.c:229
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:120
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:44
Here is the call graph for this function: