Ejemplo n.º 1
0
        public bool Contains(S2Cell cell)
        {
            // If the cap does not contain all cell vertices, return false.
            // We check the vertices before taking the Complement() because we can't
            // accurately represent the complement of a very small cap (a height
            // of 2-epsilon is rounded off to 2).
            var vertices = new S2Point[4];

            for (var k = 0; k < 4; ++k)
            {
                vertices[k] = cell.GetVertex(k);
                if (!Contains(vertices[k]))
                {
                    return(false);
                }
            }
            // Otherwise, return true if the complement of the cap does not intersect
            // the cell. (This test is slightly conservative, because technically we
            // want Complement().InteriorIntersects() here.)
            return(!Complement.Intersects(cell, vertices));
        }
        /**
         * Returns the smallest cell containing all four points, or
         * {@link S2CellId#sentinel()} if they are not all on the same face. The
         * points don't need to be normalized.
         */

        private static S2CellId ContainingCell(S2Point pa, S2Point pb, S2Point pc, S2Point pd)
        {
            var a = S2CellId.FromPoint(pa);
            var b = S2CellId.FromPoint(pb);
            var c = S2CellId.FromPoint(pc);
            var d = S2CellId.FromPoint(pd);

            if (a.Face != b.Face || a.Face != c.Face || a.Face != d.Face)
            {
                return(S2CellId.Sentinel);
            }

            while (!a.Equals(b) || !a.Equals(c) || !a.Equals(d))
            {
                a = a.Parent;
                b = b.Parent;
                c = c.Parent;
                d = d.Parent;
            }
            return(a);
        }
Ejemplo n.º 3
0
            /**
             * Initializes the iterator to iterate over a set of candidates that may
             * cross the edge (a,b).
             */

            public void GetCandidates(S2Point a, S2Point b)
            {
                _edgeIndex.PredictAdditionalCalls(1);
                _isBruteForce = !_edgeIndex.IsIndexComputed;
                if (_isBruteForce)
                {
                    _edgeIndex.IncrementQueryCount();
                    _currentIndex = 0;
                    _numEdges     = _edgeIndex.NumEdges;
                }
                else
                {
                    _candidates.Clear();
                    _edgeIndex.FindCandidateCrossings(a, b, _candidates);
                    _currentIndexInCandidates = 0;
                    if (_candidates.Any())
                    {
                        _currentIndex = _candidates[0];
                    }
                }
            }
Ejemplo n.º 4
0
        // S2Region interface (see {@code S2Region} for details):

        /** Return a bounding spherical cap. */

        /**
         * The point 'p' does not need to be normalized.
         */

        public bool Contains(S2Point p)
        {
            if (!_bound.Contains(p))
            {
                return(false);
            }

            var inside  = _originInside;
            var origin  = S2.Origin;
            var crosser = new EdgeCrosser(origin, p,
                                          _vertices[_numVertices - 1]);

            // The s2edgeindex library is not optimized yet for long edges,
            // so the tradeoff to using it comes with larger loops.
            if (_numVertices < 2000)
            {
                for (var i = 0; i < _numVertices; i++)
                {
                    inside ^= crosser.EdgeOrVertexCrossing(_vertices[i]);
                }
            }
            else
            {
                var it = GetEdgeIterator(_numVertices);
                it.GetCandidates(origin, p);
                var previousIndex = -2;
                foreach (var ai in it) // it.GetCandidates(origin, p); it.HasNext; it.Next())
                {
                    //var ai = it.Index;
                    if (previousIndex != ai - 1)
                    {
                        crosser.RestartAt(_vertices[ai]);
                    }
                    previousIndex = ai;
                    inside       ^= crosser.EdgeOrVertexCrossing(Vertex(ai + 1));
                }
            }

            return(inside);
        }
Ejemplo n.º 5
0
        public static R2Vector ValidFaceXyzToUv(int face, S2Point p)
        {
            // assert (p.dotProd(faceUvToXyz(face, 0, 0)) > 0);
            double pu;
            double pv;

            switch (face)
            {
            case 0:
                pu = p.Y / p.X;
                pv = p.Z / p.X;
                break;

            case 1:
                pu = -p.X / p.Y;
                pv = p.Z / p.Y;
                break;

            case 2:
                pu = -p.X / p.Z;
                pv = -p.Y / p.Z;
                break;

            case 3:
                pu = p.Z / p.X;
                pv = p.Y / p.X;
                break;

            case 4:
                pu = p.Z / p.Y;
                pv = -p.X / p.Y;
                break;

            default:
                pu = -p.Y / p.Z;
                pv = -p.X / p.Z;
                break;
            }
            return(new R2Vector(pu, pv));
        }
        // S2Region interface (see S2Region.java for details):

        /** Return a bounding spherical cap. */

        /**
         * The point 'p' does not need to be normalized.
         */

        public bool Contains(S2Point p)
        {
            if (NumLoops == 1)
            {
                return(Loop(0).Contains(p)); // Optimization.
            }
            if (!_bound.Contains(p))
            {
                return(false);
            }
            var inside = false;

            for (var i = 0; i < NumLoops; ++i)
            {
                inside ^= Loop(i).Contains(p);
                if (inside && !_hasHoles)
                {
                    break; // Shells are disjoint.
                }
            }
            return(inside);
        }
Ejemplo n.º 7
0
        /**
         * Return the approximate area of this cell. This method is accurate to within
         * 3% percent for all cell sizes and accurate to within 0.1% for cells at
         * level 5 or higher (i.e. 300km square or smaller). It is moderately cheap to
         * compute.
         */

        public double ApproxArea()
        {
            // All cells at the first two levels have the same area.
            if (_level < 2)
            {
                return(AverageArea(_level));
            }

            // First, compute the approximate area of the cell when projected
            // perpendicular to its normal. The cross product of its diagonals gives
            // the normal, and the length of the normal is twice the projected area.
            var flatArea = 0.5 * S2Point.CrossProd(
                GetVertex(2) - GetVertex(0), GetVertex(3) - GetVertex(1)).Norm;

            // Now, compensate for the curvature of the cell surface by pretending
            // that the cell is shaped like a spherical cap. The ratio of the
            // area of a spherical cap to the area of its projected disc turns out
            // to be 2 / (1 + sqrt(1 - r*r)) where "r" is the radius of the disc.
            // For example, when r=0 the ratio is 1, and when r=1 the ratio is 2.
            // Here we set Pi*r*r == flat_area to find the equivalent disc.
            return(flatArea * 2 / (1 + Math.Sqrt(1 - Math.Min(S2.InversePi * flatArea, 1.0))));
        }
Ejemplo n.º 8
0
        /**
         * Return true if the edges OA, OB, and OC are encountered in that order while
         * sweeping CCW around the point O. You can think of this as testing whether
         * A <= B <= C with respect to a continuous CCW ordering around O.
         *
         * Properties:
         * <ol>
         *   <li>If orderedCCW(a,b,c,o) && orderedCCW(b,a,c,o), then a == b</li>
         *   <li>If orderedCCW(a,b,c,o) && orderedCCW(a,c,b,o), then b == c</li>
         *   <li>If orderedCCW(a,b,c,o) && orderedCCW(c,b,a,o), then a == b == c</li>
         *   <li>If a == b or b == c, then orderedCCW(a,b,c,o) is true</li>
         *   <li>Otherwise if a == c, then orderedCCW(a,b,c,o) is false</li>
         * </ol>
         */

        public static bool OrderedCcw(S2Point a, S2Point b, S2Point c, S2Point o)
        {
            // The last inequality below is ">" rather than ">=" so that we return true
            // if A == B or B == C, and otherwise false if A == C. Recall that
            // RobustCCW(x,y,z) == -RobustCCW(z,y,x) for all x,y,z.

            var sum = 0;

            if (RobustCcw(b, o, a) >= 0)
            {
                ++sum;
            }
            if (RobustCcw(c, o, b) >= 0)
            {
                ++sum;
            }
            if (RobustCcw(a, o, c) > 0)
            {
                ++sum;
            }
            return(sum >= 2);
        }
Ejemplo n.º 9
0
        /**
         * Given two edge chains (see WedgeRelation above), this function returns +1
         * if A contains B, 0 if B contains A or the two wedges do not intersect,
         * and -1 if the edge chains A and B cross each other (i.e. if A intersects
         * both the interior and exterior of the region to the left of B). In
         * degenerate cases where more than one of these conditions is satisfied,
         * the maximum possible result is returned. For example, if A == B then the
         * result is +1.
         */

        public int Test(S2Point a0, S2Point ab1, S2Point a2, S2Point b0, S2Point b2)
        {
            // There are 6 possible edge orderings at a shared vertex (all
            // of these orderings are circular, i.e. abcd == bcda):
            //
            // (1) a2 b2 b0 a0: A contains B
            // (2) a2 a0 b0 b2: B contains A
            // (3) a2 a0 b2 b0: A and B are disjoint
            // (4) a2 b0 a0 b2: A and B intersect in one wedge
            // (5) a2 b2 a0 b0: A and B intersect in one wedge
            // (6) a2 b0 b2 a0: A and B intersect in two wedges
            //
            // In cases (4-6), the boundaries of A and B cross (i.e. the boundary
            // of A intersects the interior and exterior of B and vice versa).
            // Thus we want to distinguish cases (1), (2-3), and (4-6).
            //
            // Note that the vertices may satisfy more than one of the edge
            // orderings above if two or more vertices are the same. The tests
            // below are written so that we take the most favorable
            // interpretation, i.e. preferring (1) over (2-3) over (4-6). In
            // particular note that if orderedCCW(a,b,c,o) returns true, it may be
            // possible that orderedCCW(c,b,a,o) is also true (if a == b or b == c).

            if (S2.OrderedCcw(a0, a2, b2, ab1))
            {
                // The cases with this vertex ordering are 1, 5, and 6,
                // although case 2 is also possible if a2 == b2.
                if (S2.OrderedCcw(b2, b0, a0, ab1))
                {
                    return(1); // Case 1 (A contains B)
                }

                // We are in case 5 or 6, or case 2 if a2 == b2.
                return((a2.Equals(b2)) ? 0 : -1); // Case 2 vs. 5,6.
            }
            // We are in case 2, 3, or 4.
            return(S2.OrderedCcw(a0, b0, a2, ab1) ? 0 : -1); // Case 2,3 vs. 4.
        }
        /**
         * If this method returns false, the region does not intersect the given cell.
         * Otherwise, either region intersects the cell, or the intersection
         * relationship could not be determined.
         */

        public bool MayIntersect(S2Cell cell)
        {
            if (NumVertices == 0)
            {
                return(false);
            }

            // We only need to check whether the cell contains vertex 0 for correctness,
            // but these tests are cheap compared to edge crossings so we might as well
            // check all the vertices.
            for (var i = 0; i < NumVertices; ++i)
            {
                if (cell.Contains(Vertex(i)))
                {
                    return(true);
                }
            }
            var cellVertices = new S2Point[4];

            for (var i = 0; i < 4; ++i)
            {
                cellVertices[i] = cell.GetVertex(i);
            }
            for (var j = 0; j < 4; ++j)
            {
                var crosser =
                    new EdgeCrosser(cellVertices[j], cellVertices[(j + 1) & 3], Vertex(0));
                for (var i = 1; i < NumVertices; ++i)
                {
                    if (crosser.RobustCrossing(Vertex(i)) >= 0)
                    {
                        // There is a proper crossing, or two vertices were the same.
                        return(true);
                    }
                }
            }
            return(false);
        }
Ejemplo n.º 11
0
        /**
         * Returns the true centroid of the spherical triangle ABC multiplied by the
         * signed area of spherical triangle ABC. The reasons for multiplying by the
         * signed area are (1) this is the quantity that needs to be summed to compute
         * the centroid of a union or difference of triangles, and (2) it's actually
         * easier to calculate this way.
         */

        public static S2Point TrueCentroid(S2Point a, S2Point b, S2Point c)
        {
            // I couldn't find any references for computing the true centroid of a
            // spherical triangle... I have a truly marvellous demonstration of this
            // formula which this margin is too narrow to contain :)

            // assert (isUnitLength(a) && isUnitLength(b) && isUnitLength(c));
            var sina = S2Point.CrossProd(b, c).Norm;
            var sinb = S2Point.CrossProd(c, a).Norm;
            var sinc = S2Point.CrossProd(a, b).Norm;
            var ra   = (sina == 0) ? 1 : (Math.Asin(sina) / sina);
            var rb   = (sinb == 0) ? 1 : (Math.Asin(sinb) / sinb);
            var rc   = (sinc == 0) ? 1 : (Math.Asin(sinc) / sinc);

            // Now compute a point M such that M.X = rX * det(ABC) / 2 for X in A,B,C.
            var x = new S2Point(a.X, b.X, c.X);
            var y = new S2Point(a.Y, b.Y, c.Y);
            var z = new S2Point(a.Z, b.Z, c.Z);
            var r = new S2Point(ra, rb, rc);

            return(new S2Point(0.5 * S2Point.CrossProd(y, z).DotProd(r),
                               0.5 * S2Point.CrossProd(z, x).DotProd(r), 0.5 * S2Point.CrossProd(x, y).DotProd(r)));
        }
Ejemplo n.º 12
0
        /**
         * Return a vector "c" that is orthogonal to the given unit-length vectors "a"
         * and "b". This function is similar to a.CrossProd(b) except that it does a
         * better job of ensuring orthogonality when "a" is nearly parallel to "b",
         * and it returns a non-zero result even when a == b or a == -b.
         *
         *  It satisfies the following properties (RCP == RobustCrossProd):
         *
         *  (1) RCP(a,b) != 0 for all a, b (2) RCP(b,a) == -RCP(a,b) unless a == b or
         * a == -b (3) RCP(-a,b) == -RCP(a,b) unless a == b or a == -b (4) RCP(a,-b)
         * == -RCP(a,b) unless a == b or a == -b
         */

        public static S2Point RobustCrossProd(S2Point a, S2Point b)
        {
            // The direction of a.CrossProd(b) becomes unstable as (a + b) or (a - b)
            // approaches zero. This leads to situations where a.CrossProd(b) is not
            // very orthogonal to "a" and/or "b". We could fix this using Gram-Schmidt,
            // but we also want b.RobustCrossProd(a) == -b.RobustCrossProd(a).
            //
            // The easiest fix is to just compute the cross product of (b+a) and (b-a).
            // Given that "a" and "b" are unit-length, this has good orthogonality to
            // "a" and "b" even if they differ only in the lowest bit of one component.

            // assert (isUnitLength(a) && isUnitLength(b));
            var x = S2Point.CrossProd(b + a, b - a);

            if (!x.Equals(new S2Point(0, 0, 0)))
            {
                return(x);
            }

            // The only result that makes sense mathematically is to return zero, but
            // we find it more convenient to return an arbitrary orthogonal vector.
            return(Ortho(a));
        }
        private S2AreaCentroid GetAreaCentroid(bool doCentroid)
        {
            double areaSum     = 0;
            var    centroidSum = new S2Point(0, 0, 0);

            for (var i = 0; i < NumLoops; ++i)
            {
                var areaCentroid = doCentroid ? (S2AreaCentroid?)Loop(i).AreaAndCentroid : null;
                var loopArea     = doCentroid ? areaCentroid.Value.Area : Loop(i).Area;

                var loopSign = Loop(i).Sign;
                areaSum += loopSign * loopArea;
                if (doCentroid)
                {
                    var currentCentroid = areaCentroid.Value.Centroid.Value;
                    centroidSum =
                        new S2Point(centroidSum.X + loopSign * currentCentroid.X,
                                    centroidSum.Y + loopSign * currentCentroid.Y,
                                    centroidSum.Z + loopSign * currentCentroid.Z);
                }
            }

            return(new S2AreaCentroid(areaSum, doCentroid ? (S2Point?)centroidSum : null));
        }
        /**
         * Add the given edge to the polygon builder. This method should be used for
         * input data that may not follow S2 polygon conventions. Note that edges are
         * not allowed to cross each other. Also note that as a convenience, edges
         * where v0 == v1 are ignored.
         */

        public void AddEdge(S2Point v0, S2Point v1)
        {
            // If xor_edges is true, we look for an existing edge in the opposite
            // direction. We either delete that edge or insert a new one.

            if (v0.Equals(v1))
            {
                return;
            }

            if (_options.XorEdges)
            {
                HashBag <S2Point> candidates;
                _edges.TryGetValue(v1, out candidates);
                if (candidates != null && candidates.Any(c => c.Equals(v0)))
                {
                    EraseEdge(v1, v0);
                    return;
                }
            }

            if (!_edges.ContainsKey(v0))
            {
                _edges[v0] = new HashBag <S2Point>();
            }

            _edges[v0].Add(v1);
            if (_options.UndirectedEdges)
            {
                if (!_edges.ContainsKey(v1))
                {
                    _edges[v1] = new HashBag <S2Point>();
                }
                _edges[v1].Add(v0);
            }
        }
Ejemplo n.º 15
0
        /**
         * This method is equivalent to calling the S2EdgeUtil.robustCrossing()
         * function (defined below) on the edges AB and CD. It returns +1 if there
         * is a crossing, -1 if there is no crossing, and 0 if two points from
         * different edges are the same. Returns 0 or -1 if either edge is
         * degenerate. As a side effect, it saves vertex D to be used as the next
         * vertex C.
         */

        public int RobustCrossing(S2Point d)
        {
            // For there to be an edge crossing, the triangles ACB, CBD, BDA, DAC must
            // all be oriented the same way (CW or CCW). We keep the orientation
            // of ACB as part of our state. When each new point D arrives, we
            // compute the orientation of BDA and check whether it matches ACB.
            // This checks whether the points C and D are on opposite sides of the
            // great circle through AB.

            // Recall that robustCCW is invariant with respect to rotating its
            // arguments, i.e. ABC has the same orientation as BDA.
            var bda = S2.RobustCcw(a, b, d, aCrossB);
            int result;

            if (bda == -acb && bda != 0)
            {
                // Most common case -- triangles have opposite orientations.
                result = -1;
            }
            else if ((bda & acb) == 0)
            {
                // At least one value is zero -- two vertices are identical.
                result = 0;
            }
            else
            {
                // assert (bda == acb && bda != 0);
                result = RobustCrossingInternal(d); // Slow path.
            }
            // Now save the current vertex D as the next vertex C, and also save the
            // orientation of the new triangle ACB (which is opposite to the current
            // triangle BDA).
            c   = d;
            acb = -bda;
            return(result);
        }
Ejemplo n.º 16
0
        /**
         * This class allows a vertex chain v0, v1, v2, ... to be efficiently tested
         * for intersection with a given fixed edge AB.
         */

        /**
         * Return true if edge AB crosses CD at a point that is interior to both
         * edges. Properties:
         *
         *  (1) simpleCrossing(b,a,c,d) == simpleCrossing(a,b,c,d) (2)
         * simpleCrossing(c,d,a,b) == simpleCrossing(a,b,c,d)
         */

        public static bool SimpleCrossing(S2Point a, S2Point b, S2Point c, S2Point d)
        {
            // We compute simpleCCW() for triangles ACB, CBD, BDA, and DAC. All
            // of these triangles need to have the same orientation (CW or CCW)
            // for an intersection to exist. Note that this is slightly more
            // restrictive than the corresponding definition for planar edges,
            // since we need to exclude pairs of line segments that would
            // otherwise "intersect" by crossing two antipodal points.

            var ab  = S2Point.CrossProd(a, b);
            var acb = -(ab.DotProd(c));
            var bda = ab.DotProd(d);

            if (acb * bda <= 0)
            {
                return(false);
            }

            var cd  = S2Point.CrossProd(c, d);
            var cbd = -(cd.DotProd(b));
            var dac = cd.DotProd(a);

            return((acb * cbd > 0) && (acb * dac > 0));
        }
Ejemplo n.º 17
0
        // //////////////////////////////////////////////////////////////////////
        // S2Region interface (see {@code S2Region} for details):

        /**
         * Return true if the cap intersects 'cell', given that the cap vertices have
         * alrady been checked.
         */

        public bool Intersects(S2Cell cell, IReadOnlyList <S2Point> vertices)
        {
            // Return true if this cap intersects any point of 'cell' excluding its
            // vertices (which are assumed to already have been checked).

            // If the cap is a hemisphere or larger, the cell and the complement of the
            // cap are both convex. Therefore since no vertex of the cell is contained,
            // no other interior point of the cell is contained either.
            if (_height >= 1)
            {
                return(false);
            }

            // We need to check for empty caps due to the axis check just below.
            if (IsEmpty)
            {
                return(false);
            }

            // Optimization: return true if the cell contains the cap axis. (This
            // allows half of the edge checks below to be skipped.)
            if (cell.Contains(_axis))
            {
                return(true);
            }

            // At this point we know that the cell does not contain the cap axis,
            // and the cap does not contain any cell vertex. The only way that they
            // can intersect is if the cap intersects the interior of some edge.

            var sin2Angle = _height * (2 - _height); // sin^2(capAngle)

            for (var k = 0; k < 4; ++k)
            {
                var edge = cell.GetEdgeRaw(k);
                var dot  = _axis.DotProd(edge);
                if (dot > 0)
                {
                    // The axis is in the interior half-space defined by the edge. We don't
                    // need to consider these edges, since if the cap intersects this edge
                    // then it also intersects the edge on the opposite side of the cell
                    // (because we know the axis is not contained with the cell).
                    continue;
                }
                // The Norm2() factor is necessary because "edge" is not normalized.
                if (dot * dot > sin2Angle * edge.Norm2)
                {
                    return(false); // Entire cap is on the exterior side of this edge.
                }
                // Otherwise, the great circle containing this edge intersects
                // the interior of the cap. We just need to check whether the point
                // of closest approach occurs between the two edge endpoints.
                var dir = S2Point.CrossProd(edge, _axis);
                if (dir.DotProd(vertices[k]) < 0 &&
                    dir.DotProd(vertices[(k + 1) & 3]) > 0)
                {
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 18
0
        /**
         * Call this function when your chain 'jumps' to a new place.
         */

        public void RestartAt(S2Point c)
        {
            this.c = c;
            acb    = -S2.RobustCcw(a, b, c, aCrossB);
        }
Ejemplo n.º 19
0
        /**
         *'interval' is the longitude interval to be tested against, and 'v0' is
         * the first vertex of edge chain.
         */

        public LongitudePruner(S1Interval interval, S2Point v0)
        {
            this.interval = interval;
            lng0          = S2LatLng.Longitude(v0).Radians;
        }
Ejemplo n.º 20
0
        /**
         * Create a cap given its axis and its area in steradians. 'axis' should be a
         * unit-length vector, and 'area' should be between 0 and 4 * M_PI.
         */

        public static S2Cap FromAxisArea(S2Point axis, double area)
        {
            // assert (S2.isUnitLength(axis));
            return(new S2Cap(axis, area / (2 * S2.Pi)));
        }
Ejemplo n.º 21
0
 public CloserResult(double dmin2, S2Point vmin)
 {
     this.dmin2 = dmin2;
     this.vmin  = vmin;
 }
Ejemplo n.º 22
0
        /**
         * Return true if the edge AB intersects the given edge of constant latitude.
         */

        private static bool IntersectsLatEdge(S2Point a, S2Point b, double lat,
                                              S1Interval lng)
        {
            // Return true if the segment AB intersects the given edge of constant
            // latitude. Unfortunately, lines of constant latitude are curves on
            // the sphere. They can intersect a straight edge in 0, 1, or 2 points.
            // assert (S2.isUnitLength(a) && S2.isUnitLength(b));

            // First, compute the normal to the plane AB that points vaguely north.
            var z = S2Point.Normalize(S2.RobustCrossProd(a, b));

            if (z.Z < 0)
            {
                z = -z;
            }

            // Extend this to an orthonormal frame (x,y,z) where x is the direction
            // where the great circle through AB achieves its maximium latitude.
            var y = S2Point.Normalize(S2.RobustCrossProd(z, new S2Point(0, 0, 1)));
            var x = S2Point.CrossProd(y, z);
            // assert (S2.isUnitLength(x) && x.z >= 0);

            // Compute the angle "theta" from the x-axis (in the x-y plane defined
            // above) where the great circle intersects the given line of latitude.
            var sinLat = Math.Sin(lat);

            if (Math.Abs(sinLat) >= x.Z)
            {
                return(false); // The great circle does not reach the given latitude.
            }
            // assert (x.z > 0);
            var cosTheta = sinLat / x.Z;
            var sinTheta = Math.Sqrt(1 - cosTheta * cosTheta);
            var theta    = Math.Atan2(sinTheta, cosTheta);

            // The candidate intersection points are located +/- theta in the x-y
            // plane. For an intersection to be valid, we need to check that the
            // intersection point is contained in the interior of the edge AB and
            // also that it is contained within the given longitude interval "lng".

            // Compute the range of theta values spanned by the edge AB.
            var abTheta = S1Interval.FromPointPair(Math.Atan2(
                                                       a.DotProd(y), a.DotProd(x)), Math.Atan2(b.DotProd(y), b.DotProd(x)));

            if (abTheta.Contains(theta))
            {
                // Check if the intersection point is also in the given "lng" interval.
                var isect = (x * cosTheta) + (y * sinTheta);
                if (lng.Contains(Math.Atan2(isect.Y, isect.X)))
                {
                    return(true);
                }
            }
            if (abTheta.Contains(-theta))
            {
                // Check if the intersection point is also in the given "lng" interval.
                var intersection = (x * cosTheta) - (y * sinTheta);
                if (lng.Contains(Math.Atan2(intersection.Y, intersection.X)))
                {
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 23
0
        /**
         * Return the minimum distance from X to any point on the edge AB. The result
         * is very accurate for small distances but may have some numerical error if
         * the distance is large (approximately Pi/2 or greater). The case A == B is
         * handled correctly. Note: x, a and b must be of unit length. Throws
         * IllegalArgumentException if this is not the case.
         */

        public static S1Angle GetDistance(S2Point x, S2Point a, S2Point b)
        {
            return(GetDistance(x, a, b, S2.RobustCrossProd(a, b)));
        }
Ejemplo n.º 24
0
 public S2LatLngRect AddPoint(S2Point p)
 {
     return(AddPoint(new S2LatLng(p)));
 }
Ejemplo n.º 25
0
        /** The point 'p' does not need to be normalized. */

        public bool Contains(S2Point p)
        {
            return(Contains(new S2LatLng(p)));
        }
Ejemplo n.º 26
0
        /**
         * Returns true if this rectangle intersects the given cell. (This is an exact
         * test and may be fairly expensive, see also MayIntersect below.)
         */

        public bool Intersects(S2Cell cell)
        {
            // First we eliminate the cases where one region completely contains the
            // other. Once these are disposed of, then the regions will intersect
            // if and only if their boundaries intersect.

            if (IsEmpty)
            {
                return(false);
            }
            if (Contains(cell.Center))
            {
                return(true);
            }
            if (cell.Contains(Center.ToPoint()))
            {
                return(true);
            }

            // Quick rejection test (not required for correctness).
            if (!Intersects(cell.RectBound))
            {
                return(false);
            }

            // Now check whether the boundaries intersect. Unfortunately, a
            // latitude-longitude rectangle does not have straight edges -- two edges
            // are curved, and at least one of them is concave.

            // Precompute the cell vertices as points and latitude-longitudes.
            var cellV  = new S2Point[4];
            var cellLl = new S2LatLng[4];

            for (var i = 0; i < 4; ++i)
            {
                cellV[i]  = cell.GetVertex(i); // Must be normalized.
                cellLl[i] = new S2LatLng(cellV[i]);
                if (Contains(cellLl[i]))
                {
                    return(true); // Quick acceptance test.
                }
            }

            for (var i = 0; i < 4; ++i)
            {
                var edgeLng = S1Interval.FromPointPair(
                    cellLl[i].Lng.Radians, cellLl[(i + 1) & 3].Lng.Radians);
                if (!_lng.Intersects(edgeLng))
                {
                    continue;
                }

                var a = cellV[i];
                var b = cellV[(i + 1) & 3];
                if (edgeLng.Contains(_lng.Lo))
                {
                    if (IntersectsLngEdge(a, b, _lat, _lng.Lo))
                    {
                        return(true);
                    }
                }
                if (edgeLng.Contains(_lng.Hi))
                {
                    if (IntersectsLngEdge(a, b, _lat, _lng.Hi))
                    {
                        return(true);
                    }
                }
                if (IntersectsLatEdge(a, b, _lat.Lo, _lng))
                {
                    return(true);
                }
                if (IntersectsLatEdge(a, b, _lat.Hi, _lng))
                {
                    return(true);
                }
            }
            return(false);
        }
Ejemplo n.º 27
0
        /**
         * Return true if and only if the given point is contained in the interior of
         * the region (i.e. the region excluding its boundary). The point 'p' does not
         * need to be normalized.
         */

        public bool InteriorContains(S2Point p)
        {
            return(InteriorContains(new S2LatLng(p)));
        }
Ejemplo n.º 28
0
 public bool Contains(S2Point p)
 {
     // The point 'p' should be a unit-length vector.
     // assert (S2.isUnitLength(p));
     return((_axis - p).Norm2 <= 2 * _height);
 }
Ejemplo n.º 29
0
        // Caps may be constructed from either an axis and a height, or an axis and
        // an angle. To avoid ambiguity, there are no public constructors
        //private S2Cap()
        //{
        //    _axis = new S2Point();
        //    _height = 0;
        //}

        private S2Cap(S2Point axis, double height)
        {
            _axis   = axis;
            _height = height;
            // assert (isValid());
        }
Ejemplo n.º 30
0
        /**
         * Return true if and only if the given point is contained in the interior of
         * the region (i.e. the region excluding its boundary). 'p' should be a
         * unit-length vector.
         */

        public bool InteriorContains(S2Point p)
        {
            // assert (S2.isUnitLength(p));
            return(IsFull || (_axis - p).Norm2 < 2 * _height);
        }