PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches

◆ ptarrayarc_contains_point_partial()

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

Definition at line 845 of file ptarray.c.

846{
847 int wn = 0;
848 uint32_t i;
849 int side;
850 const POINT2D *seg1;
851 const POINT2D *seg2;
852 const POINT2D *seg3;
853 GBOX gbox;
854
855 /* Check for not an arc ring (always have odd # of points) */
856 if ( (pa->npoints % 2) == 0 )
857 {
858 lwerror("ptarrayarc_contains_point called with even number of points");
859 return LW_OUTSIDE;
860 }
861
862 /* Check for not an arc ring (always have >= 3 points) */
863 if ( pa->npoints < 3 )
864 {
865 lwerror("ptarrayarc_contains_point called too-short pointarray");
866 return LW_OUTSIDE;
867 }
868
869 /* Check for unclosed case */
870 seg1 = getPoint2d_cp(pa, 0);
871 seg3 = getPoint2d_cp(pa, pa->npoints-1);
872 if ( check_closed && ! p2d_same(seg1, seg3) )
873 {
874 lwerror("ptarrayarc_contains_point called on unclosed ring");
875 return LW_OUTSIDE;
876 }
877 /* OK, it's closed. Is it just one circle? */
878 else if ( p2d_same(seg1, seg3) && pa->npoints == 3 )
879 {
880 double radius, d;
881 POINT2D c;
882 seg2 = getPoint2d_cp(pa, 1);
883
884 /* Wait, it's just a point, so it can't contain anything */
885 if ( lw_arc_is_pt(seg1, seg2, seg3) )
886 return LW_OUTSIDE;
887
888 /* See if the point is within the circle radius */
889 radius = lw_arc_center(seg1, seg2, seg3, &c);
890 d = distance2d_pt_pt(pt, &c);
891 if ( FP_EQUALS(d, radius) )
892 return LW_BOUNDARY; /* Boundary of circle */
893 else if ( d < radius )
894 return LW_INSIDE; /* Inside circle */
895 else
896 return LW_OUTSIDE; /* Outside circle */
897 }
898 else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) )
899 {
900 return LW_BOUNDARY; /* Boundary case */
901 }
902
903 /* Start on the ring */
904 seg1 = getPoint2d_cp(pa, 0);
905 for ( i=1; i < pa->npoints; i += 2 )
906 {
907 seg2 = getPoint2d_cp(pa, i);
908 seg3 = getPoint2d_cp(pa, i+1);
909
910 /* Catch an easy boundary case */
911 if( p2d_same(seg3, pt) )
912 return LW_BOUNDARY;
913
914 /* Skip arcs that have no size */
915 if ( lw_arc_is_pt(seg1, seg2, seg3) )
916 {
917 seg1 = seg3;
918 continue;
919 }
920
921 /* Only test segments in our vertical range */
922 lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox);
923 if ( pt->y > gbox.ymax || pt->y < gbox.ymin )
924 {
925 seg1 = seg3;
926 continue;
927 }
928
929 /* Outside of horizontal range, and not between end points we also skip */
930 if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) &&
931 (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) )
932 {
933 seg1 = seg3;
934 continue;
935 }
936
937 side = lw_arc_side(seg1, seg2, seg3, pt);
938
939 /* On the boundary */
940 if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) )
941 {
942 return LW_BOUNDARY;
943 }
944
945 /* Going "up"! Point to left of arc. */
946 if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) )
947 {
948 wn++;
949 }
950
951 /* Going "down"! */
952 if ( side > 0 && (seg3->y <= pt->y) && (pt->y < seg1->y) )
953 {
954 wn--;
955 }
956
957 /* Inside the arc! */
958 if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin )
959 {
960 POINT2D C;
961 double radius = lw_arc_center(seg1, seg2, seg3, &C);
962 double d = distance2d_pt_pt(pt, &C);
963
964 /* On the boundary! */
965 if ( d == radius )
966 return LW_BOUNDARY;
967
968 /* Within the arc! */
969 if ( d < radius )
970 {
971 /* Left side, increment winding number */
972 if ( side < 0 )
973 wn++;
974 /* Right side, decrement winding number */
975 if ( side > 0 )
976 wn--;
977 }
978 }
979
980 seg1 = seg3;
981 }
982
983 /* Sent out the winding number for calls that are building on this as a primitive */
984 if ( winding_number )
985 *winding_number = wn;
986
987 /* Outside */
988 if (wn == 0)
989 {
990 return LW_OUTSIDE;
991 }
992
993 /* Inside */
994 return LW_INSIDE;
995}
int lw_arc_calculate_gbox_cartesian_2d(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, GBOX *gbox)
Definition gbox.c:453
double distance2d_pt_pt(const POINT2D *p1, const POINT2D *p2)
Definition measures.c:2397
#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.
int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
#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) .
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
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:91
double ymax
Definition liblwgeom.h:343
double xmax
Definition liblwgeom.h:341
double ymin
Definition liblwgeom.h:342
double xmin
Definition liblwgeom.h:340
double y
Definition liblwgeom.h:376
double x
Definition liblwgeom.h:376
uint32_t npoints
Definition liblwgeom.h:413

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: