Find the face-id of the face properly containing a given point.
7829{
7832 uint64_t numedges, i;
7834 const POINT2D *closestPointOnEdge = NULL;
7835 uint32_t closestSegmentIndex;
7836 int closestSegmentSide;
7837 uint32_t closestPointVertex;
7838 const POINT2D *closestSegmentP0, *closestSegmentP1;
7840 double dist;
7842
7850 );
7851 if (numedges == UINT64_MAX)
7852 {
7854
7855 return -1;
7856 }
7857 if (numedges == 0)
7858 {
7859
7860 return 0;
7861 }
7862
7864 {
7868 return -1;
7869 }
7870
7872 {
7876 return -1;
7877 }
7878
7880 {
7884 return -1;
7885 }
7886
7888
7889
7897 closestSegmentP0->
x,
7898 closestSegmentP0->
y,
7899 closestSegmentP1->
x,
7901 );
7902
7903
7904
7905
7906
7907
7908
7909
7910
7911
7912
7913
7914
7915
7916
7917 const POINT2D *p = queryPoint;
7918 const POINT2D *A = closestSegmentP0;
7919 const POINT2D *B = closestSegmentP1;
7920 double r = ( (p->
x-A->
x) * (B->
x-A->
x) + (p->
y-A->
y) * (B->
y-A->
y) )/( (B->
x-A->
x)*(B->
x-A->
x) +(B->
y-A->
y)*(B->
y-A->
y) );
7922 {
7923 closestPointOnEdge = A;
7924 closestPointVertex = closestSegmentIndex;
7925 if ( closestSegmentIndex == 0 )
7926 {
7928 }
7929 }
7931 {
7932 closestPointOnEdge = B;
7933 closestPointVertex = closestSegmentIndex + 1;
7935 {
7936 closestNode = closestEdge->
end_node;
7937 }
7938 }
7939 else
7940 {
7942 }
7943
7944 if ( closestNode != 0 )
7945 {
7947 if ( dist == 0 )
7948 {
7950
7951
7952
7953
7954
7955
7956
7958 {
7960 lwerror(
"Two or more faces found");
7961 return -1;
7962 }
7963 containingFace = closestEdge->
face_left;
7964
7965
7966 numedges = 1;
7968 if (numedges == UINT64_MAX)
7969 {
7971
7973 return -1;
7974 }
7975 for (i=0; i<numedges; ++i)
7976 {
7977 if ( edges[i].face_left != containingFace ||
7978 edges[i].face_right != containingFace )
7979 {
7982 lwerror(
"Two or more faces found");
7983 return -1;
7984 }
7985 }
7986 if (numedges < 1 )
7987 {
7989 ") returns no edges when we previously found edge %"
7991 closestNode, closestEdge->
edge_id);
7994 return -1;
7995 }
7996 LWDEBUGF(1,
"lwt_be_getEdgeByNode returned %" PRIu64
" edges", numedges);
7999 return containingFace;
8000 }
8001
8002
8003
8004
8007 lwerror(
"error computing azimuth of query point [%.15g %.15g,%.15g %.15g]",
8008 closestPointOnEdge->
x, closestPointOnEdge->
y,
8009 queryPoint->
x, queryPoint->
y);
8011 return -1;
8012 }
8013
8015
8017 if ( ! found ) {
8018 lwerror(
"Unexpected backend return: _lwt_FindAdjacentEdges(%"
8020 ") found no edges when we previously found edge %"
8022 closestNode, closestEdge->
edge_id);
8024 return -1;
8025 }
8026
8029
8030 }
8031
8032 LWDEBUG(1,
"Closest point is NOT a node");
8033
8034
8035
8037 {
8039 " on both sides", closestEdge->
face_left);
8040
8041 containingFace = closestEdge->
face_left;
8043 return containingFace;
8044 }
8045
8046 if ( dist == 0 )
8047 {
8048
8050 lwerror(
"Two or more faces found");
8051 return -1;
8052 }
8053
8054
8056 {
8057
8058 LWDEBUGF(1,
"Closest point is vertex %d of closest segment", closestPointVertex);
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069 uint32_t prevVertexIndex = closestPointVertex > 0 ?
8070 closestPointVertex - 1u :
8072
8075 prevVertexIndex
8076 );
8077
8078 LWDEBUGF(1,
"Previous vertex %u is POINT(%.15g %.15g)",
8079 prevVertexIndex,
8082 );
8083
8084 uint32_t nextVertexIndex = closestPointVertex == closestEdge->
geom->
points->
npoints - 1u ?
8085 1u :
8086 closestPointVertex + 1u;
8087
8090 nextVertexIndex
8091 );
8092
8093 LWDEBUGF(1,
"Next vertex %u is POINT(%.15g %.15g)",
8094 nextVertexIndex,
8097 );
8098
8099
8100 double azS0;
8101 double azS1;
8102 double azSL;
8103
8104 if ( !
azimuth_pt_pt(closestPointOnEdge, prevVertex, &azS0)) {
8105 lwerror(
"error computing azimuth of segment to closest point [%.15g %.15g,%.15g %.15g]",
8106 closestPointOnEdge->
x, closestPointOnEdge->
y,
8107 prevVertex->
x, prevVertex->
y);
8109 return -1;
8110 }
8111 if ( !
azimuth_pt_pt(closestPointOnEdge, nextVertex, &azS1)) {
8112 lwerror(
"error computing azimuth of segment from closest point [%.15g %.15g,%.15g %.15g]",
8113 closestPointOnEdge->
x, closestPointOnEdge->
y,
8114 nextVertex->
x, nextVertex->
y);
8116 return -1;
8117 }
8118 if ( !
azimuth_pt_pt(closestPointOnEdge, queryPoint, &azSL) ) {
8119 lwerror(
"error computing azimuth of queryPoint [%.15g %.15g,%.15g %.15g]",
8120 closestPointOnEdge->
x, closestPointOnEdge->
y,
8121 queryPoint->
x, queryPoint->
y);
8123 return -1;
8124 }
8125
8126 double angle_S0_S1 = azS1 - azS0;
8127 if ( angle_S0_S1 < 0 ) angle_S0_S1 += 2 * M_PI;
8128
8129 double angle_S0_SL = azSL - azS0;
8130 if ( angle_S0_SL < 0 ) angle_S0_SL += 2 * M_PI;
8131
8132 LWDEBUGF(1,
"Azimuths from closest (vertex) point: P:%g, N:%g (+%g), Q:%g (+%g)",
8133 azS0,
8134 azS1, angle_S0_S1,
8135 azSL, angle_S0_SL
8136 );
8137 if ( angle_S0_SL < angle_S0_S1 )
8138 {
8139
8140 containingFace = closestEdge->
face_left;
8141 }
8142 else
8143 {
8144
8146 }
8147 }
8148 else
8149 {
8150
8151
8152
8153 LWDEBUGF(1,
"Closest point is internal to closest segment, calling lw_segment_side((%g,%g),(%g,%g),(%g,%g)",
8154 closestSegmentP0->
x,
8155 closestSegmentP0->
y,
8156 closestSegmentP1->
x,
8157 closestSegmentP1->
y,
8160 );
8161
8162 closestSegmentSide =
lw_segment_side(closestSegmentP0, closestSegmentP1, queryPoint);
8163 LWDEBUGF(1,
"Side of closest segment query point falls on: %d (%s)",
8164 closestSegmentSide, closestSegmentSide == -1 ? "left" : closestSegmentSide == 1 ? "right" : "collinear" );
8165
8166 if ( closestSegmentSide == -1 )
8167 {
8168 containingFace = closestEdge->
face_left;
8169 }
8170 else if ( closestSegmentSide == 1 )
8171 {
8173 }
8174 else
8175 {
8176 lwerror(
"Unexpected collinearity reported from lw_segment_side");
8178 return -1;
8179 }
8180
8181 }
8182
8184 return containingFace;
8185}
int ptarray_closest_segment_2d(const POINTARRAY *pa, const POINT2D *qp, double *dist)
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
#define LWT_COL_EDGE_FACE_RIGHT
LWT_INT64 LWT_ELEMID
Identifier of topology element.
#define LWT_COL_EDGE_START_NODE
#define LWT_COL_EDGE_FACE_LEFT
#define LWT_COL_EDGE_EDGE_ID
Edge fields.
#define LWT_COL_EDGE_END_NODE
#define LWT_COL_EDGE_GEOM
#define PGTOPO_BE_ERROR()
#define LWDEBUG(level, msg)
#define LWDEBUGF(level, msg,...)
#define LWDEBUGGF(level, geom, fmt,...)
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static LWT_ISO_EDGE * lwt_be_getClosestEdge(const LWT_TOPOLOGY *topo, const LWPOINT *pt, uint64_t *numelems, int fields)
void _lwt_release_edges(LWT_ISO_EDGE *edges, int num_edges)
LWT_ISO_EDGE * lwt_be_getEdgeByNode(LWT_TOPOLOGY *topo, const LWT_ELEMID *ids, uint64_t *numelems, int fields)
static int _lwt_FindAdjacentEdges(LWT_TOPOLOGY *topo, LWT_ELEMID node, edgeend *data, edgeend *other, LWT_ELEMID myedge_id)
static const POINT2D * getPoint2d_cp(const POINTARRAY *pa, uint32_t n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from.