static bool IsPointInPolygon(Geo x, Geo center, IList<Geo> poly) { // do this only once and pass it in for the math. // Geo c = Limits.center(poly); // bail out if the point is more than 90 degrees off the // centroid var d = x.DistanceRadians(center); if (d >= (Math.PI / 2)) { return false; } // ray is normal to the great circle from c to x. reusing c to hold ray // info var ray = center.CrossNormalize(x); /* * side is a point on the great circle between c and x. It is used to * choose a direction. */ var side = x.CrossNormalize(ray); var isIn = false; // Why do we need to allocate new Geos? // Geo p1 = new Geo(poly[0]); // Geo p2 = new Geo(poly[0]); var p1 = new Geo(poly[0]); Geo p2; var polySize = poly.Count; for (var i = 1; i < polySize; i++) { p2 = new Geo(poly[i]); /* * p1 and p2 are on different sides of the ray, and the great acircle * between p1 and p2 is on the side that counts; */ if ((p1.Dot(ray) < 0.0) != (p2.Dot(ray) < 0.0) && new GeoSegment(p1, p2).GreatCircleIntersection(ray).Dot(side) > 0.0) { isIn = !isIn; } p1 = new Geo(p2); } // Check for unclosed polygons, if the polygon isn't closed, // do the calculation for the last point to the starting // point. if (!poly[0].Equals(p1)) { p2 = new Geo(poly[0]); if ((p1.Dot(ray) < 0.0) != (p2.Dot(ray) < 0.0) && new GeoSegment(p1, p2).GreatCircleIntersection(ray).Dot(side) > 0.0) { isIn = !isIn; } } return isIn; }
/// <summary> /// Treating the passed in GeoSegments as planar vectors, return the dot product /// </summary> /// <param name="segment1"></param> /// <param name="segment2"></param> /// <returns></returns> public static double Dot(this GeoSegment segment1, GeoSegment segment2) { // Using Geo only for convenience, these are NOT Geos, really! // X is delta longitude, Y is delta latitude, Z is always zero. var vec1 = new Geo(segment1[1].Longitude - segment1[0].Longitude, segment1[1].Latitude - segment1[0].Latitude, 0).Normalized; var vec2 = new Geo(segment2[1].Longitude - segment2[0].Longitude, segment2[1].Latitude - segment2[0].Latitude, 0).Normalized; return vec1.Dot(vec2); }