PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ 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 together will build up the input polygon (after snapping). Caller will need to free the array using lwfree(), if not null.

Definition at line 7705 of file lwgeom_topo.c.

7706{
7707 *nfaces = -1; /* error condition, by default */
7708 int num;
7709 LWT_ISO_FACE *faces;
7710 uint64_t nfacesinbox;
7711 uint64_t j;
7712 LWT_ELEMID *ids = NULL;
7713 GBOX qbox;
7714 const GEOSPreparedGeometry *ppoly;
7715 GEOSGeometry *polyg;
7716
7717 /* Nothing to add, in an empty polygon */
7718 if ( lwpoly_is_empty(poly) )
7719 {
7720 *nfaces = 0;
7721 return NULL;
7722 }
7723
7724 /* Get tolerance, if 0 was given */
7725 if ( tol == -1 ) tol = _LWT_MINTOLERANCE( topo, (LWGEOM*)poly );
7726 LWDEBUGF(1, "Working tolerance:%.15g", tol);
7727
7728 lwt_LoadPolygon(topo, poly, tol);
7729
7730 /*
7731 -- Find faces covered by input polygon
7732 -- NOTE: potential snapping changed polygon edges
7733 */
7734 qbox = *lwgeom_get_bbox( lwpoly_as_lwgeom(poly) );
7735 gbox_expand(&qbox, tol);
7736 faces = lwt_be_getFaceWithinBox2D( topo, &qbox, &nfacesinbox,
7737 LWT_COL_FACE_ALL, 0 );
7738 if (nfacesinbox == UINT64_MAX)
7739 {
7740 lwfree(ids);
7742 return NULL;
7743 }
7744
7745 num = 0;
7746 if ( nfacesinbox )
7747 {
7748 polyg = LWGEOM2GEOS(lwpoly_as_lwgeom(poly), 0);
7749 if ( ! polyg )
7750 {
7751 _lwt_release_faces(faces, nfacesinbox);
7752 lwerror("Could not convert poly geometry to GEOS: %s", lwgeom_geos_errmsg);
7753 return NULL;
7754 }
7755 ppoly = GEOSPrepare(polyg);
7756 ids = lwalloc(sizeof(LWT_ELEMID)*nfacesinbox);
7757 for ( j=0; j<nfacesinbox; ++j )
7758 {
7759 LWT_ISO_FACE *f = &(faces[j]);
7760 LWGEOM *fg;
7761 GEOSGeometry *fgg, *sp;
7762 int covers;
7763
7764 /* check if a point on this face surface is covered by our polygon */
7765 fg = lwt_GetFaceGeometry( topo, f->face_id );
7766 if ( ! fg )
7767 {
7768 j = f->face_id; /* so we can destroy faces */
7769 GEOSPreparedGeom_destroy(ppoly);
7770 GEOSGeom_destroy(polyg);
7771 lwfree(ids);
7772 _lwt_release_faces(faces, nfacesinbox);
7773 lwerror("Could not get geometry of face %" LWTFMT_ELEMID, j);
7774 return NULL;
7775 }
7776 /* check if a point on this face's surface is covered by our polygon */
7777 fgg = LWGEOM2GEOS(fg, 0);
7778 lwgeom_free(fg);
7779 if ( ! fgg )
7780 {
7781 GEOSPreparedGeom_destroy(ppoly);
7782 GEOSGeom_destroy(polyg);
7783 _lwt_release_faces(faces, nfacesinbox);
7784 lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
7785 return NULL;
7786 }
7787 sp = GEOSPointOnSurface(fgg);
7788 GEOSGeom_destroy(fgg);
7789 if ( ! sp )
7790 {
7791 GEOSPreparedGeom_destroy(ppoly);
7792 GEOSGeom_destroy(polyg);
7793 _lwt_release_faces(faces, nfacesinbox);
7794 lwerror("Could not find point on face surface: %s", lwgeom_geos_errmsg);
7795 return NULL;
7796 }
7797 covers = GEOSPreparedCovers( ppoly, sp );
7798 GEOSGeom_destroy(sp);
7799 if (covers == 2)
7800 {
7801 GEOSPreparedGeom_destroy(ppoly);
7802 GEOSGeom_destroy(polyg);
7803 _lwt_release_faces(faces, nfacesinbox);
7804 lwerror("PreparedCovers error: %s", lwgeom_geos_errmsg);
7805 return NULL;
7806 }
7807 if ( ! covers )
7808 {
7809 continue; /* we're not composed by this face */
7810 }
7811
7812 /* TODO: avoid duplicates ? */
7813 ids[num++] = f->face_id;
7814 }
7815 GEOSPreparedGeom_destroy(ppoly);
7816 GEOSGeom_destroy(polyg);
7817 _lwt_release_faces(faces, nfacesinbox);
7818 }
7819
7820 /* possibly 0 if non face's surface point was found
7821 * to be covered by input polygon */
7822 *nfaces = num;
7823
7824 return ids;
7825}
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:1246
void * lwalloc(size_t size)
Definition lwutil.c:227
void lwfree(void *mem)
Definition lwutil.c:248
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:771
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:357
int lwpoly_is_empty(const LWPOLY *poly)
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_FACE_ALL
#define PGTOPO_BE_ERROR()
#define LWTFMT_ELEMID
Datum covers(PG_FUNCTION_ARGS)
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
LWT_ISO_FACE * lwt_be_getFaceWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
void _lwt_release_faces(LWT_ISO_FACE *faces, int num_faces)
static void lwt_LoadPolygon(LWT_TOPOLOGY *topo, const LWPOLY *poly, double tol)
#define _LWT_MINTOLERANCE(topo, geom)
LWGEOM * lwt_GetFaceGeometry(LWT_TOPOLOGY *topo, LWT_ELEMID faceid)
Return the geometry of a face.
LWT_ELEMID face_id

References _LWT_MINTOLERANCE, _lwt_release_faces(), covers(), LWT_ISO_FACE::face_id, gbox_expand(), lwalloc(), LWDEBUGF, lwerror(), lwfree(), LWGEOM2GEOS(), lwgeom_free(), lwgeom_geos_errmsg, lwgeom_get_bbox(), lwpoly_as_lwgeom(), lwpoly_is_empty(), lwt_be_getFaceWithinBox2D(), LWT_COL_FACE_ALL, lwt_GetFaceGeometry(), lwt_LoadPolygon(), LWTFMT_ELEMID, and PGTOPO_BE_ERROR.

Here is the call graph for this function: