/**
         * Creates an empty polygon that should be initialized by calling Init().
         */

        public S2Polygon()
        {
            _loops       = new List <S2Loop>();
            _bound       = S2LatLngRect.Empty;
            _hasHoles    = false;
            _numVertices = 0;
        }
        /**
         * Convenience constructor that calls Init() with the given loops. Clears the
         * given list.
         */

        public S2Polygon(System.Collections.Generic.IList <S2Loop> loops)
        {
            _loops = new List <S2Loop>();
            _bound = S2LatLngRect.Empty;

            Init(loops);
        }
Ejemplo n.º 3
0
        private void InitBound()
        {
            // The bounding rectangle of a loop is not necessarily the same as the
            // bounding rectangle of its vertices. First, the loop may wrap entirely
            // around the sphere (e.g. a loop that defines two revolutions of a
            // candy-cane stripe). Second, the loop may include one or both poles.
            // Note that a small clockwise loop near the equator contains both poles.

            var bounder = new RectBounder();

            for (var i = 0; i <= NumVertices; ++i)
            {
                bounder.AddPoint(Vertex(i));
            }
            var b = bounder.Bound;

            // Note that we need to initialize bound with a temporary value since
            // contains() does a bounding rectangle check before doing anything else.
            _bound = S2LatLngRect.Full;
            if (Contains(new S2Point(0, 0, 1)))
            {
                b = new S2LatLngRect(new R1Interval(b.Lat.Lo, S2.PiOver2), S1Interval.Full);
            }
            // If a loop contains the south pole, then either it wraps entirely
            // around the sphere (full longitude range), or it also contains the
            // north pole in which case b.lng().isFull() due to the test above.

            if (b.Lng.IsFull && Contains(new S2Point(0, 0, -1)))
            {
                b = new S2LatLngRect(new R1Interval(-S2.PiOver2, b.Lat.Hi), b.Lng);
            }
            _bound = b;
        }
        /**
         * Copy constructor.
         */

        public S2Polygon(S2Loop loop)
        {
            _loops       = new List <S2Loop>();
            _bound       = loop.RectBound;
            _hasHoles    = false;
            _numVertices = loop.NumVertices;

            _loops.Add(loop);
        }
        /**
         * Initialize a polygon by taking ownership of the given loops and clearing
         * the given list. This method figures out the loop nesting hierarchy and then
         * reorders the loops by following a preorder traversal. This implies that
         * each loop is immediately followed by its descendants in the nesting
         * hierarchy. (See also getParent and getLastDescendant.)
         */

        public void Init(System.Collections.Generic.IList <S2Loop> loops)
        {
            // assert isValid(loops);
            // assert (this.loops.isEmpty());

            //Dictionary<S2Loop, List<S2Loop>> loopMap =new Dictionary<S2Loop, List<S2Loop>>();
            // Note: We're using C5's HashDictionary because SCG's Dictionary<,> does not allow
            // NULL keys
            var loopMap = new Dictionary <NullObject <S2Loop>, List <S2Loop> >();

            // Yes, a null key is valid. It is used here to refer to the root of the
            // loopMap
            loopMap[null] = new List <S2Loop>();

            foreach (var loop in loops)
            {
                InsertLoop(loop, null, loopMap);
                _numVertices += loop.NumVertices;
            }
            loops.Clear();

            // Sort all of the lists of loops; in this way we guarantee a total ordering
            // on loops in the polygon. Loops will be sorted by their natural ordering,
            // while also preserving the requirement that each loop is immediately
            // followed by its descendants in the nesting hierarchy.
            //
            // TODO(andriy): as per kirilll in CL 18750833 code review comments:
            // This should work for now, but I think it's possible to guarantee the
            // correct order inside insertLoop by searching for the correct position in
            // the children list before inserting.
            SortValueLoops(loopMap);

            // Reorder the loops in depth-first traversal order.
            // Starting at null == starting at the root
            InitLoop(null, -1, loopMap);

            // TODO(dbeaumont): Add tests or preconditions for these asserts (here and elesewhere).
            // forall i != j : containsChild(loop(i), loop(j), loopMap) == loop(i).containsNested(loop(j)));

            // Compute the bounding rectangle of the entire polygon.
            _hasHoles = false;
            _bound    = S2LatLngRect.Empty;
            for (var i = 0; i < NumLoops; ++i)
            {
                if (Loop(i).Sign < 0)
                {
                    _hasHoles = true;
                }
                else
                {
                    _bound = _bound.Union(Loop(i).RectBound);
                }
            }
        }
Ejemplo n.º 6
0
        /**
         * Copy constructor.
         */

        public S2Loop(S2Loop src)
        {
            _numVertices        = src._numVertices;
            _vertices           = (S2Point[])src._vertices.Clone();
            _vertexToIndex      = src._vertexToIndex;
            _index              = src._index;
            _firstLogicalVertex = src._firstLogicalVertex;
            _bound              = src.RectBound;
            _originInside       = src._originInside;
            _depth              = src._depth;
        }
        /**
         * Copy constructor.
         */

        public S2Polygon(S2Polygon src)
        {
            _loops       = new List <S2Loop>();
            _bound       = src.RectBound;
            _hasHoles    = src._hasHoles;
            _numVertices = src._numVertices;

            for (var i = 0; i < src.NumLoops; ++i)
            {
                _loops.Add(new S2Loop(src.Loop(i)));
            }
        }
        /**
         * Release ownership of the loops of this polygon by appending them to the
         * given list. Resets the polygon to be empty.
         */

        public void Release(System.Collections.Generic.IList <S2Loop> loops)
        {
            foreach (var item in _loops)
            {
                loops.Add(item);
            }

            _loops.Clear();
            _bound       = S2LatLngRect.Empty;
            _hasHoles    = false;
            _numVertices = 0;
        }
Ejemplo n.º 9
0
        /**
         * Like the constructor above, but assumes that the cell's bounding rectangle
         * has been precomputed.
         *
         * @param cell
         * @param bound
         */

        public S2Loop(S2Cell cell, S2LatLngRect bound)
        {
            _bound         = bound;
            _numVertices   = 4;
            _vertices      = new S2Point[_numVertices];
            _vertexToIndex = null;
            _index         = null;
            _depth         = 0;
            for (var i = 0; i < 4; ++i)
            {
                _vertices[i] = cell.GetVertex(i);
            }
            InitOrigin();
            InitFirstLogicalVertex();
        }
Ejemplo n.º 10
0
        public void AddPoint(S2Point b)
        {
            // assert (S2.isUnitLength(b));

            var bLatLng = new S2LatLng(b);

            if (bound.IsEmpty)
            {
                bound = bound.AddPoint(bLatLng);
            }
            else
            {
                // We can't just call bound.addPoint(bLatLng) here, since we need to
                // ensure that all the longitudes between "a" and "b" are included.
                bound = bound.Union(S2LatLngRect.FromPointPair(aLatLng, bLatLng));

                // Check whether the Min/Max latitude occurs in the edge interior.
                // We find the normal to the plane containing AB, and then a vector
                // "dir" in this plane that also passes through the equator. We use
                // RobustCrossProd to ensure that the edge normal is accurate even
                // when the two points are very close together.
                var aCrossB = S2.RobustCrossProd(a, b);
                var dir     = S2Point.CrossProd(aCrossB, new S2Point(0, 0, 1));
                var da      = dir.DotProd(a);
                var db      = dir.DotProd(b);

                if (da * db < 0)
                {
                    // Minimum/maximum latitude occurs in the edge interior. This affects
                    // the latitude bounds but not the longitude bounds.
                    var absLat = Math.Acos(Math.Abs(aCrossB[2] / aCrossB.Norm));
                    var lat    = bound.Lat;
                    if (da < 0)
                    {
                        // It's possible that absLat < lat.lo() due to numerical errors.
                        lat = new R1Interval(lat.Lo, Math.Max(absLat, bound.Lat.Hi));
                    }
                    else
                    {
                        lat = new R1Interval(Math.Min(-absLat, bound.Lat.Lo), lat.Hi);
                    }
                    bound = new S2LatLngRect(lat, bound.Lng);
                }
            }
            a       = b;
            aLatLng = bLatLng;
        }
Ejemplo n.º 11
0
        /**
         * Initialize a loop connecting the given vertices. The last vertex is
         * implicitly connected to the first. All points should be unit length. Loops
         * must have at least 3 vertices.
         *
         * @param vertices
         */

        public S2Loop(IEnumerable <S2Point> vertices)
        {
            _vertices    = vertices.ToArray();
            _numVertices = _vertices.Length;
            _bound       = S2LatLngRect.Full;
            _depth       = 0;

            // if (debugMode) {
            //  assert (isValid(vertices, DEFAULT_MAX_ADJACENT));
            // }


            // initOrigin() must be called before InitBound() because the latter
            // function expects Contains() to work properly.
            InitOrigin();
            InitBound();
            InitFirstLogicalVertex();
        }
Ejemplo n.º 12
0
        /**
         * Reverse the order of the loop vertices, effectively complementing the
         * region represented by the loop.
         */

        public void Invert()
        {
            var last = NumVertices - 1;

            for (var i = (last - 1) / 2; i >= 0; --i)
            {
                var t = _vertices[i];
                _vertices[i]        = _vertices[last - i];
                _vertices[last - i] = t;
            }
            _vertexToIndex = null;
            _index         = null;
            _originInside ^= true;
            if (_bound.Lat.Lo > -S2.PiOver2 && _bound.Lat.Hi < S2.PiOver2)
            {
                // The complement of this loop contains both poles.
                _bound = S2LatLngRect.Full;
            }
            else
            {
                InitBound();
            }
            InitFirstLogicalVertex();
        }
Ejemplo n.º 13
0
 public RectBounder()
 {
     bound = S2LatLngRect.Empty;
 }