PostGIS  3.7.0dev-r@@SVN_REVISION@@

◆ ptarrayarc_contains_point_partial()

int ptarrayarc_contains_point_partial ( const POINTARRAY pa,
const POINT2D pt,
int  check_closed,
int *  winding_number 
)

Definition at line 862 of file ptarray.c.

863 {
864  int wn = 0;
865  uint32_t i;
866  int side;
867  const POINT2D *seg1;
868  const POINT2D *seg2;
869  const POINT2D *seg3;
870  GBOX gbox;
871 
872  /* Check for not an arc ring (always have odd # of points) */
873  if ( (pa->npoints % 2) == 0 )
874  {
875  lwerror("ptarrayarc_contains_point called with even number of points");
876  return LW_OUTSIDE;
877  }
878 
879  /* Check for not an arc ring (always have >= 3 points) */
880  if ( pa->npoints < 3 )
881  {
882  lwerror("ptarrayarc_contains_point called too-short pointarray");
883  return LW_OUTSIDE;
884  }
885 
886  /* Check for unclosed case */
887  seg1 = getPoint2d_cp(pa, 0);
888  seg3 = getPoint2d_cp(pa, pa->npoints-1);
889  if ( check_closed && ! p2d_same(seg1, seg3) )
890  {
891  lwerror("ptarrayarc_contains_point called on unclosed ring");
892  return LW_OUTSIDE;
893  }
894  /* OK, it's closed. Is it just one circle? */
895  else if ( p2d_same(seg1, seg3) && pa->npoints == 3 )
896  {
897  double radius, d;
898  POINT2D c;
899  seg2 = getPoint2d_cp(pa, 1);
900 
901  /* Wait, it's just a point, so it can't contain anything */
902  if ( lw_arc_is_pt(seg1, seg2, seg3) )
903  return LW_OUTSIDE;
904 
905  /* See if the point is within the circle radius */
906  radius = lw_arc_center(seg1, seg2, seg3, &c);
907  d = distance2d_pt_pt(pt, &c);
908  if ( FP_EQUALS(d, radius) )
909  return LW_BOUNDARY; /* Boundary of circle */
910  else if ( d < radius )
911  return LW_INSIDE; /* Inside circle */
912  else
913  return LW_OUTSIDE; /* Outside circle */
914  }
915  else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) )
916  {
917  return LW_BOUNDARY; /* Boundary case */
918  }
919 
920  /* Start on the ring */
921  seg1 = getPoint2d_cp(pa, 0);
922  for ( i=1; i < pa->npoints; i += 2 )
923  {
924  seg2 = getPoint2d_cp(pa, i);
925  seg3 = getPoint2d_cp(pa, i+1);
926 
927  /* Catch an easy boundary case */
928  if( p2d_same(seg3, pt) )
929  return LW_BOUNDARY;
930 
931  /* Skip arcs that have no size */
932  if ( lw_arc_is_pt(seg1, seg2, seg3) )
933  {
934  seg1 = seg3;
935  continue;
936  }
937 
938  /* Only test segments in our vertical range */
939  lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox);
940  if ( pt->y > gbox.ymax || pt->y < gbox.ymin )
941  {
942  seg1 = seg3;
943  continue;
944  }
945 
946  /* Outside of horizontal range, and not between end points we also skip */
947  if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) &&
948  (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) )
949  {
950  seg1 = seg3;
951  continue;
952  }
953 
954  side = lw_arc_side(seg1, seg2, seg3, pt);
955 
956  /* On the boundary */
957  if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) )
958  {
959  return LW_BOUNDARY;
960  }
961 
962  /* Going "up"! Point to left of arc. */
963  if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) )
964  {
965  wn++;
966  }
967 
968  /* Going "down"! */
969  if ( side > 0 && (seg3->y <= pt->y) && (pt->y < seg1->y) )
970  {
971  wn--;
972  }
973 
974  /* Inside the arc! */
975  if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin )
976  {
977  POINT2D C;
978  double radius = lw_arc_center(seg1, seg2, seg3, &C);
979  double d = distance2d_pt_pt(pt, &C);
980 
981  /* On the boundary! */
982  if ( d == radius )
983  return LW_BOUNDARY;
984 
985  /* Within the arc! */
986  if ( d < radius )
987  {
988  /* Left side, increment winding number */
989  if ( side < 0 )
990  wn++;
991  /* Right side, decrement winding number */
992  if ( side > 0 )
993  wn--;
994  }
995  }
996 
997  seg1 = seg3;
998  }
999 
1000  /* Sent out the winding number for calls that are building on this as a primitive */
1001  if ( winding_number )
1002  *winding_number = wn;
1003 
1004  /* Outside */
1005  if (wn == 0)
1006  {
1007  return LW_OUTSIDE;
1008  }
1009 
1010  /* Inside */
1011  return LW_INSIDE;
1012 }
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
Definition: gbox.c:465
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition: measures.c:2445
#define LW_INSIDE
Constants for point-in-polygon return values.
#define LW_BOUNDARY
#define FP_MAX(A, B)
#define FP_MIN(A, B)
double lw_arc_center(const POINT2D *p1, const POINT2D *p2, const POINT2D *p3, POINT2D *result)
Determines the center of the circle defined by the three given points.
Definition: lwalgorithm.c:234
int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
Definition: lwalgorithm.c:184
#define FP_EQUALS(A, B)
#define LW_OUTSIDE
int lw_arc_is_pt(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if arc A is actually a point (all vertices are the same) .
Definition: lwalgorithm.c:111
int lw_pt_in_arc(const POINT2D *P, const POINT2D *A1, const POINT2D *A2, const POINT2D *A3)
Returns true if P is on the same side of the plane partition defined by A1/A3 as A2 is.
Definition: lwalgorithm.c:91
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:57
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
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
double ymax
Definition: liblwgeom.h:357
double xmax
Definition: liblwgeom.h:355
double ymin
Definition: liblwgeom.h:356
double xmin
Definition: liblwgeom.h:354
double y
Definition: liblwgeom.h:390
double x
Definition: liblwgeom.h:390
uint32_t npoints
Definition: liblwgeom.h:427

References distance2d_pt_pt(), FP_EQUALS, FP_MAX, FP_MIN, getPoint2d_cp(), lw_arc_calculate_gbox_cartesian_2d(), lw_arc_center(), lw_arc_is_pt(), lw_arc_side(), LW_BOUNDARY, LW_INSIDE, LW_OUTSIDE, lw_pt_in_arc(), lwerror(), POINTARRAY::npoints, p2d_same(), POINT2D::x, GBOX::xmax, GBOX::xmin, POINT2D::y, GBOX::ymax, and GBOX::ymin.

Referenced by lwcompound_contains_point(), and ptarrayarc_contains_point().

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