PostGIS  2.5.1dev-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 5779 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.

5780 {
5781  uint32_t i;
5782  *nfaces = -1; /* error condition, by default */
5783  int num;
5784  LWT_ISO_FACE *faces;
5785  int nfacesinbox;
5786  int j;
5787  LWT_ELEMID *ids = NULL;
5788  GBOX qbox;
5789  const GEOSPreparedGeometry *ppoly;
5790  GEOSGeometry *polyg;
5791 
5792  /* Get tolerance, if 0 was given */
5793  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
5794  LWDEBUGF(1, "Working tolerance:%.15g", tol);
5795 
5796  /* Add each ring as an edge */
5797  for ( i=0; i<poly->nrings; ++i )
5798  {
5799  LWLINE *line;
5800  POINTARRAY *pa;
5801  LWT_ELEMID *eids;
5802  int nedges;
5803 
5804  pa = ptarray_clone(poly->rings[i]);
5805  line = lwline_construct(topo->srid, NULL, pa);
5806  eids = lwt_AddLine( topo, line, tol, &nedges );
5807  if ( nedges < 0 ) {
5808  /* probably too late as lwt_AddLine invoked lwerror */
5809  lwline_free(line);
5810  lwerror("Error adding ring %d of polygon", i);
5811  return NULL;
5812  }
5813  lwline_free(line);
5814  lwfree(eids);
5815  }
5816 
5817  /*
5818  -- Find faces covered by input polygon
5819  -- NOTE: potential snapping changed polygon edges
5820  */
5821  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
5822  gbox_expand(&qbox, tol);
5823  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
5824  LWT_COL_FACE_ALL, 0 );
5825  if ( nfacesinbox == -1 )
5826  {
5827  lwfree(ids);
5828  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
5829  return NULL;
5830  }
5831 
5832  num = 0;
5833  if ( nfacesinbox )
5834  {
5835  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
5836  if ( ! polyg )
5837  {
5838  _lwt_release_faces(faces, nfacesinbox);
5839  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
5840  return NULL;
5841  }
5842  ppoly = GEOSPrepare(polyg);
5843  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
5844  for ( j=0; j<nfacesinbox; ++j )
5845  {
5846  LWT_ISO_FACE *f = &(faces[j]);
5847  LWGEOM *fg;
5848  GEOSGeometry *fgg, *sp;
5849  int covers;
5850 
5851  /* check if a point on this face surface is covered by our polygon */
5852  fg = lwt_GetFaceGeometry( topo, f->face_id );
5853  if ( ! fg )
5854  {
5855  j = f->face_id; /* so we can destroy faces */
5856  GEOSPreparedGeom_destroy(ppoly);
5857  GEOSGeom_destroy(polyg);
5858  lwfree(ids);
5859  _lwt_release_faces(faces, nfacesinbox);
5860  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
5861  return NULL;
5862  }
5863  /* check if a point on this face's surface is covered by our polygon */
5864  fgg = LWGEOM2GEOS(fg, 0);
5865  lwgeom_free(fg);
5866  if ( ! fgg )
5867  {
5868  GEOSPreparedGeom_destroy(ppoly);
5869  GEOSGeom_destroy(polyg);
5870  _lwt_release_faces(faces, nfacesinbox);
5871  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
5872  return NULL;
5873  }
5874  sp = GEOSPointOnSurface(fgg);
5875  GEOSGeom_destroy(fgg);
5876  if ( ! sp )
5877  {
5878  GEOSPreparedGeom_destroy(ppoly);
5879  GEOSGeom_destroy(polyg);
5880  _lwt_release_faces(faces, nfacesinbox);
5881  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
5882  return NULL;
5883  }
5884  covers = GEOSPreparedCovers( ppoly, sp );
5885  GEOSGeom_destroy(sp);
5886  if (covers == 2)
5887  {
5888  GEOSPreparedGeom_destroy(ppoly);
5889  GEOSGeom_destroy(polyg);
5890  _lwt_release_faces(faces, nfacesinbox);
5891  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
5892  return NULL;
5893  }
5894  if ( ! covers )
5895  {
5896  continue; /* we're not composed by this face */
5897  }
5898 
5899  /* TODO: avoid duplicates ? */
5900  ids[num++] = f->face_id;
5901  }
5902  GEOSPreparedGeom_destroy(ppoly);
5903  GEOSGeom_destroy(polyg);
5904  _lwt_release_faces(faces, nfacesinbox);
5905  }
5906 
5907  /* possibly 0 if non face's surface point was found
5908  * to be covered by input polygon */
5909  *nfaces = num;
5910 
5911  return ids;
5912 }
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition: ptarray.c:659
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:4857
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:5767
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:2778
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: