PostGIS  3.2.2dev-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 1125 of file ptarray.c.

1126 {
1127  int wn = 0;
1128  uint32_t i;
1129  int side;
1130  const POINT2D *seg1;
1131  const POINT2D *seg2;
1132  const POINT2D *seg3;
1133  GBOX gbox;
1134 
1135  /* Check for not an arc ring (always have odd # of points) */
1136  if ( (pa->npoints % 2) == 0 )
1137  {
1138  lwerror("ptarrayarc_contains_point called with even number of points");
1139  return LW_OUTSIDE;
1140  }
1141 
1142  /* Check for not an arc ring (always have >= 3 points) */
1143  if ( pa->npoints < 3 )
1144  {
1145  lwerror("ptarrayarc_contains_point called too-short pointarray");
1146  return LW_OUTSIDE;
1147  }
1148 
1149  /* Check for unclosed case */
1150  seg1 = getPoint2d_cp(pa, 0);
1151  seg3 = getPoint2d_cp(pa, pa->npoints-1);
1152  if ( check_closed && ! p2d_same(seg1, seg3) )
1153  {
1154  lwerror("ptarrayarc_contains_point called on unclosed ring");
1155  return LW_OUTSIDE;
1156  }
1157  /* OK, it's closed. Is it just one circle? */
1158  else if ( p2d_same(seg1, seg3) && pa->npoints == 3 )
1159  {
1160  double radius, d;
1161  POINT2D c;
1162  seg2 = getPoint2d_cp(pa, 1);
1163 
1164  /* Wait, it's just a point, so it can't contain anything */
1165  if ( lw_arc_is_pt(seg1, seg2, seg3) )
1166  return LW_OUTSIDE;
1167 
1168  /* See if the point is within the circle radius */
1169  radius = lw_arc_center(seg1, seg2, seg3, &c);
1170  d = distance2d_pt_pt(pt, &c);
1171  if ( FP_EQUALS(d, radius) )
1172  return LW_BOUNDARY; /* Boundary of circle */
1173  else if ( d < radius )
1174  return LW_INSIDE; /* Inside circle */
1175  else
1176  return LW_OUTSIDE; /* Outside circle */
1177  }
1178  else if ( p2d_same(seg1, pt) || p2d_same(seg3, pt) )
1179  {
1180  return LW_BOUNDARY; /* Boundary case */
1181  }
1182 
1183  /* Start on the ring */
1184  seg1 = getPoint2d_cp(pa, 0);
1185  for ( i=1; i < pa->npoints; i += 2 )
1186  {
1187  seg2 = getPoint2d_cp(pa, i);
1188  seg3 = getPoint2d_cp(pa, i+1);
1189 
1190  /* Catch an easy boundary case */
1191  if( p2d_same(seg3, pt) )
1192  return LW_BOUNDARY;
1193 
1194  /* Skip arcs that have no size */
1195  if ( lw_arc_is_pt(seg1, seg2, seg3) )
1196  {
1197  seg1 = seg3;
1198  continue;
1199  }
1200 
1201  /* Only test segments in our vertical range */
1202  lw_arc_calculate_gbox_cartesian_2d(seg1, seg2, seg3, &gbox);
1203  if ( pt->y > gbox.ymax || pt->y < gbox.ymin )
1204  {
1205  seg1 = seg3;
1206  continue;
1207  }
1208 
1209  /* Outside of horizontal range, and not between end points we also skip */
1210  if ( (pt->x > gbox.xmax || pt->x < gbox.xmin) &&
1211  (pt->y > FP_MAX(seg1->y, seg3->y) || pt->y < FP_MIN(seg1->y, seg3->y)) )
1212  {
1213  seg1 = seg3;
1214  continue;
1215  }
1216 
1217  side = lw_arc_side(seg1, seg2, seg3, pt);
1218 
1219  /* On the boundary */
1220  if ( (side == 0) && lw_pt_in_arc(pt, seg1, seg2, seg3) )
1221  {
1222  return LW_BOUNDARY;
1223  }
1224 
1225  /* Going "up"! Point to left of arc. */
1226  if ( side < 0 && (seg1->y <= pt->y) && (pt->y < seg3->y) )
1227  {
1228  wn++;
1229  }
1230 
1231  /* Going "down"! */
1232  if ( side > 0 && (seg3->y <= pt->y) && (pt->y < seg1->y) )
1233  {
1234  wn--;
1235  }
1236 
1237  /* Inside the arc! */
1238  if ( pt->x <= gbox.xmax && pt->x >= gbox.xmin )
1239  {
1240  POINT2D C;
1241  double radius = lw_arc_center(seg1, seg2, seg3, &C);
1242  double d = distance2d_pt_pt(pt, &C);
1243 
1244  /* On the boundary! */
1245  if ( d == radius )
1246  return LW_BOUNDARY;
1247 
1248  /* Within the arc! */
1249  if ( d < radius )
1250  {
1251  /* Left side, increment winding number */
1252  if ( side < 0 )
1253  wn++;
1254  /* Right side, decrement winding number */
1255  if ( side > 0 )
1256  wn--;
1257  }
1258  }
1259 
1260  seg1 = seg3;
1261  }
1262 
1263  /* Sent out the winding number for calls that are building on this as a primitive */
1264  if ( winding_number )
1265  *winding_number = wn;
1266 
1267  /* Outside */
1268  if (wn == 0)
1269  {
1270  return LW_OUTSIDE;
1271  }
1272 
1273  /* Inside */
1274  return LW_INSIDE;
1275 }
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:2306
#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:237
int lw_arc_side(const POINT2D *A1, const POINT2D *A2, const POINT2D *A3, const POINT2D *Q)
Definition: lwalgorithm.c:187
#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:114
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:84
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 ymax
Definition: liblwgeom.h:371
double xmax
Definition: liblwgeom.h:369
double ymin
Definition: liblwgeom.h:370
double xmin
Definition: liblwgeom.h:368
double y
Definition: liblwgeom.h:404
double x
Definition: liblwgeom.h:404
uint32_t npoints
Definition: liblwgeom.h:441

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.

Here is the call graph for this function: