PostGIS  2.4.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 5875 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.

5876 {
5877  int i;
5878  *nfaces = -1; /* error condition, by default */
5879  int num;
5880  LWT_ISO_FACE *faces;
5881  int nfacesinbox;
5882  LWT_ELEMID *ids = NULL;
5883  GBOX qbox;
5884  const GEOSPreparedGeometry *ppoly;
5885  GEOSGeometry *polyg;
5886 
5887  /* Get tolerance, if 0 was given */
5888  if ( ! tol ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
5889  LWDEBUGF(1, "Working tolerance:%.15g", tol);
5890 
5891  /* Add each ring as an edge */
5892  for ( i=0; i<poly->nrings; ++i )
5893  {
5894  LWLINE *line;
5895  POINTARRAY *pa;
5896  LWT_ELEMID *eids;
5897  int nedges;
5898 
5899  pa = ptarray_clone(poly->rings[i]);
5900  line = lwline_construct(topo->srid, NULL, pa);
5901  eids = lwt_AddLine( topo, line, tol, &nedges );
5902  if ( nedges < 0 ) {
5903  /* probably too late as lwt_AddLine invoked lwerror */
5904  lwline_free(line);
5905  lwerror("Error adding ring %d of polygon", i);
5906  return NULL;
5907  }
5908  lwline_free(line);
5909  lwfree(eids);
5910  }
5911 
5912  /*
5913  -- Find faces covered by input polygon
5914  -- NOTE: potential snapping changed polygon edges
5915  */
5916  qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
5917  gbox_expand(&qbox, tol);
5918  faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
5919  LWT_COL_FACE_ALL, 0 );
5920  if ( nfacesinbox == -1 )
5921  {
5922  lwfree(ids);
5923  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
5924  return NULL;
5925  }
5926 
5927  num = 0;
5928  if ( nfacesinbox )
5929  {
5930  polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
5931  if ( ! polyg )
5932  {
5933  _lwt_release_faces(faces, nfacesinbox);
5934  lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
5935  return NULL;
5936  }
5937  ppoly = GEOSPrepare(polyg);
5938  ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
5939  for ( i=0; i<nfacesinbox; ++i )
5940  {
5941  LWT_ISO_FACE *f = &(faces[i]);
5942  LWGEOM *fg;
5943  GEOSGeometry *fgg, *sp;
5944  int covers;
5945 
5946  /* check if a point on this face surface is covered by our polygon */
5947  fg = lwt_GetFaceGeometry( topo, f->face_id );
5948  if ( ! fg )
5949  {
5950  i = f->face_id; /* so we can destroy faces */
5951  GEOSPreparedGeom_destroy(ppoly);
5952  GEOSGeom_destroy(polyg);
5953  lwfree(ids);
5954  _lwt_release_faces(faces, nfacesinbox);
5955  lwerror("Could not get geometry of face %" LWTFMT_ELEMID, i);
5956  return NULL;
5957  }
5958  /* check if a point on this face's surface is covered by our polygon */
5959  fgg = LWGEOM2GEOS(fg, 0);
5960  lwgeom_free(fg);
5961  if ( ! fgg )
5962  {
5963  GEOSPreparedGeom_destroy(ppoly);
5964  GEOSGeom_destroy(polyg);
5965  _lwt_release_faces(faces, nfacesinbox);
5966  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
5967  return NULL;
5968  }
5969  sp = GEOSPointOnSurface(fgg);
5970  GEOSGeom_destroy(fgg);
5971  if ( ! sp )
5972  {
5973  GEOSPreparedGeom_destroy(ppoly);
5974  GEOSGeom_destroy(polyg);
5975  _lwt_release_faces(faces, nfacesinbox);
5976  lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
5977  return NULL;
5978  }
5979  covers = GEOSPreparedCovers( ppoly, sp );
5980  GEOSGeom_destroy(sp);
5981  if (covers == 2)
5982  {
5983  GEOSPreparedGeom_destroy(ppoly);
5984  GEOSGeom_destroy(polyg);
5985  _lwt_release_faces(faces, nfacesinbox);
5986  lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
5987  return NULL;
5988  }
5989  if ( ! covers )
5990  {
5991  continue; /* we're not composed by this face */
5992  }
5993 
5994  /* TODO: avoid duplicates ? */
5995  ids[num++] = f->face_id;
5996  }
5997  GEOSPreparedGeom_destroy(ppoly);
5998  GEOSGeom_destroy(polyg);
5999  _lwt_release_faces(faces, nfacesinbox);
6000  }
6001 
6002  /* possibly 0 if non face's surface point was found
6003  * to be covered by input polygon */
6004  *nfaces = num;
6005 
6006  return ids;
6007 }
POINTARRAY * ptarray_clone(const POINTARRAY *ptarray)
Clone a POINTARRAY object.
Definition: ptarray.c:661
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:108
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1099
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:4999
LWT_ELEMID * lwt_AddLine(LWT_TOPOLOGY *topo, LWLINE *line, double tol, int *nedges)
Adds a linestring to the topology.
Definition: lwgeom_topo.c:5620
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:288
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:689
POINTARRAY ** rings
Definition: liblwgeom.h:457
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
int nrings
Definition: liblwgeom.h:455
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, int 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:2858
LWT_INT64 LWT_ELEMID
Identifier of topology element.
static void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
Definition: lwgeom_topo.c:457
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: