PostGIS  3.2.2dev-r@@SVN_REVISION@@

◆ ptarray_contains_point()

int ptarray_contains_point ( const POINTARRAY pa,
const POINT2D pt 
)

The following is based on the "Fast Winding Number Inclusion of a Point in a Polygon" algorithm by Dan Sunday.

http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm#Winding%20Number

Return:

  • LW_INSIDE (1) if the point is inside the POINTARRAY
  • LW_BOUNDARY (0) if it is on the boundary.
  • LW_OUTSIDE (-1) if it is outside

Definition at line 746 of file ptarray.c.

747 {
748  const POINT2D *seg1, *seg2;
749  int wn = 0;
750 
751  seg1 = getPoint2d_cp(pa, 0);
752  seg2 = getPoint2d_cp(pa, pa->npoints-1);
753  if (!p2d_same(seg1, seg2))
754  lwerror("ptarray_contains_point called on unclosed ring");
755 
756  for (uint32_t i = 1; i < pa->npoints; i++)
757  {
758  double side, ymin, ymax;
759 
760  seg2 = getPoint2d_cp(pa, i);
761 
762  /* Zero length segments are ignored. */
763  if (p2d_same(seg1, seg2))
764  {
765  seg1 = seg2;
766  continue;
767  }
768 
769  ymin = FP_MIN(seg1->y, seg2->y);
770  ymax = FP_MAX(seg1->y, seg2->y);
771 
772  /* Only test segments in our vertical range */
773  if (pt->y > ymax || pt->y < ymin)
774  {
775  seg1 = seg2;
776  continue;
777  }
778 
779  side = lw_segment_side(seg1, seg2, pt);
780 
781  /*
782  * A point on the boundary of a ring is not contained.
783  * WAS: if (fabs(side) < 1e-12), see #852
784  */
785  if ((side == 0) && lw_pt_in_seg(pt, seg1, seg2))
786  {
787  return LW_BOUNDARY;
788  }
789 
790  /*
791  * If the point is to the left of the line, and it's rising,
792  * then the line is to the right of the point and
793  * circling counter-clockwise, so increment.
794  */
795  if ((side < 0) && (seg1->y <= pt->y) && (pt->y < seg2->y))
796  {
797  wn++;
798  }
799 
800  /*
801  * If the point is to the right of the line, and it's falling,
802  * then the line is to the right of the point and circling
803  * clockwise, so decrement.
804  */
805  else if ( (side > 0) && (seg2->y <= pt->y) && (pt->y < seg1->y) )
806  {
807  wn--;
808  }
809 
810  seg1 = seg2;
811  }
812 
813  /* wn == 0 => Outside, wn != 0 => Inside */
814  return wn == 0 ? LW_OUTSIDE : LW_INSIDE;
815 }
#define LW_INSIDE
Constants for point-in-polygon return values.
#define LW_BOUNDARY
#define FP_MAX(A, B)
#define FP_MIN(A, B)
int lw_pt_in_seg(const POINT2D *P, const POINT2D *A1, const POINT2D *A2)
Returns true if P is between A1/A2.
Definition: lwalgorithm.c:96
#define LW_OUTSIDE
int lw_segment_side(const POINT2D *p1, const POINT2D *p2, const POINT2D *q)
lw_segment_side()
Definition: lwalgorithm.c:63
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:50
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
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:101
double y
Definition: liblwgeom.h:404
uint32_t npoints
Definition: liblwgeom.h:441

References FP_MAX, FP_MIN, getPoint2d_cp(), LW_BOUNDARY, LW_INSIDE, LW_OUTSIDE, lw_pt_in_seg(), lw_segment_side(), lwerror(), POINTARRAY::npoints, p2d_same(), and POINT2D::y.

Referenced by _lwt_AddFaceSplit(), lw_dist2d_line_poly(), lw_dist2d_line_tri(), lw_dist2d_point_poly(), lw_dist2d_point_tri(), lw_dist2d_poly_poly(), lw_dist2d_tri_circstring(), lw_dist2d_tri_poly(), lw_dist2d_tri_tri(), lwgeom_contains_point(), lwgeom_solid_contains_lwgeom(), lwpoly_contains_point(), and test_ptarray_contains_point().

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