Пример #1
0
 public void Clear()
 {
     if (Next == null)
     {
         return;
     }
     Next.Clear();
     Next = null;
 }
Пример #2
0
 public LinkedGeoCoord(Code.LinkedGeo.LinkedGeoCoord codeLinkedGeoCoord)
 {
     Vertex = new GeoCoord {
         Latitude = codeLinkedGeoCoord.vertex.lat, Longitude = codeLinkedGeoCoord.vertex.lon
     };
     if (codeLinkedGeoCoord.next != null)
     {
         Next = new LinkedGeoCoord(codeLinkedGeoCoord.next);
     }
 }
Пример #3
0
        /// <summary>
        /// Count the number of coordinates in a loop
        /// </summary>
        /// <param name="loop"> Loop to count coordinates for</param>
        /// <returns>Count</returns>
        /// <!-- Based off 3.1.1 -->
        public static int countLinkedCoords(ref LinkedGeoLoop loop)
        {
            LinkedGeoCoord coord = loop.first;
            int            count = 0;

            while (coord != null)
            {
                count++;
                coord = coord.next;
            }
            return(count);
        }
Пример #4
0
        /// <summary>
        /// Free all allocated memory for a linked geo loop. The caller is
        /// responsible for freeing memory allocated to input loop struct.
        /// </summary>
        /// <param name="loop">Loop to free</param>
        /// <!-- Based off 3.1.1 -->
        public static void destroyLinkedGeoLoop(ref LinkedGeoLoop loop)
        {
            LinkedGeoCoord nextCoord;

            for (LinkedGeoCoord currentCoord = loop.first; currentCoord != null;
                 currentCoord = nextCoord)
            {
                nextCoord = currentCoord.next;
                // ReSharper disable once RedundantAssignment
                currentCoord = null;
            }
        }
Пример #5
0
 public LinkedGeoLoop(Code.LinkedGeo.LinkedGeoLoop codeLinkedGeoLoop)
 {
     if (codeLinkedGeoLoop.first != null)
     {
         First = new LinkedGeoCoord(codeLinkedGeoLoop.first);
     }
     if (codeLinkedGeoLoop.last != null)
     {
         Last = new LinkedGeoCoord(codeLinkedGeoLoop.last);
     }
     if (codeLinkedGeoLoop.next != null)
     {
         Next = new LinkedGeoLoop(codeLinkedGeoLoop.next);
     }
 }
Пример #6
0
            public void Clear()
            {
                if (First != null)
                {
                    First.Clear();
                    First = null;
                }

                if (Last != null)
                {
                    Last.Clear();
                    Last = null;
                }

                if (Next != null)
                {
                    Next.Clear();
                    Next = null;
                }
            }
Пример #7
0
        /// <summary>
        /// Whether the winding order of a given LinkedGeoLoop is clockwise
        /// </summary>
        /// <param name="loop">The loop to check</param>
        /// <returns>Whether the loop is clockwise</returns>
        /// <!-- Based off 3.1.1 -->
        static bool isClockwiseNormalizedLinkedGeoLoop(LinkedGeoLoop loop, bool isTransmeridian)
        {
            double   sum = 0;
            GeoCoord a;
            GeoCoord b;

            LinkedGeoCoord currentCoord = null;
            LinkedGeoCoord nextCoord    = null;

            while (true)
            {
                currentCoord = currentCoord == null
                                   ? loop.first
                                   : currentCoord.next;
                if (currentCoord == null)
                {
                    break;
                }

                a         = currentCoord.vertex;
                nextCoord = currentCoord.next == null
                                ? loop.first
                                : currentCoord.next;
                b = nextCoord.vertex;
                // 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(isClockwiseNormalizedLinkedGeoLoop(loop, true));
                }
                sum += ((NORMALIZE_LON(b.lon, isTransmeridian) -
                         NORMALIZE_LON(a.lon, isTransmeridian)) *
                        (b.lat + a.lat));
            }

            return(sum > 0);
        }
Пример #8
0
        /// <summary>
        /// Add a new linked coordinate to the current loop
        /// </summary>
        /// <param name="loop">Loop to add coordinate to</param>
        /// <param name="vertex">Coordinate to add</param>
        /// <returns>Pointer to the coordinate</returns>
        /// <!-- Based off 3.1.1 -->
        public static LinkedGeoCoord addLinkedCoord(ref LinkedGeoLoop loop, ref GeoCoord vertex)
        {
            LinkedGeoCoord coord = new LinkedGeoCoord();

            coord.vertex = new GeoCoord(vertex.lat, vertex.lon);
            coord.next   = null;

            LinkedGeoCoord last = loop.last;

            if (last == null)
            {
                if (loop.first != null)
                {
                    throw new Exception("assert(loop->first == NULL);");
                }
                loop.first = coord;
            }
            else
            {
                last.next = coord;
            }
            loop.last = coord;
            return(coord);
        }
Пример #9
0
        /// <summary>
        /// Take a given LinkedGeoLoop data structure and check if it
        /// contains a given geo coordinate.
        /// </summary>
        /// <param name="loop">The linked loop</param>
        /// <param name="bbox">The bbox for the loop</param>
        /// <param name="coord">The coordinate to check</param>
        /// <returns>Whether the point is contained</returns>
        /// <!-- Based off 3.1.1 -->
        public static bool pointInsideLinkedGeoLoop(ref LinkedGeoLoop 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;
            LinkedGeoCoord currentCoord = null;
            LinkedGeoCoord nextCoord    = null;


            while (true)
            {
                currentCoord = currentCoord == null ? loop.first : currentCoord.next;
                if (currentCoord == null)
                {
                    break;
                }

                a         = currentCoord.vertex;
                nextCoord = currentCoord.next == null ? loop.first : currentCoord.next;
                b         = nextCoord.vertex;

                // 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 = new GeoCoord(a.lat, a.lon);
                    a = new GeoCoord(b.lat, b.lon);
                    b = new GeoCoord(tmp.lat, tmp.lon);
                }

                // 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.EPSILON || Math.Abs(bLng - lng) < Constants.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);
        }
Пример #10
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">bbox</param>
        /// <!-- Based off 3.1.1 -->
        public static void bboxFromLinkedGeoLoop(ref LinkedGeoLoop loop, ref BBox bbox)
        {
            // Early exit if there are no vertices
            if (loop.first == null)
            {
                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;

            LinkedGeoCoord currentCoord = null;
            LinkedGeoCoord nextCoord    = null;

            while (true)
            {
                currentCoord = currentCoord == null ? loop.first : currentCoord.next;
                if (currentCoord == null)
                {
                    break;
                }

                coord     = currentCoord.vertex;
                nextCoord = currentCoord.next == null ? loop.first : currentCoord.next;
                next      = nextCoord.vertex;


                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;
            }
        }