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

References _lwt_release_edges(), _lwt_release_nodes(), LWT_TOPOLOGY_T::be_iface, contains(), LWT_ISO_EDGE::edge_id, LWT_ISO_NODE::geom, LWT_ISO_EDGE::geom, LWDEBUGF, lwerror(), LWGEOM2GEOS(), lwgeom_geos_errmsg, lwgeom_geos_error(), lwgeom_get_bbox(), lwline_as_lwgeom(), lwnotice(), lwpoint_as_lwgeom(), lwt_be_getEdgeWithinBox2D(), lwt_be_getNodeWithinBox2D(), lwt_be_lastErrorMessage(), LWT_COL_EDGE_ALL, LWT_COL_NODE_ALL, LWTFMT_ELEMID, and LWT_ISO_NODE::node_id.

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

592 {
593  int i, num_nodes, num_edges;
594  LWT_ISO_EDGE *edges;
595  LWT_ISO_NODE *nodes;
596  const GBOX *edgebox;
597  GEOSGeometry *edgegg;
598  const GEOSPreparedGeometry* prepared_edge;
599 
600  initGEOS(lwnotice, lwgeom_geos_error);
601 
602  edgegg = LWGEOM2GEOS( lwline_as_lwgeom(geom), 0);
603  if ( ! edgegg ) {
604  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
605  return -1;
606  }
607  prepared_edge = GEOSPrepare( edgegg );
608  if ( ! prepared_edge ) {
609  lwerror("Could not prepare edge geometry: %s", lwgeom_geos_errmsg);
610  return -1;
611  }
612  edgebox = lwgeom_get_bbox( lwline_as_lwgeom(geom) );
613 
614  /* loop over each node within the edge's gbox */
615  nodes = lwt_be_getNodeWithinBox2D( topo, edgebox, &num_nodes,
616  LWT_COL_NODE_ALL, 0 );
617  LWDEBUGF(1, "lwt_be_getNodeWithinBox2D returned %d nodes", num_nodes);
618  if ( num_nodes == -1 ) {
619  GEOSPreparedGeom_destroy(prepared_edge);
620  GEOSGeom_destroy(edgegg);
621  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
622  return -1;
623  }
624  for ( i=0; i<num_nodes; ++i )
625  {
626  LWT_ISO_NODE* node = &(nodes[i]);
627  GEOSGeometry *nodegg;
628  int contains;
629  if ( node->node_id == start_node ) continue;
630  if ( node->node_id == end_node ) continue;
631  /* check if the edge contains this node (not on boundary) */
632  nodegg = LWGEOM2GEOS( lwpoint_as_lwgeom(node->geom) , 0);
633  /* ST_RelateMatch(rec.relate, 'T********') */
634  contains = GEOSPreparedContains( prepared_edge, nodegg );
635  GEOSGeom_destroy(nodegg);
636  if (contains == 2)
637  {
638  GEOSPreparedGeom_destroy(prepared_edge);
639  GEOSGeom_destroy(edgegg);
640  _lwt_release_nodes(nodes, num_nodes);
641  lwerror("GEOS exception on PreparedContains: %s", lwgeom_geos_errmsg);
642  return -1;
643  }
644  if ( contains )
645  {
646  GEOSPreparedGeom_destroy(prepared_edge);
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 %d edges", num_edges);
659  if ( num_edges == -1 ) {
660  GEOSPreparedGeom_destroy(prepared_edge);
661  GEOSGeom_destroy(edgegg);
662  lwerror("Backend error: %s", lwt_be_lastErrorMessage(topo->be_iface));
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 %d has NULL geometry!", edge_id);
678  return -1;
679  }
680 
681  eegg = LWGEOM2GEOS( lwline_as_lwgeom(edge->geom), 0 );
682  if ( ! eegg ) {
683  GEOSPreparedGeom_destroy(prepared_edge);
684  GEOSGeom_destroy(edgegg);
685  _lwt_release_edges(edges, num_edges);
686  lwerror("Could not convert edge geometry to GEOS: %s", lwgeom_geos_errmsg);
687  return -1;
688  }
689 
690  LWDEBUGF(2, "Edge %d converted to GEOS", edge_id);
691 
692  /* check if the edge crosses our edge (not boundary-boundary) */
693 
694  relate = GEOSRelateBoundaryNodeRule(eegg, edgegg, 2);
695  if ( ! relate ) {
696  GEOSGeom_destroy(eegg);
697  GEOSPreparedGeom_destroy(prepared_edge);
698  GEOSGeom_destroy(edgegg);
699  _lwt_release_edges(edges, num_edges);
700  lwerror("GEOSRelateBoundaryNodeRule error: %s", lwgeom_geos_errmsg);
701  return -1;
702  }
703 
704  LWDEBUGF(2, "Edge %d relate pattern is %s", edge_id, relate);
705 
706  match = GEOSRelatePatternMatch(relate, "F********");
707  if ( match ) {
708  /* error or no interior intersection */
709  GEOSGeom_destroy(eegg);
710  GEOSFree(relate);
711  if ( match == 2 ) {
712  _lwt_release_edges(edges, num_edges);
713  GEOSPreparedGeom_destroy(prepared_edge);
714  GEOSGeom_destroy(edgegg);
715  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
716  return -1;
717  }
718  else continue; /* no interior intersection */
719  }
720 
721  match = GEOSRelatePatternMatch(relate, "1FFF*FFF2");
722  if ( match ) {
723  _lwt_release_edges(edges, num_edges);
724  GEOSPreparedGeom_destroy(prepared_edge);
725  GEOSGeom_destroy(edgegg);
726  GEOSGeom_destroy(eegg);
727  GEOSFree(relate);
728  if ( match == 2 ) {
729  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
730  } else {
731  lwerror("SQL/MM Spatial exception - coincident edge %" LWTFMT_ELEMID,
732  edge_id);
733  }
734  return -1;
735  }
736 
737  match = GEOSRelatePatternMatch(relate, "1********");
738  if ( match ) {
739  _lwt_release_edges(edges, num_edges);
740  GEOSPreparedGeom_destroy(prepared_edge);
741  GEOSGeom_destroy(edgegg);
742  GEOSGeom_destroy(eegg);
743  GEOSFree(relate);
744  if ( match == 2 ) {
745  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
746  } else {
747  lwerror("Spatial exception - geometry intersects edge %"
748  LWTFMT_ELEMID, edge_id);
749  }
750  return -1;
751  }
752 
753  match = GEOSRelatePatternMatch(relate, "T********");
754  if ( match ) {
755  _lwt_release_edges(edges, num_edges);
756  GEOSPreparedGeom_destroy(prepared_edge);
757  GEOSGeom_destroy(edgegg);
758  GEOSGeom_destroy(eegg);
759  GEOSFree(relate);
760  if ( match == 2 ) {
761  lwerror("GEOSRelatePatternMatch error: %s", lwgeom_geos_errmsg);
762  } else {
763  lwerror("SQL/MM Spatial exception - geometry crosses edge %"
764  LWTFMT_ELEMID, edge_id);
765  }
766  return -1;
767  }
768 
769  LWDEBUGF(2, "Edge %d analisys completed, it does no harm", edge_id);
770 
771  GEOSFree(relate);
772  GEOSGeom_destroy(eegg);
773  }
774  if ( edges ) _lwt_release_edges(edges, num_edges);
775  /* would be NULL if num_edges was 0 */
776 
777  GEOSPreparedGeom_destroy(prepared_edge);
778  GEOSGeom_destroy(edgegg);
779 
780  return 0;
781 }
static void _lwt_release_nodes(LWT_ISO_NODE *nodes, int num_nodes)
Definition: lwgeom_topo.c:477
LWPOINT * geom
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:177
Datum contains(PG_FUNCTION_ARGS)
char lwgeom_geos_errmsg[LWGEOM_GEOS_ERRMSG_MAXSIZE]
LWLINE * geom
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:298
void lwgeom_geos_error(const char *fmt,...)
const LWT_BE_IFACE * be_iface
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:689
#define LWT_COL_EDGE_ALL
LWT_ELEMID node_id
LWT_ELEMID edge_id
GEOSGeometry * LWGEOM2GEOS(const LWGEOM *lwgeom, int autofix)
#define LWT_COL_NODE_ALL
static void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
Definition: lwgeom_topo.c:467
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:303
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
static LWT_ISO_EDGE * lwt_be_getEdgeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
Definition: lwgeom_topo.c:179
static LWT_ISO_NODE * lwt_be_getNodeWithinBox2D(const LWT_TOPOLOGY *topo, const GBOX *box, int *numelems, int fields, int limit)
Definition: lwgeom_topo.c:171
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
Here is the call graph for this function:
Here is the caller graph for this function: