PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ lwt_Polygonize()

int lwt_Polygonize ( LWT_TOPOLOGY topo)

Definition at line 802 of file lwgeom_topo_polygonizer.c.

803 {
804  /*
805  Fetch all edges
806  Sort edges by edge_id
807  Mark all edges' left and right face as -1
808  Iteratively:
809  Fetch next edge with left or right face == -1
810  For each side with face == -1:
811  Find ring on its side
812  If ring is CCW:
813  create a new face, assign to the ring edges' appropriate side
814  If ring is CW (face needs to be same of external):
815  assign a negative face_id the ring edges' appropriate side
816  Now for each edge with a negative face_id on the side:
817  Find containing face (mbr cache and all)
818  Update with id of containing face
819  */
820 
821  const LWT_BE_IFACE *iface = topo->be_iface;
822  LWT_ISO_EDGE *edge;
823  int numfaces = -1;
824  LWT_ISO_EDGE_TABLE edgetable;
825  LWT_EDGERING_ARRAY holes, shells;
826  int i;
827  int err = 0;
828 
829  LWT_EDGERING_ARRAY_INIT(&holes);
830  LWT_EDGERING_ARRAY_INIT(&shells);
831 
832  initGEOS(lwnotice, lwgeom_geos_error);
833 
834  /*
835  Check if Topology already contains some Face
836  (ignoring the Universal Face)
837  */
838  numfaces = _lwt_CheckFacesExist(topo);
839  if ( numfaces != 0 ) {
840  if ( numfaces > 0 ) {
841  /* Faces exist */
842  lwerror("Polygonize: face table is not empty.");
843  }
844  /* Backend error, message should have been printed already */
845  return -1;
846  }
847 
848 
849  edgetable.edges = _lwt_FetchAllEdges(topo, &(edgetable.size));
850  if ( ! edgetable.edges ) {
851  if (edgetable.size == 0) {
852  /* not an error: no Edges */
853  return 0;
854  }
855  /* error should have been printed already */
856  return -1;
857  }
858 
859  /* Sort edges by ID (to allow btree searches) */
860  qsort(edgetable.edges, edgetable.size, sizeof(LWT_ISO_EDGE), compare_iso_edges_by_id);
861 
862  /* Mark all edges as unvisited */
863  for (i=0; i<edgetable.size; ++i)
864  edgetable.edges[i].face_left = edgetable.edges[i].face_right = -1;
865 
866  i = 0;
867  while (1)
868  {
869  i = _lwt_FetchNextUnvisitedEdge(topo, &edgetable, i);
870  if ( i < 0 ) break; /* end of unvisited */
871  edge = &(edgetable.edges[i]);
872 
873  LWT_ELEMID newface = -1;
874 
875  LWDEBUGF(1, "Next face-missing edge has id:%lld, face_left:%lld, face_right:%lld",
876  edge->edge_id, edge->face_left, edge->face_right);
877  if ( edge->face_left == -1 )
878  {
879  err = _lwt_RegisterFaceOnEdgeSide(topo, edge, 1, &edgetable,
880  &holes, &shells, &newface);
881  if ( err ) break;
882  LWDEBUGF(1, "New face on the left of edge %lld is %lld",
883  edge->edge_id, newface);
884  edge->face_left = newface;
885  }
886  if ( edge->face_right == -1 )
887  {
888  err = _lwt_RegisterFaceOnEdgeSide(topo, edge, -1, &edgetable,
889  &holes, &shells, &newface);
890  if ( err ) break;
891  LWDEBUGF(1, "New face on the right of edge %lld is %lld",
892  edge->edge_id, newface);
893  edge->face_right = newface;
894  }
895  }
896 
897  if ( err )
898  {
899  _lwt_release_edges(edgetable.edges, edgetable.size);
900  LWT_EDGERING_ARRAY_CLEAN( &holes );
901  LWT_EDGERING_ARRAY_CLEAN( &shells );
902  lwerror("Errors fetching or registering face-missing edges: %s",
903  lwt_be_lastErrorMessage(iface));
904  return -1;
905  }
906 
907  LWDEBUGF(1, "Found %d holes and %d shells", holes.size, shells.size);
908 
909  /* TODO: sort holes by pt.x, sort shells by bbox.xmin */
910 
911  /* Assign shells to holes */
912  for (i=0; i<holes.size; ++i)
913  {
914  LWT_ELEMID containing_face;
915  LWT_EDGERING *ring = holes.rings[i];
916 
917  containing_face = _lwt_FindFaceContainingRing(topo, ring, &shells);
918  LWDEBUGF(1, "Ring %d contained by face %" LWTFMT_ELEMID, i, containing_face);
919  if ( containing_face == -1 )
920  {
921  _lwt_release_edges(edgetable.edges, edgetable.size);
922  LWT_EDGERING_ARRAY_CLEAN( &holes );
923  LWT_EDGERING_ARRAY_CLEAN( &shells );
924  lwerror("Errors finding face containing ring: %s",
925  lwt_be_lastErrorMessage(iface));
926  return -1;
927  }
928  int ret = _lwt_UpdateEdgeRingSideFace(topo, holes.rings[i], containing_face);
929  if ( ret )
930  {
931  _lwt_release_edges(edgetable.edges, edgetable.size);
932  LWT_EDGERING_ARRAY_CLEAN( &holes );
933  LWT_EDGERING_ARRAY_CLEAN( &shells );
934  lwerror("Errors updating edgering side face: %s",
935  lwt_be_lastErrorMessage(iface));
936  return -1;
937  }
938  }
939 
940  LWDEBUG(1, "All holes assigned, cleaning up");
941 
942  _lwt_release_edges(edgetable.edges, edgetable.size);
943 
944  /* delete all shell and hole EDGERINGS */
945  LWT_EDGERING_ARRAY_CLEAN( &holes );
946  LWT_EDGERING_ARRAY_CLEAN( &shells );
947 
948  return 0;
949 }
void lwgeom_geos_error(const char *fmt,...)
LWT_INT64 LWT_ELEMID
Identifier of topology element.
const char * lwt_be_lastErrorMessage(const LWT_BE_IFACE *be)
Definition: lwgeom_topo.c:114
void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:460
#define LWTFMT_ELEMID
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:101
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:106
void lwnotice(const char *fmt,...) __attribute__((format(printf
Write a notice out to the notice handler.
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static int _lwt_UpdateEdgeRingSideFace(LWT_TOPOLOGY *topo, LWT_EDGERING *ring, LWT_ELEMID face)
static int _lwt_CheckFacesExist(LWT_TOPOLOGY *topo)
#define LWT_EDGERING_ARRAY_INIT(a)
static int _lwt_RegisterFaceOnEdgeSide(LWT_TOPOLOGY *topo, LWT_ISO_EDGE *edge, int side, LWT_ISO_EDGE_TABLE *edges, LWT_EDGERING_ARRAY *holes, LWT_EDGERING_ARRAY *shells, LWT_ELEMID *registered)
static LWT_ELEMID _lwt_FindFaceContainingRing(LWT_TOPOLOGY *topo, LWT_EDGERING *ring, LWT_EDGERING_ARRAY *shells)
#define LWT_EDGERING_ARRAY_CLEAN(a)
static LWT_ISO_EDGE * _lwt_FetchAllEdges(LWT_TOPOLOGY *topo, int *numedges)
static int compare_iso_edges_by_id(const void *si1, const void *si2)
static int _lwt_FetchNextUnvisitedEdge(__attribute__((__unused__)) LWT_TOPOLOGY *topo, LWT_ISO_EDGE_TABLE *etab, int from)
LWT_ELEMID face_right
LWT_ELEMID face_left
LWT_ELEMID edge_id
const LWT_BE_IFACE * be_iface

References _lwt_CheckFacesExist(), _lwt_FetchAllEdges(), _lwt_FetchNextUnvisitedEdge(), _lwt_FindFaceContainingRing(), _lwt_RegisterFaceOnEdgeSide(), _lwt_release_edges(), _lwt_UpdateEdgeRingSideFace(), LWT_TOPOLOGY_T::be_iface, compare_iso_edges_by_id(), LWT_ISO_EDGE::edge_id, LWT_ISO_EDGE_TABLE_T::edges, LWT_ISO_EDGE::face_left, LWT_ISO_EDGE::face_right, LWDEBUG, LWDEBUGF, lwerror(), lwgeom_geos_error(), lwnotice(), lwt_be_lastErrorMessage(), LWT_EDGERING_ARRAY_CLEAN, LWT_EDGERING_ARRAY_INIT, LWTFMT_ELEMID, LWT_EDGERING_ARRAY_T::rings, LWT_ISO_EDGE_TABLE_T::size, and LWT_EDGERING_ARRAY_T::size.

Here is the call graph for this function: