Beispiel #1
0
        /// <summary>
        /// Whether the winding order of a given loop is clockwise, with normalization
        /// for loops crossing the antimeridian.
        /// </summary>
        /// <param name="loop">The loop to check</param>
        /// <param name="isTransmeridian">Whether the loop crosses the antimeridian</param>
        /// <returns>Whether the loop is clockwise</returns>
        /// <!-- Based off 3.1.1 -->
        public static bool isClockwiseNormalizedGeofence(Geofence loop, bool isTransmeridian)
        {
            double   sum = 0;
            GeoCoord a;
            GeoCoord b;

            int loopIndex = -1;

            while (true)
            {
                if (++loopIndex >= loop.numVerts)
                {
                    break;
                }
                a = new GeoCoord(loop.verts[loopIndex].lat, loop.verts[loopIndex].lon);
                b = new GeoCoord
                    (
                    loop.verts[(loopIndex + 1) % loop.numVerts].lat,
                    loop.verts[(loopIndex + 1) % loop.numVerts].lon
                    );


                // If we identify a transmeridian arc (> 180 degrees longitude),
                // start over with the transmeridian flag set
                if (!isTransmeridian && Math.Abs(a.lon - b.lon) > Constants.M_PI)
                {
                    return(isClockwiseNormalizedGeofence(loop, true));
                }
                sum += (NORMALIZE_LON(b.lon, isTransmeridian) -
                        NORMALIZE_LON(a.lon, isTransmeridian)) *
                       (b.lat + a.lat);
            }

            return(sum > 0);
        }
Beispiel #2
0
        /// <summary>
        /// Create a bounding box from a simple polygon loop.
        /// Known limitations:
        /// - Does not support polygons with two adjacent points > 180 degrees of
        ///   longitude apart. These will be interpreted as crossing the antimeridian.
        /// - Does not currently support polygons containing a pole.
        /// </summary>
        /// <param name="loop">Loop of coordinates</param>
        /// <param name="bbox">Output bbox</param>
        /// <!-- Based off 3.1.1 -->
        public static void bboxFromGeofence(ref Geofence loop, ref BBox bbox)
        {
            // Early exit if there are no vertices
            if (loop.numVerts == 0)
            {
                bbox = new BBox();
                return;
            }

            bbox.south = Double.MaxValue;
            bbox.west  = Double.MaxValue;
            bbox.north = -Double.MaxValue;
            bbox.east  = -Double.MaxValue;
            double minPosLon       = Double.MaxValue;
            double maxNegLon       = -Double.MaxValue;
            bool   isTransmeridian = false;

            double   lat;
            double   lon;
            GeoCoord coord;
            GeoCoord next;

            int loopIndex = -1;

            while (true)
            {
                if (++loopIndex >= loop.numVerts)
                {
                    break;
                }

                coord = new GeoCoord(loop.verts[loopIndex].lat, loop.verts[loopIndex].lon);
                next  = new GeoCoord
                        (
                    loop.verts[(loopIndex + 1) % loop.numVerts].lat,
                    loop.verts[(loopIndex + 1) % loop.numVerts].lon
                        );



                lat = coord.lat;
                lon = coord.lon;
                if (lat < bbox.south)
                {
                    bbox.south = lat;
                }
                if (lon < bbox.west)
                {
                    bbox.west = lon;
                }
                if (lat > bbox.north)
                {
                    bbox.north = lat;
                }
                if (lon > bbox.east)
                {
                    bbox.east = lon;
                }
                // Save the min positive and max negative longitude for
                // use in the transmeridian case
                if (lon > 0 && lon < minPosLon)
                {
                    minPosLon = lon;
                }
                if (lon < 0 && lon > maxNegLon)
                {
                    maxNegLon = lon;
                }
                // check for arcs > 180 degrees longitude, flagging as transmeridian
                if (Math.Abs(lon - next.lon) > Constants.M_PI)
                {
                    isTransmeridian = true;
                }
            }
            // Swap east and west if transmeridian
            if (isTransmeridian)
            {
                bbox.east = maxNegLon;
                bbox.west = minPosLon;
            }
        }
Beispiel #3
0
 /// <summary>
 /// Whether the winding order of a given loop is clockwise. In GeoJSON,
 /// clockwise loops are always inner loops (holes).
 /// </summary>
 /// <param name="loop">The loop to check</param>
 /// <returns>Whether the loop is clockwise</returns>
 /// <!-- Based off 3.1.1 -->
 public static bool isClockwiseGeofence(Geofence loop)
 {
     return(isClockwiseNormalizedGeofence(loop, false));
 }
Beispiel #4
0
        /// <summary>
        /// pointInside is the core loop of the point-in-poly algorithm
        /// </summary>
        /// <param name="loop">The loop to check</param>
        /// <param name="bbox">The bbox for the loop being tested</param>
        /// <param name="coord">The coordinate to check</param>
        /// <returns>Whether the point is contained</returns>
        /// <!-- Based off 3.1.1 -->
        public static bool pointInsideGeofence(ref Geofence loop, ref BBox bbox, ref GeoCoord coord)
        {
            // fail fast if we're outside the bounding box
            if (!BBox.bboxContains(bbox, coord))
            {
                return(false);
            }
            bool isTransmeridian = BBox.bboxIsTransmeridian(bbox);
            bool contains        = false;

            double lat = coord.lat;
            double lng = NORMALIZE_LON(coord.lon, isTransmeridian);

            GeoCoord a;
            GeoCoord b;

            int loopIndex = -1;

            while (true)
            {
                if (++loopIndex >= loop.numVerts)
                {
                    break;
                }
                a = new GeoCoord(loop.verts[loopIndex].lat, loop.verts[loopIndex].lon);
                b = new GeoCoord
                    (
                    loop.verts[(loopIndex + 1) % loop.numVerts].lat,
                    loop.verts[(loopIndex + 1) % loop.numVerts].lon
                    );


                //b = loop.verts[(loopIndex + 1) % loop.numVerts];

                // Ray casting algo requires the second point to always be higher
                // than the first, so swap if needed
                if (a.lat > b.lat)
                {
                    GeoCoord tmp = a;
                    a = b;
                    b = tmp;
                }

                // If we're totally above or below the latitude ranges, the test
                // ray cannot intersect the line segment, so let's move on
                if (lat < a.lat || lat > b.lat)
                {
                    continue;
                }

                double aLng = NORMALIZE_LON(a.lon, isTransmeridian);
                double bLng = NORMALIZE_LON(b.lon, isTransmeridian);

                // Rays are cast in the longitudinal direction, in case a point
                // exactly matches, to decide tiebreakers, bias westerly
                if (Math.Abs(aLng - lng) < Constants.DBL_EPSILON || Math.Abs(bLng - lng) < Constants.DBL_EPSILON)
                {
                    lng -= Constants.DBL_EPSILON;
                }

                // For the latitude of the point, compute the longitude of the
                // point that lies on the line segment defined by a and b
                // This is done by computing the percent above a the lat is,
                // and traversing the same percent in the longitudinal direction
                // of a to b
                double ratio   = (lat - a.lat) / (b.lat - a.lat);
                double testLng =
                    NORMALIZE_LON(aLng + (bLng - aLng) * ratio, isTransmeridian);

                // Intersection of the ray
                if (testLng > lng)
                {
                    contains = !contains;
                }
            }

            return(contains);
        }
Beispiel #5
0
 /// <summary>
 /// Create a bounding box from a Geofence
 /// </summary>
 /// <param name="Geofence">Input <see cref="Geofence"/></param>
 /// <param name="bbox">Output bbox</param>
 /// <!-- Based off 3.1.1 -->
 public static void bboxFromGeofence(Geofence Geofence, ref BBox bbox)
 {
     bboxFromVertices(Geofence.verts.ToList(), Geofence.numVerts, ref bbox);
 }