PostGIS  3.4.0dev-r@@SVN_REVISION@@

◆ 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 3068 of file lwgeom_topo.c.

3069 {
3070  LWGEOM *face;
3071  LWPOLY *facepoly;
3072  LWT_ISO_EDGE *edges;
3073  uint64_t numfaceedges;
3074  int fields;
3075  uint32_t i;
3076  int nseid = 0; /* number of signed edge ids */
3077  int prevseid;
3078  LWT_ELEMID *seid; /* signed edge ids */
3079 
3080  /* Get list of face edges */
3081  numfaceedges = 1;
3082  fields = LWT_COL_EDGE_EDGE_ID |
3086  ;
3087  edges = lwt_be_getEdgeByFace( topo, &face_id, &numfaceedges, fields, NULL );
3088  if (numfaceedges == UINT64_MAX)
3089  {
3090  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
3091  return -1;
3092  }
3093  if ( ! numfaceedges ) return 0; /* no edges in output */
3094  LWDEBUGF(1, "lwt_GetFaceEdges: lwt_be_getEdgeByFace returned %d edges", numfaceedges);
3095 
3096  /* order edges by occurrence in face */
3097 
3098  face = _lwt_FaceByEdges(topo, edges, numfaceedges);
3099  if ( ! face )
3100  {
3101  /* _lwt_FaceByEdges should have already invoked lwerror in this case */
3102  _lwt_release_edges(edges, numfaceedges);
3103  return -1;
3104  }
3105 
3106  if ( lwgeom_is_empty(face) )
3107  {
3108  /* no edges in output */
3109  _lwt_release_edges(edges, numfaceedges);
3110  lwgeom_free(face);
3111  return 0;
3112  }
3113 
3114  /* force_lhr, if the face is not the universe */
3115  /* _lwt_FaceByEdges seems to guaranteed RHR */
3116  /* lwgeom_force_clockwise(face); */
3117  if ( face_id ) lwgeom_reverse_in_place(face);
3118 
3119 #if 0
3120  {
3121  size_t sz;
3122  char *wkt = lwgeom_to_wkt(face, WKT_EXTENDED, 6, &sz);
3123  LWDEBUGF(1, "Geometry of face %" LWTFMT_ELEMID " is: %s",
3124  face_id, wkt);
3125  lwfree(wkt);
3126  }
3127 #endif
3128 
3129  facepoly = lwgeom_as_lwpoly(face);
3130  if ( ! facepoly )
3131  {
3132  _lwt_release_edges(edges, numfaceedges);
3133  lwgeom_free(face);
3134  lwerror("Geometry of face %" LWTFMT_ELEMID " is not a polygon", face_id);
3135  return -1;
3136  }
3137 
3138  nseid = prevseid = 0;
3139  seid = lwalloc( sizeof(LWT_ELEMID) * numfaceedges );
3140 
3141  /* for each ring of the face polygon... */
3142  for ( i=0; i<facepoly->nrings; ++i )
3143  {
3144  const POINTARRAY *ring = facepoly->rings[i];
3145  int32_t j = 0;
3146  LWT_ISO_EDGE *nextedge;
3147  LWLINE *nextline;
3148 
3149  LWDEBUGF(1, "Ring %d has %d points", i, ring->npoints);
3150 
3151  while ( j < (int32_t) ring->npoints-1 )
3152  {
3153  LWDEBUGF(1, "Looking for edge covering ring %d from vertex %d",
3154  i, j);
3155 
3156  int edgeno = _lwt_FindNextRingEdge(ring, j, edges, numfaceedges);
3157  if ( edgeno == -1 )
3158  {
3159  /* should never happen */
3160  _lwt_release_edges(edges, numfaceedges);
3161  lwgeom_free(face);
3162  lwfree(seid);
3163  lwerror("No edge (among %d) found to be defining geometry of face %"
3164  LWTFMT_ELEMID, numfaceedges, face_id);
3165  return -1;
3166  }
3167 
3168  nextedge = &(edges[edgeno]);
3169  nextline = nextedge->geom;
3170 
3171  LWDEBUGF(1, "Edge %" LWTFMT_ELEMID
3172  " covers ring %d from vertex %d to %d",
3173  nextedge->edge_id, i, j, j + nextline->points->npoints - 1);
3174 
3175 #if 0
3176  {
3177  size_t sz;
3178  char *wkt = lwgeom_to_wkt(lwline_as_lwgeom(nextline), WKT_EXTENDED, 6, &sz);
3179  LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is %s",
3180  nextedge->edge_id, wkt);
3181  lwfree(wkt);
3182  }
3183 #endif
3184 
3185  j += nextline->points->npoints - 1;
3186 
3187  /* Add next edge to the output array */
3188  seid[nseid++] = nextedge->face_left == face_id ?
3189  nextedge->edge_id :
3190  -nextedge->edge_id;
3191 
3192  /* avoid checking again on next time turn */
3193  nextedge->face_left = nextedge->face_right = -1;
3194  }
3195 
3196  /* now "scroll" the list of edges so that the one
3197  * with smaller absolute edge_id is first */
3198  /* Range is: [prevseid, nseid) -- [inclusive, exclusive) */
3199  if ( (nseid - prevseid) > 1 )
3200  {{
3201  LWT_ELEMID minid = 0;
3202  int minidx = 0;
3203  LWDEBUGF(1, "Looking for smallest id among the %d edges "
3204  "composing ring %d", (nseid-prevseid), i);
3205  for ( j=prevseid; j<nseid; ++j )
3206  {
3207  LWT_ELEMID id = llabs(seid[j]);
3208  LWDEBUGF(1, "Abs id of edge in pos %d is %" LWTFMT_ELEMID, j, id);
3209  if ( ! minid || id < minid )
3210  {
3211  minid = id;
3212  minidx = j;
3213  }
3214  }
3215  LWDEBUGF(1, "Smallest id is %" LWTFMT_ELEMID
3216  " at position %d", minid, minidx);
3217  if ( minidx != prevseid )
3218  {
3219  _lwt_RotateElemidArray(seid, prevseid, nseid, minidx);
3220  }
3221  }}
3222 
3223  prevseid = nseid;
3224  }
3225 
3226  lwgeom_free(face);
3227  _lwt_release_edges(edges, numfaceedges);
3228 
3229  *out = seid;
3230  return nseid;
3231 }
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
#define WKT_EXTENDED
Definition: liblwgeom.h:2186
void lwfree(void *mem)
Definition: lwutil.c:242
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:708
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:215
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition: lwgeom.c:103
#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
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:125
static int _lwt_FindNextRingEdge(const POINTARRAY *ring, int from, const LWT_ISO_EDGE *edges, int numedges)
Definition: lwgeom_topo.c:2912
static LWT_ISO_EDGE * lwt_be_getEdgeByFace(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields, const GBOX *box)
Definition: lwgeom_topo.c:244
static void _lwt_RotateElemidArray(LWT_ELEMID *ary, int from, int to, int rotidx)
Definition: lwgeom_topo.c:3059
static LWGEOM * _lwt_FaceByEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edges, int numfaceedges)
Definition: lwgeom_topo.c:2770
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:43
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:471
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:203
POINTARRAY * points
Definition: liblwgeom.h:483
POINTARRAY ** rings
Definition: liblwgeom.h:519
uint32_t nrings
Definition: liblwgeom.h:524
LWT_ELEMID face_right
LWT_ELEMID face_left
LWLINE * geom
LWT_ELEMID edge_id
const LWT_BE_IFACE * be_iface
uint32_t npoints
Definition: liblwgeom.h:427

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: