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

◆ lwt_GetFaceEdges()

int lwt_GetFaceEdges ( LWT_TOPOLOGY topo,
LWT_ELEMID  face,
LWT_ELEMID **  edges 
)

Return the list of directed edges bounding a face.

For ST_GetFaceEdges

Parameters
topothe topology to operate on
faceidentifier of the face
edgeswill be set to an array of signed edge identifiers, will need to be released with lwfree
Returns
the number of edges in the edges array, or -1 on error (liblwgeom error handler will be invoked with error message)

Definition at line 3022 of file lwgeom_topo.c.

3023{
3024 LWGEOM *face;
3025 LWPOLY *facepoly;
3026 LWT_ISO_EDGE *edges;
3027 uint64_t numfaceedges;
3028 int fields;
3029 uint32_t i;
3030 int nseid = 0; /* number of signed edge ids */
3031 int prevseid;
3032 LWT_ELEMID *seid; /* signed edge ids */
3033
3034 /* Get list of face edges */
3035 numfaceedges = 1;
3036 fields = LWT_COL_EDGE_EDGE_ID |
3040 ;
3041 edges = lwt_be_getEdgeByFace( topo, &face_id, &numfaceedges, fields, NULL );
3042 if (numfaceedges == UINT64_MAX)
3043 {
3044 lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3045 return -1;
3046 }
3047 if ( ! numfaceedges ) return 0; /* no edges in output */
3048
3049 /* order edges by occurrence in face */
3050
3051 face = _lwt_FaceByEdges(topo, edges, numfaceedges);
3052 if ( ! face )
3053 {
3054 /* _lwt_FaceByEdges should have already invoked lwerror in this case */
3055 _lwt_release_edges(edges, numfaceedges);
3056 lwerror("Corrupted topology: unable to build geometry of face %"
3057 LWTFMT_ELEMID " from its %"PRIu64" edges", face_id, numfaceedges);
3058 return -1;
3059 }
3060
3061 if ( lwgeom_is_empty(face) )
3062 {
3063 /* no edges in output */
3064 _lwt_release_edges(edges, numfaceedges);
3065 lwgeom_free(face);
3066 return 0;
3067 }
3068
3069 /* force_lhr, if the face is not the universe */
3070 /* _lwt_FaceByEdges seems to guaranteed RHR */
3071 /* lwgeom_force_clockwise(face); */
3072 if ( face_id ) lwgeom_reverse_in_place(face);
3073
3074#if 0
3075 {
3076 size_t sz;
3077 char *wkt = lwgeom_to_wkt(face, WKT_EXTENDED, 6, &sz);
3078 LWDEBUGF(1, "Geometry of face %" LWTFMT_ELEMID " is: %s",
3079 face_id, wkt);
3080 lwfree(wkt);
3081 }
3082#endif
3083
3084 facepoly = lwgeom_as_lwpoly(face);
3085 if ( ! facepoly )
3086 {
3087 _lwt_release_edges(edges, numfaceedges);
3088 lwgeom_free(face);
3089 lwerror("Geometry of face %" LWTFMT_ELEMID " is not a polygon", face_id);
3090 return -1;
3091 }
3092
3093 nseid = prevseid = 0;
3094 seid = lwalloc( sizeof(LWT_ELEMID) * numfaceedges );
3095
3096 /* for each ring of the face polygon... */
3097 for ( i=0; i<facepoly->nrings; ++i )
3098 {
3099 const POINTARRAY *ring = facepoly->rings[i];
3100 int32_t j = 0;
3101 LWT_ISO_EDGE *nextedge;
3102 LWLINE *nextline;
3103
3104 LWDEBUGF(1, "Ring %d has %d points", i, ring->npoints);
3105
3106 while ( j < (int32_t) ring->npoints-1 )
3107 {
3108 LWDEBUGF(1, "Looking for edge covering ring %d from vertex %d",
3109 i, j);
3110
3111 int edgeno = _lwt_FindNextRingEdge(ring, j, edges, numfaceedges);
3112 if ( edgeno == -1 )
3113 {
3114 /* should never happen */
3115 _lwt_release_edges(edges, numfaceedges);
3116 lwgeom_free(face);
3117 lwfree(seid);
3118 lwerror("No edge (among %d) found to be defining geometry of face %"
3119 LWTFMT_ELEMID, numfaceedges, face_id);
3120 return -1;
3121 }
3122
3123 nextedge = &(edges[edgeno]);
3124 nextline = nextedge->geom;
3125
3126 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID
3127 " covers ring %d from vertex %d to %d",
3128 nextedge->edge_id, i, j, j + nextline->points->npoints - 1);
3129
3130#if 0
3131 {
3132 size_t sz;
3133 char *wkt = lwgeom_to_wkt(lwline_as_lwgeom(nextline), WKT_EXTENDED, 6, &sz);
3134 LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is %s",
3135 nextedge->edge_id, wkt);
3136 lwfree(wkt);
3137 }
3138#endif
3139
3140 j += nextline->points->npoints - 1;
3141
3142 /* Add next edge to the output array */
3143 seid[nseid++] = nextedge->face_left == face_id ?
3144 nextedge->edge_id :
3145 -nextedge->edge_id;
3146
3147 /* avoid checking again on next time turn */
3148 nextedge->face_left = nextedge->face_right = -1;
3149 }
3150
3151 /* now "scroll" the list of edges so that the one
3152 * with smaller absolute edge_id is first */
3153 /* Range is: [prevseid, nseid) -- [inclusive, exclusive) */
3154 if ( (nseid - prevseid) > 1 )
3155 {{
3156 LWT_ELEMID minid = 0;
3157 int minidx = 0;
3158 LWDEBUGF(1, "Looking for smallest id among the %d edges "
3159 "composing ring %d", (nseid-prevseid), i);
3160 for ( j=prevseid; j<nseid; ++j )
3161 {
3162 LWT_ELEMID id = llabs(seid[j]);
3163 LWDEBUGF(1, "Abs id of edge in pos %d is %" LWTFMT_ELEMID, j, id);
3164 if ( ! minid || id < minid )
3165 {
3166 minid = id;
3167 minidx = j;
3168 }
3169 }
3170 LWDEBUGF(1, "Smallest id is %" LWTFMT_ELEMID
3171 " at position %d", minid, minidx);
3172 if ( minidx != prevseid )
3173 {
3174 _lwt_RotateElemidArray(seid, prevseid, nseid, minidx);
3175 }
3176 }}
3177
3178 prevseid = nseid;
3179 }
3180
3181 lwgeom_free(face);
3182 _lwt_release_edges(edges, numfaceedges);
3183
3184 *out = seid;
3185 return nseid;
3186}
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1138
#define WKT_EXTENDED
Definition liblwgeom.h:2132
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition lwout_wkt.c:676
void * lwalloc(size_t size)
Definition lwutil.c:227
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:197
void lwfree(void *mem)
Definition lwutil.c:242
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:321
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition lwgeom.c:102
#define LWT_COL_EDGE_FACE_RIGHT
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_EDGE_FACE_LEFT
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_EDGE_GEOM
#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 int _lwt_FindNextRingEdge(const POINTARRAY *ring, int from, const LWT_ISO_EDGE *edges, int numedges)
static void _lwt_RotateElemidArray(LWT_ELEMID *ary, int from, int to, int rotidx)
static LWT_ISO_EDGE * lwt_be_getEdgeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields, const GBOX *box)
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
#define LWTFMT_ELEMID
Definition lwgeom_topo.c:43
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
static LWGEOM * _lwt_FaceByEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edges, int numfaceedges)
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition lwinline.h:193
POINTARRAY * points
Definition liblwgeom.h:469
POINTARRAY ** rings
Definition liblwgeom.h:505
uint32_t nrings
Definition liblwgeom.h:510
LWT_ELEMID face_right
LWT_ELEMID face_left
LWT_ELEMID edge_id
const LWT_BE_IFACE * be_iface
uint32_t npoints
Definition liblwgeom.h:413

References _lwt_FaceByEdges(), _lwt_FindNextRingEdge(), _lwt_release_edges(), _lwt_RotateElemidArray(), LWT_TOPOLOGY_T::be_iface, LWT_ISO_EDGE::edge_id, LWT_ISO_EDGE::face_left, LWT_ISO_EDGE::face_right, LWT_ISO_EDGE::geom, lwalloc(), LWDEBUGF, lwerror(), lwfree(), lwgeom_as_lwpoly(), lwgeom_free(), lwgeom_is_empty(), lwgeom_reverse_in_place(), lwgeom_to_wkt(), lwline_as_lwgeom(), lwt_be_getEdgeByFace(), lwt_be_lastErrorMessage(), LWT_COL_EDGE_EDGE_ID, LWT_COL_EDGE_FACE_LEFT, LWT_COL_EDGE_FACE_RIGHT, LWT_COL_EDGE_GEOM, LWTFMT_ELEMID, POINTARRAY::npoints, LWPOLY::nrings, LWLINE::points, LWPOLY::rings, and WKT_EXTENDED.

Here is the call graph for this function: