PostGIS  3.0.6dev-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 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  return -1;
3057  }
3058 
3059  if ( lwgeom_is_empty(face) )
3060  {
3061  /* no edges in output */
3062  _lwt_release_edges(edges, numfaceedges);
3063  lwgeom_free(face);
3064  return 0;
3065  }
3066 
3067  /* force_lhr, if the face is not the universe */
3068  /* _lwt_FaceByEdges seems to guaranteed RHR */
3069  /* lwgeom_force_clockwise(face); */
3070  if ( face_id ) lwgeom_reverse_in_place(face);
3071 
3072 #if 0
3073  {
3074  size_t sz;
3075  char *wkt = lwgeom_to_wkt(face, WKT_EXTENDED, 6, &sz);
3076  LWDEBUGF(1, "Geometry of face %" LWTFMT_ELEMID " is: %s",
3077  face_id, wkt);
3078  lwfree(wkt);
3079  }
3080 #endif
3081 
3082  facepoly = lwgeom_as_lwpoly(face);
3083  if ( ! facepoly )
3084  {
3085  _lwt_release_edges(edges, numfaceedges);
3086  lwgeom_free(face);
3087  lwerror("Geometry of face %" LWTFMT_ELEMID " is not a polygon", face_id);
3088  return -1;
3089  }
3090 
3091  nseid = prevseid = 0;
3092  seid = lwalloc( sizeof(LWT_ELEMID) * numfaceedges );
3093 
3094  /* for each ring of the face polygon... */
3095  for ( i=0; i<facepoly->nrings; ++i )
3096  {
3097  const POINTARRAY *ring = facepoly->rings[i];
3098  int32_t j = 0;
3099  LWT_ISO_EDGE *nextedge;
3100  LWLINE *nextline;
3101 
3102  LWDEBUGF(1, "Ring %d has %d points", i, ring->npoints);
3103 
3104  while ( j < (int32_t) ring->npoints-1 )
3105  {
3106  LWDEBUGF(1, "Looking for edge covering ring %d from vertex %d",
3107  i, j);
3108 
3109  int edgeno = _lwt_FindNextRingEdge(ring, j, edges, numfaceedges);
3110  if ( edgeno == -1 )
3111  {
3112  /* should never happen */
3113  _lwt_release_edges(edges, numfaceedges);
3114  lwgeom_free(face);
3115  lwfree(seid);
3116  lwerror("No edge (among %d) found to be defining geometry of face %"
3117  LWTFMT_ELEMID, numfaceedges, face_id);
3118  return -1;
3119  }
3120 
3121  nextedge = &(edges[edgeno]);
3122  nextline = nextedge->geom;
3123 
3124  LWDEBUGF(1, "Edge %" LWTFMT_ELEMID
3125  " covers ring %d from vertex %d to %d",
3126  nextedge->edge_id, i, j, j + nextline->points->npoints - 1);
3127 
3128 #if 0
3129  {
3130  size_t sz;
3131  char *wkt = lwgeom_to_wkt(lwline_as_lwgeom(nextline), WKT_EXTENDED, 6, &sz);
3132  LWDEBUGF(1, "Edge %" LWTFMT_ELEMID " is %s",
3133  nextedge->edge_id, wkt);
3134  lwfree(wkt);
3135  }
3136 #endif
3137 
3138  j += nextline->points->npoints - 1;
3139 
3140  /* Add next edge to the output array */
3141  seid[nseid++] = nextedge->face_left == face_id ?
3142  nextedge->edge_id :
3143  -nextedge->edge_id;
3144 
3145  /* avoid checking again on next time turn */
3146  nextedge->face_left = nextedge->face_right = -1;
3147  }
3148 
3149  /* now "scroll" the list of edges so that the one
3150  * with smaller absolute edge_id is first */
3151  /* Range is: [prevseid, nseid) -- [inclusive, exclusive) */
3152  if ( (nseid - prevseid) > 1 )
3153  {{
3154  LWT_ELEMID minid = 0;
3155  int minidx = 0;
3156  LWDEBUGF(1, "Looking for smallest id among the %d edges "
3157  "composing ring %d", (nseid-prevseid), i);
3158  for ( j=prevseid; j<nseid; ++j )
3159  {
3160  LWT_ELEMID id = llabs(seid[j]);
3161  LWDEBUGF(1, "Abs id of edge in pos %d is %" LWTFMT_ELEMID, j, id);
3162  if ( ! minid || id < minid )
3163  {
3164  minid = id;
3165  minidx = j;
3166  }
3167  }
3168  LWDEBUGF(1, "Smallest id is %" LWTFMT_ELEMID
3169  " at position %d", minid, minidx);
3170  if ( minidx != prevseid )
3171  {
3172  _lwt_RotateElemidArray(seid, prevseid, nseid, minidx);
3173  }
3174  }}
3175 
3176  prevseid = nseid;
3177  }
3178 
3179  lwgeom_free(face);
3180  _lwt_release_edges(edges, numfaceedges);
3181 
3182  *out = seid;
3183  return nseid;
3184 }
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:321
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1138
#define WKT_EXTENDED
Definition: liblwgeom.h:2132
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:676
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:197
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
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:119
static int _lwt_FindNextRingEdge(const POINTARRAY *ring, int from, const LWT_ISO_EDGE *edges, int numedges)
Definition: lwgeom_topo.c:2866
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:238
static void _lwt_RotateElemidArray(LWT_ELEMID *ary, int from, int to, int rotidx)
Definition: lwgeom_topo.c:3013
static LWGEOM * _lwt_FaceByEdges(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edges, int numfaceedges)
Definition: lwgeom_topo.c:2744
#define LWTFMT_ELEMID
Definition: lwgeom_topo.c:43
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:451
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
LWLINE * geom
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: