PostGIS  2.1.10dev-r@@SVN_REVISION@@
int ptarrayarc_contains_point_partial ( const POINTARRAY pa,
const POINT2D pt,
int  check_closed,
int *  winding_number 
)

Definition at line 802 of file ptarray.c.

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().

803 {
804  int wn = 0;
805  int i, side;
806  const POINT2D *seg1;
807  const POINT2D *seg2;
808  const POINT2D *seg3;
809  GBOX gbox;
810 
811  /* Check for not an arc ring (always have odd # of points) */
812  if ( (pa->npoints % 2) == 0 )
813  {
814  lwerror("ptarrayarc_contains_point called with even number of points");
815  return LW_OUTSIDE;
816  }
817 
818  /* Check for not an arc ring (always have >= 3 points) */
819  if ( pa->npoints < 3 )
820  {
821  lwerror("ptarrayarc_contains_point called too-short pointarray");
822  return LW_OUTSIDE;
823  }
824 
825  /* Check for unclosed case */
826  seg1 = getPoint2d_cp(pa, 0);
827  seg3 = getPoint2d_cp(pa, pa->npoints-1);
828  if ( check_closed && ! p2d_same(seg1, seg3) )
829  {
830  lwerror("ptarrayarc_contains_point called on unclosed ring");
831  return LW_OUTSIDE;
832  }
833  /* OK, it's closed. Is it just one circle? */
834  else if ( p2d_same(seg1, seg3) && pa->npoints == 3 )
835  {
836  double radius, d;
837  POINT2D c;
838  seg2 = getPoint2d_cp(pa, 1);
839 
840  /* Wait, it's just a point, so it can't contain anything */
841  if ( lw_arc_is_pt(seg1, seg2, seg3) )
842  return LW_OUTSIDE;
843 
844  /* See if the point is within the circle radius */
845  radius = lw_arc_center(seg1, seg2, seg3, &c);
846  d = distance2d_pt_pt(pt, &c);
847  if ( FP_EQUALS(d, radius) )
848  return LW_BOUNDARY; /* Boundary of circle */
849  else if ( d < radius )
850  return LW_INSIDE; /* Inside circle */
851  else
852  return LW_OUTSIDE; /* Outside circle */
853  }
854  else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) )
855  {
856  return LW_BOUNDARY; /* Boundary case */
857  }
858 
859  /* Start on the ring */
860  seg1 = getPoint2d_cp(pa, 0);
861  for ( i=1; i < pa->npoints; i += 2 )
862  {
863  seg2 = getPoint2d_cp(pa, i);
864  seg3 = getPoint2d_cp(pa, i+1);
865 
866  /* Catch an easy boundary case */
867  if( p2d_same(seg3, pt) )
868  return LW_BOUNDARY;
869 
870  /* Skip arcs that have no size */
871  if ( lw_arc_is_pt(seg1, seg2, seg3) )
872  {
873  seg1 = seg3;
874  continue;
875  }
876 
877  /* Only test segments in our vertical range */
878  lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox);
879  if ( pt->y > gbox.ymax || pt->y < gbox.ymin )
880  {
881  seg1 = seg3;
882  continue;
883  }
884 
885  /* Outside of horizontal range, and not between end points we also skip */
886  if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) &&
887  (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) )
888  {
889  seg1 = seg3;
890  continue;
891  }
892 
893  side = lw_arc_side(seg1, seg2, seg3, pt);
894 
895  /* On the boundary */
896  if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) )
897  {
898  return LW_BOUNDARY;
899  }
900 
901  /* Going "up"! Point to left of arc. */
902  if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) )
903  {
904  wn++;
905  }
906 
907  /* Going "down"! */
908  if ( side > 0 && (seg2->y <= pt->y) && (pt->y < seg1->y) )
909  {
910  wn--;
911  }
912 
913  /* Inside the arc! */
914  if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin )
915  {
916  POINT2D C;
917  double radius = lw_arc_center(seg1, seg2, seg3, &C);
918  double d = distance2d_pt_pt(pt, &C);
919 
920  /* On the boundary! */
921  if ( d == radius )
922  return LW_BOUNDARY;
923 
924  /* Within the arc! */
925  if ( d < radius )
926  {
927  /* Left side, increment winding number */
928  if ( side < 0 )
929  wn++;
930  /* Right side, decrement winding number */
931  if ( side > 0 )
932  wn--;
933  }
934  }
935 
936  seg1 = seg3;
937  }
938 
939  /* Sent out the winding number for calls that are building on this as a primitive */
940  if ( winding_number )
941  *winding_number = wn;
942 
943  /* Outside */
944  if (wn == 0)
945  {
946  return LW_OUTSIDE;
947  }
948 
949  /* Inside */
950  return LW_INSIDE;
951 }
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:228
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:106
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
Definition: g_box.c:388
int npoints
Definition: liblwgeom.h:327
double xmax
Definition: liblwgeom.h:249
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
The old function nessecary for ptarray_segmentize2d in ptarray.c.
Definition: measures.c:2123
#define FP_MIN(A, B)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
double x
Definition: liblwgeom.h:284
int p2d_same(const POINT2D *p1, const POINT2D *p2)
Definition: lwalgorithm.c:47
double ymin
Definition: liblwgeom.h:250
double xmin
Definition: liblwgeom.h:248
const POINT2D * getPoint2d_cp(const POINTARRAY *pa, int n)
Returns a POINT2D pointer into the POINTARRAY serialized_ptlist, suitable for reading from...
Definition: lwgeom_api.c:458
#define LW_INSIDE
Constants for point-in-polygon return values.
double ymax
Definition: liblwgeom.h:251
double y
Definition: liblwgeom.h:284
int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
Definition: lwalgorithm.c:179
#define LW_BOUNDARY
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:86
#define FP_EQUALS(A, B)
#define LW_OUTSIDE
#define FP_MAX(A, B)

Here is the call graph for this function:

Here is the caller graph for this function: