예제 #1
0
        /// <summary>
        /// Smallest cell that contains given box.
        /// </summary>
        public Cell2d(Box2d box)
        {
            if (!box.IsValid)
            {
                throw new InvalidOperationException();
            }

            // case 1: contains origin
            if (box.Min.X < 0.0 && box.Max.X > 0.0 ||
                box.Min.Y < 0.0 && box.Max.Y > 0.0)
            {
                X        = Y = long.MaxValue;
                Exponent = Math.Max(box.Min.NormMax, box.Max.NormMax).Log2Int() + 1;
            }
            else // case 2: doesn't contain origin
            {
                Exponent = (box.Min == box.Max)
                        ? (box.Min.NormMax / (long.MaxValue >> 1)).Log2Int()
                        : box.Size.NormMax.Log2Int()
                ;
                var s = Math.Pow(2.0, Exponent);
                var a = (box.Min / s).Floor() * s;
                while (a.X + s < box.Max.X || a.Y + s < box.Max.Y)
                {
                    s *= 2.0; Exponent++;
                    a  = (box.Min / s).Floor() * s;
                }
                X = (long)Math.Floor(a.X / s);
                Y = (long)Math.Floor(a.Y / s);
            }
        }
예제 #2
0
        public static IEnumerable <Polygon2d> Union(this Box2d b0, Box2d b1)
        {
            Polygon2d p0 = new Polygon2d(b0.ComputeCornersCCW());
            Polygon2d p1 = new Polygon2d(b1.ComputeCornersCCW());

            return(p0.Union(p1));
        }
예제 #3
0
        private static Box2d ComputeBoundingBox(long x, long y, int e)
        {
            var d = Math.Pow(2.0, e);
            var isCenteredAtOrigin = x == long.MaxValue && y == long.MaxValue;
            var min = isCenteredAtOrigin ? new V2d(-0.5 * d) : new V2d(x * d, y * d);

            return(Box2d.FromMinAndSize(min, new V2d(d, d)));
        }
예제 #4
0
        /// <summary>
        /// Gets oriented bounding box of this polygon
        /// </summary>
        public static Polygon2d ComputeOrientedBoundingBox(this Polygon2d polygon)
        {
            var rot      = polygon.ComputeMinAreaEnclosingBoxRotation();
            var rotInv   = rot.Transposed;
            var bbGlobal = new Box2d(polygon.Points.Select(p => rot * p));

            return(new Polygon2d(bbGlobal.ComputeCornersCCW().Apply(p => rotInv * p)));
        }
예제 #5
0
 public Hull2d(Box2d box)
 {
     PlaneArray = new[]
     {
         new Plane2d(V2d.XAxis, box.Min),
         new Plane2d(V2d.YAxis, box.Min),
         new Plane2d(-V2d.XAxis, box.Max),
         new Plane2d(-V2d.YAxis, box.Max),
     };
 }
예제 #6
0
        /// <summary>
        /// Compute the Delaunay triangluation of the supplied points. Note that
        /// the supplied point array must be by 3 larger than the actual number of
        /// points.
        /// </summary>
        private static void Triangulate2d(V2d[] pa,
                                          out Triangle1i[] ta, out int triangleCount)
        {
            int vc    = pa.Length - 4;
            int tcMax = 2 * vc + 2; // sharp upper bound with no degenerates
            int ecMax = 6 * vc - 3; // sharp bound: last step replaces all tris

            ta = new Triangle1i[tcMax];
            var ra = new double[tcMax];
            var ca = new V2d[tcMax];
            var ea = new Line1i[ecMax];

            // -------------------------------------- set up the supertriangle
            ta[0] = new Triangle1i(vc, vc + 2, vc + 1);
            ra[0] = -1.0;
            ta[1] = new Triangle1i(vc, vc + 3, vc + 2);
            ra[1] = -1.0;
            int tc = 2, cc = 0; // triangle count, complete count

            // ------------- superquad vertices at the end of vertex array
            var box = new Box2d(pa.Take(vc)).EnlargedBy(0.1);
            V2d center = box.Center, size = box.Size;

            pa[vc + 0] = box.Min;
            pa[vc + 1] = new V2d(box.Min.X, box.Max.Y);
            pa[vc + 2] = box.Max;
            pa[vc + 3] = new V2d(box.Max.X, box.Min.Y);

            // ------------------------------ include the points one at a time
            for (int i = 0; i < vc; i++)
            {
                V2d p  = pa[i];
                int ec = 0;

                /*
                 * if the point lies inside the circumcircle then the triangle
                 * is removed and its edges are added to the edge array
                 */
                for (int ti = cc; ti < tc; ti++)
                {
                    var    tr = ta[ti];
                    double r2 = ra[ti];
                    if (r2 < 0.0)
                    {
                        Triangle2d.ComputeCircumCircleSquared(
                            pa[tr.I0], pa[tr.I1], pa[tr.I2],
                            out center, out r2);
                        ra[ti] = r2; ca[ti] = center;
                    }
                    else
                    {
                        center = ca[ti];
                    }

                    // ---------------- include this if points are sorted by X
                    if (center.X < p.X && (p.X - center.X).Square() > r2)
                    {
                        Fun.Swap(ref ta[ti], ref ta[cc]);
                        ra[ti] = ra[cc]; ca[ti] = ca[cc];
                        ++cc; continue;
                    }
                    if (Vec.DistanceSquared(p, center) <= r2)
                    {
                        int nec = ec + 3;
                        if (nec >= ecMax)
                        {
                            ecMax = Fun.Max(nec, (int)(1.1 * (double)ecMax));
                            Array.Resize(ref ea, ecMax);
                        }
                        ea[ec]   = tr.Line01; ea[ec + 1] = tr.Line12; ea[ec + 2] = tr.Line20;
                        --tc; ec = nec;
                        ta[ti]   = ta[tc]; ra[ti] = ra[tc]; ca[ti] = ca[tc];
                        --ti;
                    }
                }

                // ---------------------------------------- tag multiple edges
                for (int ei = 0; ei < ec - 1; ei++)
                {
                    for (int ej = ei + 1; ej < ec; ej++)
                    {
                        if (ea[ei].I0 == ea[ej].I1 && ea[ei].I1 == ea[ej].I0)
                        {
                            ea[ei] = Line1i.Invalid; ea[ej] = Line1i.Invalid;
                        }
                    }
                }

                // ------------------ form new triangles for the current point
                for (int ei = 0; ei < ec; ei++)
                {
                    var e = ea[ei];
                    if (e.I0 < 0 || e.I1 < 0)
                    {
                        continue;    // skip tagged edges
                    }
                    if (tc >= tcMax) // necessary for degenerate cases
                    {
                        tcMax = Fun.Max(tcMax + 1, (int)(1.1 * (double)tcMax));
                        Array.Resize(ref ta, tcMax);
                        Array.Resize(ref ra, tcMax);
                        Array.Resize(ref ca, tcMax);
                    }
                    ta[tc]   = new Triangle1i(e.I0, e.I1, i);
                    ra[tc++] = -1.0;
                }
            }

            // ------------------ remove triangles with supertriangle vertices
            for (int ti = 0; ti < tc; ti++)
            {
                if (ta[ti].I0 >= vc || ta[ti].I1 >= vc || ta[ti].I2 >= vc)
                {
                    ta[ti--] = ta[--tc];
                }
            }

            triangleCount = tc;
        }
예제 #7
0
 /// <summary>
 /// Computes bounding circle of box.
 /// </summary>
 public static Circle2d GetBoundingCircle2d(this Box2d box)
 => box.IsInvalid ? Circle2d.Invalid : new Circle2d(box.Center, 0.5 * box.Size.Length);
예제 #8
0
 public static V2d UniformV2dFullClosed(this IRandomUniform rnd, Box2d box)
 {
     return(new V2d(box.Min.X + rnd.UniformDoubleFullClosed() * (box.Max.X - box.Min.X),
                    box.Min.Y + rnd.UniformDoubleFullClosed() * (box.Max.Y - box.Min.Y)));
 }
예제 #9
0
        /// <summary>
        /// This variant of the intersection method returns the affected
        /// planes of the box if the box was hit.
        /// </summary>
        public bool Intersects(
            Box2d box,
            ref double tmin,
            ref double tmax,
            out Box.Flags tminFlags,
            out Box.Flags tmaxFlags
            )
        {
            var dirFlags = DirFlags;

            tminFlags = Box.Flags.None;
            tmaxFlags = Box.Flags.None;

            if ((dirFlags & DirFlags.PositiveX) != 0)
            {
                {
                    double t = (box.Max.X - Ray.Origin.X) * InvDir.X;
                    if (t <= tmin)
                    {
                        return(false);
                    }
                    if (t < tmax)
                    {
                        tmax = t; tmaxFlags = Box.Flags.MaxX;
                    }
                }
                {
                    double t = (box.Min.X - Ray.Origin.X) * InvDir.X;
                    if (t >= tmax)
                    {
                        return(false);
                    }
                    if (t > tmin)
                    {
                        tmin = t; tminFlags = Box.Flags.MinX;
                    }
                }
            }
            else if ((dirFlags & DirFlags.NegativeX) != 0)
            {
                {
                    double t = (box.Min.X - Ray.Origin.X) * InvDir.X;
                    if (t <= tmin)
                    {
                        return(false);
                    }
                    if (t < tmax)
                    {
                        tmax = t; tmaxFlags = Box.Flags.MinX;
                    }
                }
                {
                    double t = (box.Max.X - Ray.Origin.X) * InvDir.X;
                    if (t >= tmax)
                    {
                        return(false);
                    }
                    if (t > tmin)
                    {
                        tmin = t; tminFlags = Box.Flags.MaxX;
                    }
                }
            }
            else    // ray parallel to X-plane
            {
                if (Ray.Origin.X < box.Min.X || Ray.Origin.X > box.Max.X)
                {
                    return(false);
                }
            }

            if ((dirFlags & DirFlags.PositiveY) != 0)
            {
                {
                    double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y;
                    if (t <= tmin)
                    {
                        return(false);
                    }
                    if (t < tmax)
                    {
                        tmax = t; tmaxFlags = Box.Flags.MaxY;
                    }
                }
                {
                    double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y;
                    if (t >= tmax)
                    {
                        return(false);
                    }
                    if (t > tmin)
                    {
                        tmin = t; tminFlags = Box.Flags.MinY;
                    }
                }
            }
            else if ((dirFlags & DirFlags.NegativeY) != 0)
            {
                {
                    double t = (box.Min.Y - Ray.Origin.Y) * InvDir.Y;
                    if (t <= tmin)
                    {
                        return(false);
                    }
                    if (t < tmax)
                    {
                        tmax = t; tmaxFlags = Box.Flags.MinY;
                    }
                }
                {
                    double t = (box.Max.Y - Ray.Origin.Y) * InvDir.Y;
                    if (t >= tmax)
                    {
                        return(false);
                    }
                    if (t > tmin)
                    {
                        tmin = t; tminFlags = Box.Flags.MaxY;
                    }
                }
            }
            else    // ray parallel to Y-plane
            {
                if (Ray.Origin.Y < box.Min.Y || Ray.Origin.Y > box.Max.Y)
                {
                    return(false);
                }
            }

            if (tmin > tmax)
            {
                return(false);
            }

            return(true);
        }
예제 #10
0
 public Box2f(Box2d box)
 {
     Min = (V2f)box.Min;
     Max = (V2f)box.Max;
 }
예제 #11
0
 public OrientedBox2d(Box2d box, Euclidean2d trafo)
 {
     Box   = box;
     Trafo = trafo;
 }
예제 #12
0
 public OrientedBox2d(Box2d box, V2d trans)
 {
     Box   = box;
     Trafo = new Euclidean2d(Rot2d.Identity, trans);
 }
예제 #13
0
 public OrientedBox2d(Box2d box, Rot2d rot)
 {
     Box   = box;
     Trafo = new Euclidean2d(rot, V2d.Zero);
 }
예제 #14
0
        /// <summary>
        /// Rasterizes an array of polygons into a matrix of given size.
        /// First polygon is rasterized with label 1, second polygon with label 2, and so on.
        /// </summary>
        /// <param name="polygons">Polygons to rasterize.</param>
        /// <param name="resolution">Resolution of result matrix.</param>
        /// <param name="bb"></param>
        public static Matrix <int> RasterizeAsLabels(this IEnumerable <Polygon2d> polygons, V2i resolution, Box2d bb)
        {
            var matrix = new Matrix <int>(resolution);
            var scale  = (V2d)resolution / bb.Size;
            int i      = 1;

            foreach (var poly in polygons)
            {
                RasterizePolygon(poly.ToPolygon2d(p => (p - bb.Min) * scale), matrix, i++);
            }
            return(matrix);
        }
예제 #15
0
 public static Polygon2d ToPolygon2dCCW(this Box2d self)
 => new Polygon2d(self.Min, new V2d(self.Max.X, self.Min.Y), self.Max, new V2d(self.Min.X, self.Max.Y));
예제 #16
0
 public SampleGrid2d(V2l gridSize, Box2d region)
 {
     m_last   = gridSize - new V2l(1, 1);
     m_region = region;
     m_delta  = region.Size / (V2d)m_last;
 }