PostGIS  2.4.9dev-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 3079 of file lwgeom_topo.c.

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(), 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.

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