PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ _lwt_CheckEdgeCrossing()

static int _lwt_CheckEdgeCrossing ( LWT_TOPOLOGY topo,
LWT_ELEMID  start_node,
LWT_ELEMID  end_node,
const LWLINE geom,
LWT_ELEMID  myself 
)
static

Definition at line 606 of file lwgeom_topo.c.

609 {
610  uint64_t i, num_nodes, num_edges;
611  LWT_ISO_EDGE *edges;
612  LWT_ISO_NODE *nodes;
613  const GBOX *edgebox;
614  GEOSGeometry *edgegg;
615 
616  initGEOS(lwnotice, lwgeom_geos_error);
617 
618  edgegg = LWGEOM2GEOS(lwline_as_lwgeom(geom), 0);
619  if (!edgegg)
620  {
621  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
622  return -1;
623  }
624  edgebox = lwgeom_get_bbox( lwline_as_lwgeom(geom) );
625 
626  /* loop over each node within the edge's gbox */
627  nodes = lwt_be_getNodeWithinBox2D( topo, edgebox, &num_nodes,
628  LWT_COL_NODE_ALL, 0 );
629  LWDEBUGF(1, "lwt_be_getNodeWithinBox2D returned %llu nodes", num_nodes);
630  if (num_nodes == UINT64_MAX)
631  {
632  PGTOPO_BE_ERROR();
633  return -1;
634  }
635  for ( i=0; i<num_nodes; ++i )
636  {
637  const POINT2D *pt;
638  LWT_ISO_NODE* node = &(nodes[i]);
639  if ( node->node_id == start_node ) continue;
640  if ( node->node_id == end_node ) continue;
641  /* check if the edge contains this node (not on boundary) */
642  /* ST_RelateMatch(rec.relate, 'T********') */
643  pt = getPoint2d_cp(node->geom->point, 0);
645  if ( contains )
646  {
647  GEOSGeom_destroy(edgegg);
648  _lwt_release_nodes(nodes, num_nodes);
649  lwerror("SQL/MM Spatial exception - geometry crosses a node");
650  return -1;
651  }
652  }
653  if ( nodes ) _lwt_release_nodes(nodes, num_nodes);
654  /* may be NULL if num_nodes == 0 */
655 
656  /* loop over each edge within the edge's gbox */
657  edges = lwt_be_getEdgeWithinBox2D( topo, edgebox, &num_edges, LWT_COL_EDGE_ALL, 0 );
658  LWDEBUGF(1, "lwt_be_getEdgeWithinBox2D returned %llu edges", num_edges);
659  if (num_edges == UINT64_MAX)
660  {
661  GEOSGeom_destroy(edgegg);
662  PGTOPO_BE_ERROR();
663  return -1;
664  }
665  for ( i=0; i<num_edges; ++i )
666  {
667  LWT_ISO_EDGE* edge = &(edges[i]);
668  LWT_ELEMID edge_id = edge->edge_id;
669  GEOSGeometry *eegg;
670  char *relate;
671  int match;
672 
673  if ( edge_id == myself ) continue;
674 
675  if ( ! edge->geom ) {
676  _lwt_release_edges(edges, num_edges);
677  lwerror("Edge %" LWTFMT_ELEMID " has NULL geometry!", edge_id);
678  return -1;
679  }
680 
681  eegg = LWGEOM2GEOS( lwline_as_lwgeom(edge->geom), 0 );
682  if ( ! eegg ) {
683  GEOSGeom_destroy(edgegg);
684  _lwt_release_edges(edges, num_edges);
685  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
686  return -1;
687  }
688 
689  LWDEBUGF(2, "Edge %" LWTFMT_ELEMID " converted to GEOS", edge_id);
690 
691  /* check if the edge has a non-boundary-boundary intersection with our edge */
692 
693  relate = GEOSRelateBoundaryNodeRule(eegg, edgegg, 2);
694  GEOSGeom_destroy(eegg);
695  if ( ! relate ) {
696  GEOSGeom_destroy(edgegg);
697  _lwt_release_edges(edges, num_edges);
698  lwerror("GEOSRelateBoundaryNodeRule error: %s", lwgeom_geos_errmsg);
699  return -1;
700  }
701 
702  LWDEBUGF(2, "Edge %" LWTFMT_ELEMID " relate pattern is %s", edge_id, relate);
703 
704  match = GEOSRelatePatternMatch(relate, "FF*F*****");
705  if ( match ) {
706  /* error or no interior intersection */
707  GEOSFree(relate);
708  if ( match == 2 ) {
709  _lwt_release_edges(edges, num_edges);
710  GEOSGeom_destroy(edgegg);
711  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
712  return -1;
713  }
714  else continue; /* no interior intersection */
715  }
716 
717  match = GEOSRelatePatternMatch(relate, "1FFF*FFF2");
718  if ( match ) {
719  _lwt_release_edges(edges, num_edges);
720  GEOSGeom_destroy(edgegg);
721  GEOSFree(relate);
722  if ( match == 2 ) {
723  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
724  } else {
725  lwerror("SQL/MM Spatial exception - coincident edge %" LWTFMT_ELEMID,
726  edge_id);
727  }
728  return -1;
729  }
730 
731  match = GEOSRelatePatternMatch(relate, "1********");
732  if ( match ) {
733  _lwt_release_edges(edges, num_edges);
734  GEOSGeom_destroy(edgegg);
735  GEOSFree(relate);
736  if ( match == 2 ) {
737  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
738  } else {
739  lwerror("Spatial exception - geometry intersects edge %"
740  LWTFMT_ELEMID, edge_id);
741  }
742  return -1;
743  }
744 
745  match = GEOSRelatePatternMatch(relate, "T********");
746  if ( match ) {
747  _lwt_release_edges(edges, num_edges);
748  GEOSGeom_destroy(edgegg);
749  GEOSFree(relate);
750  if ( match == 2 ) {
751  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
752  } else {
753  lwerror("SQL/MM Spatial exception - geometry crosses edge %"
754  LWTFMT_ELEMID, edge_id);
755  }
756  return -1;
757  }
758 
759  match = GEOSRelatePatternMatch(relate, "*T*******");
760  if ( match ) {
761  _lwt_release_edges(edges, num_edges);
762  GEOSGeom_destroy(edgegg);
763  GEOSFree(relate);
764  if ( match == 2 ) {
765  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
766  } else {
767  lwerror("Spatial exception - geometry boundary touches interior of edge %"
768  LWTFMT_ELEMID, edge_id);
769  }
770  return -1;
771  }
772 
773  match = GEOSRelatePatternMatch(relate, "***T*****");
774  if ( match ) {
775  _lwt_release_edges(edges, num_edges);
776  GEOSGeom_destroy(edgegg);
777  GEOSFree(relate);
778  if ( match == 2 ) {
779  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
780  } else {
781  lwerror("Spatial exception - boundary of edge %" LWTFMT_ELEMID" touches interior of geometry", edge_id);
782  }
783  return -1;
784  }
785 
786  LWDEBUGF(2, "Edge %" LWTFMT_ELEMID " analysis completed, it does no harm", edge_id);
787 
788  GEOSFree(relate);
789  }
790  LWDEBUGF(1, "No edge crossing detected among the %llu candidate edges", num_edges);
791  if ( edges ) _lwt_release_edges(edges, num_edges);
792  /* would be NULL if num_edges was 0 */
793 
794  GEOSGeom_destroy(edgegg);
795 
796  return 0;
797 }
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, uint8_t autofix)
void lwgeom_geos_error(const char *fmt,...)
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
#define LW_FALSE
Definition: liblwgeom.h:94
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition: lwgeom.c:743
int ptarray_contains_point_partial(const POINTARRAY *pa, const POINT2D *pt, int check_closed, int *winding_number)
Definition: ptarray.c:763
#define LW_BOUNDARY
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_EDGE_ALL
#define LWT_COL_NODE_ALL
#define PGTOPO_BE_ERROR()
#define LWTFMT_ELEMID
Datum contains(PG_FUNCTION_ARGS)
#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 void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
Definition: lwgeom_topo.c:470
LWT_ISO_EDGE * lwt_be_getEdgeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
Definition: lwgeom_topo.c:173
void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:460
static LWT_ISO_NODE * lwt_be_getNodeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, uint64_t *numelems, int fields, uint64_t limit)
Definition: lwgeom_topo.c:167
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.
Definition: lwinline.h:97
POINTARRAY * points
Definition: liblwgeom.h:483
POINTARRAY * point
Definition: liblwgeom.h:471
LWLINE * geom
LWT_ELEMID edge_id
LWT_ELEMID node_id
LWPOINT * geom

References _lwt_release_edges(), _lwt_release_nodes(), contains(), LWT_ISO_EDGE::edge_id, LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, getPoint2d_cp(), LW_BOUNDARY, LW_FALSE, LWDEBUGF, lwerror(), LWGEOM2GEOS(), lwgeom_geos_errmsg, lwgeom_geos_error(), lwgeom_get_bbox(), lwline_as_lwgeom(), lwnotice(), lwt_be_getEdgeWithinBox2D(), lwt_be_getNodeWithinBox2D(), LWT_COL_EDGE_ALL, LWT_COL_NODE_ALL, LWTFMT_ELEMID, LWT_ISO_NODE::node_id, PGTOPO_BE_ERROR, LWPOINT::point, LWLINE::points, and ptarray_contains_point_partial().

Referenced by _lwt_AddEdge(), lwt_AddIsoEdge(), and lwt_ChangeEdgeGeom().

Here is the call graph for this function:
Here is the caller graph for this function: