Esempio n. 1
0
    // Return the smallest cell that contains all descendants of this cell whose
    // bounds intersect "rect".  For algorithms that use recursive subdivision
    // to find the cells that intersect a particular object, this method can be
    // used to skip all the initial subdivision steps where only one child needs
    // to be expanded.
    //
    // Note that this method is not the same as returning the smallest cell that
    // contains the intersection of this cell with "rect".  Because of the
    // padding, even if one child completely contains "rect" it is still
    // possible that a neighboring child also intersects "rect".
    //
    // REQUIRES: bound().Intersects(rect)
    public S2CellId ShrinkToFit(R2Rect rect)
    {
        System.Diagnostics.Debug.Assert(Bound.Intersects(rect));

        // Quick rejection test: if "rect" contains the center of this cell along
        // either axis, then no further shrinking is possible.
        int ij_size = S2CellId.SizeIJ(Level);

        if (Level == 0)
        {
            // Fast path (most calls to this function start with a face cell).
            if (rect[0].Contains(0) || rect[1].Contains(0))
            {
                return(Id);
            }
        }
        else
        {
            if (rect[0].Contains(S2.STtoUV(S2.SiTitoST((uint)(2 * ij_lo_[0] + ij_size)))) ||
                rect[1].Contains(S2.STtoUV(S2.SiTitoST((uint)(2 * ij_lo_[1] + ij_size)))))
            {
                return(Id);
            }
        }
        // Otherwise we expand "rect" by the given padding() on all sides and find
        // the range of coordinates that it spans along the i- and j-axes.  We then
        // compute the highest bit position at which the min and max coordinates
        // differ.  This corresponds to the first cell level at which at least two
        // children intersect "rect".

        // Increase the padding to compensate for the error in S2Coords.UVtoST().
        // (The constant below is a provable upper bound on the additional error.)
        R2Rect padded = rect.Expanded(Padding + 1.5 * S2.DoubleEpsilon);
        var    ij_min = new int[2]; // Min i- or j- coordinate spanned by "padded"
        var    ij_xor = new int[2]; // XOR of the min and max i- or j-coordinates

        for (int d = 0; d < 2; ++d)
        {
            ij_min[d] = Math.Max(ij_lo_[d], S2.STtoIJ(S2.UVtoST(padded[d][0])));
            int ij_max = Math.Min(ij_lo_[d] + ij_size - 1,
                                  S2.STtoIJ(S2.UVtoST(padded[d][1])));
            ij_xor[d] = ij_min[d] ^ ij_max;
        }
        // Compute the highest bit position where the two i- or j-endpoints differ,
        // and then choose the cell level that includes both of these endpoints.  So
        // if both pairs of endpoints are equal we choose kMaxLevel; if they differ
        // only at bit 0, we choose (kMaxLevel - 1), and so on.
        var level_msb = ((ij_xor[0] | ij_xor[1]) << 1) + 1;
        var level     = S2.kMaxCellLevel - BitsUtils.FindMSBSetNonZero((uint)level_msb);

        if (level <= Level)
        {
            return(Id);
        }
        return(S2CellId.FromFaceIJ((int)Id.Face(), ij_min[0], ij_min[1]).Parent(level));
    }
Esempio n. 2
0
    // Given an edge AB and a rectangle "clip", verify that IntersectsRect(),
    // ClipEdge(), and ClipEdgeBound() produce consistent results.
    private static void TestClipEdge(R2Point a, R2Point b, R2Rect clip)
    {
        // A bound for the error in edge clipping plus the error in the
        // IntersectsRect calculation below.
        double kError = kEdgeClipErrorUVDist + kIntersectsRectErrorUVDist;

        if (!ClipEdge(a, b, clip, out var a_clipped, out var b_clipped))
        {
            Assert.False(IntersectsRect(a, b, clip.Expanded(-kError)));
        }
Esempio n. 3
0
        public void Test_S2PaddedCell_ShrinkToFit()
        {
            const int kIters = 1000;

            for (int iter = 0; iter < kIters; ++iter)
            {
                // Start with the desired result and work backwards.
                S2CellId result    = S2Testing.GetRandomCellId();
                R2Rect   result_uv = result.BoundUV();
                R2Point  size_uv   = result_uv.GetSize();

                // Find the biggest rectangle that fits in "result" after padding.
                // (These calculations ignore numerical errors.)
                double max_padding = 0.5 * Math.Min(size_uv[0], size_uv[1]);
                double padding     = max_padding * S2Testing.Random.RandDouble();
                R2Rect max_rect    = result_uv.Expanded(-padding);

                // Start with a random subset of the maximum rectangle.
                R2Point a = new(SampleInterval(max_rect[0]), SampleInterval(max_rect[1]));
                R2Point b = new(SampleInterval(max_rect[0]), SampleInterval(max_rect[1]));
                if (!result.IsLeaf())
                {
                    // If the result is not a leaf cell, we must ensure that no child of
                    // "result" also satisfies the conditions of ShrinkToFit().  We do this
                    // by ensuring that "rect" intersects at least two children of "result"
                    // (after padding).
                    int    axis   = S2Testing.Random.Uniform(2);
                    double center = result.CenterUV()[axis];

                    // Find the range of coordinates that are shared between child cells
                    // along that axis.
                    R1Interval shared = new(center - padding, center + padding);
                    double     mid    = SampleInterval(shared.Intersection(max_rect[axis]));
                    a = a.SetAxis(axis, SampleInterval(new R1Interval(max_rect[axis].Lo, mid)));
                    b = b.SetAxis(axis, SampleInterval(new R1Interval(mid, max_rect[axis].Hi)));
                }
                R2Rect rect = R2Rect.FromPointPair(a, b);

                // Choose an arbitrary ancestor as the S2PaddedCell.
                S2CellId initial_id = result.Parent(S2Testing.Random.Uniform(result.Level() + 1));
                Assert.Equal(result, new S2PaddedCell(initial_id, padding).ShrinkToFit(rect));
            }
        }