Пример #1
0
        /// <summary>
        /// Returns the rotation of the supplied counter clockwise enumerated
        /// convex polygon that results in the minimum area enclosing box.
        /// If multiple rotations are within epsilon in their area, the one
        /// that is closest to an axis-aligned rotation (0, 90, 180, 270) is
        /// returned. O(n).
        /// </summary>
        public static M22d ComputeMinAreaEnclosingBoxRotation(
            this Polygon2d polygon, double epsilon = 1e-6)
        {
            polygon = polygon.WithoutMultiplePoints(epsilon);
            var pc = polygon.PointCount;

            if (pc < 2)
            {
                return(M22d.Identity);
            }
            var ea = polygon.GetEdgeArray();

            ea.Apply(v => v.Normalized);

            int i0 = 0, i1 = 0;
            int i2 = 0, i3 = 0;
            var min = polygon[0]; var max = polygon[0];

            for (int pi = 1; pi < pc; pi++)
            {
                var p = polygon[pi];
                if (p.Y < min.Y)
                {
                    i0 = pi; min.Y = p.Y;
                }
                else if (p.Y > max.Y)
                {
                    i2 = pi; max.Y = p.Y;
                }
                if (p.X > max.X)
                {
                    i1 = pi; max.X = p.X;
                }
                else if (p.X < min.X)
                {
                    i3 = pi; min.X = p.X;
                }
            }

            V2d p0 = polygon[i0], e0 = ea[i0], p1 = polygon[i1], e1 = ea[i1];
            V2d p2 = polygon[i2], e2 = ea[i2], p3 = polygon[i3], e3 = ea[i3];

            int end0 = (i0 + 1) % pc, end1 = (i1 + 1) % pc;
            int end2 = (i2 + 1) % pc, end3 = (i3 + 1) % pc;
            var dir = V2d.XAxis;

            var best      = dir;
            var bestArea  = double.MaxValue;
            var bestValue = double.MaxValue;

            while (true)
            {
                var s0 = Fun.FastAtan2(e0.Dot90(dir), e0.Dot(dir));
                var s1 = Fun.FastAtan2(e1.Dot180(dir), e1.Dot90(dir));
                var s2 = Fun.FastAtan2(e2.Dot270(dir), e2.Dot180(dir));
                var s3 = Fun.FastAtan2(e3.Dot(dir), e3.Dot270(dir));

                int si, si01, si23; double s01, s23;
                if (s0 < s1)
                {
                    s01 = s0; si01 = 0;
                }
                else
                {
                    s01 = s1; si01 = 1;
                }
                if (s2 < s3)
                {
                    s23 = s2; si23 = 2;
                }
                else
                {
                    s23 = s3; si23 = 3;
                }
                if (s01 < s23)
                {
                    si = si01;
                }
                else
                {
                    si = si23;
                }

                if (si == 0)
                {
                    dir = ea[i0];
                }
                else if (si == 1)
                {
                    dir = ea[i1].Rot270;
                }
                else if (si == 2)
                {
                    dir = ea[i2].Rot180;
                }
                else
                {
                    dir = ea[i3].Rot90;
                }

                double sx = (p2 - p0).Dot90(dir), sy = (p1 - p3).Dot(dir);
                double area  = sx * sy;
                double value = Fun.Min(Fun.Abs(dir.X), Fun.Abs(dir.Y));

                if (area < bestArea - epsilon ||
                    (area < bestArea + epsilon && value < bestValue))
                {
                    bestArea = area; bestValue = value; best = dir;
                }

                if (si == 0)
                {
                    if (++i0 >= pc)
                    {
                        i0 -= pc;
                    }
                    if (i0 == end1)
                    {
                        break;
                    }
                    p0 = polygon[i0]; e0 = ea[i0];
                }
                else if (si == 1)
                {
                    if (++i1 >= pc)
                    {
                        i1 -= pc;
                    }
                    if (i1 == end2)
                    {
                        break;
                    }
                    p1 = polygon[i1]; e1 = ea[i1];
                }
                else if (si == 2)
                {
                    if (++i2 >= pc)
                    {
                        i2 -= pc;
                    }
                    if (i2 == end3)
                    {
                        break;
                    }
                    p2 = polygon[i2]; e2 = ea[i2];
                }
                else
                {
                    if (++i3 >= pc)
                    {
                        i3 -= pc;
                    }
                    if (i3 == end0)
                    {
                        break;
                    }
                    p3 = polygon[i3]; e3 = ea[i3];
                }
            }
            return(new M22d(best.X, best.Y, -best.Y, best.X));
        }
Пример #2
0
        /// <summary>
        /// Returns the Line-Segments of line inside the Polygon (CCW ordered).
        /// Works with all (convex and non-convex) Polygons
        /// </summary>
        public static IEnumerable <Line2d> ClipWith(this Line2d line, Polygon2d poly)
        {
            bool i0, i1;

            i0 = poly.Contains(line.P0);
            i1 = poly.Contains(line.P1);


            List <V2d>  resulting = new List <V2d>();
            List <bool> enter     = new List <bool>();

            if (i0)
            {
                resulting.Add(line.P0);
                enter.Add(true);
            }
            if (i1)
            {
                resulting.Add(line.P1);
                enter.Add(false);
            }

            V2d p         = V2d.NaN;
            V2d direction = line.Direction;

            foreach (var l in poly.EdgeLines)
            {
                if (line.Intersects(l, out p))
                {
                    V2d d = l.Direction;
                    V2d n = new V2d(-d.Y, d.X);

                    if (!p.IsNaN)
                    {
                        bool addflag = true;
                        bool flag    = direction.Dot(n) > 0;

                        for (int i = 0; i < resulting.Count; i++)
                        {
                            if (Fun.IsTiny((resulting[i] - p).Length))
                            {
                                if (flag != enter[i])
                                {
                                    resulting.RemoveAt(i);
                                    enter.RemoveAt(i);
                                }

                                addflag = false;
                                break;
                            }
                        }

                        if (addflag)
                        {
                            resulting.Add(p);
                            enter.Add(flag);
                        }
                    }
                }
            }


            V2d dir = line.P1 - line.P0;

            resulting = (from r in resulting select r).OrderBy(x => x.Dot(dir)).ToList();

            int           counter = resulting.Count;
            List <Line2d> lines   = new List <Line2d>();

            for (int i = 0; i < counter - 1; i += 2)
            {
                lines.Add(new Line2d(resulting[i], resulting[i + 1]));
            }
            return(lines);
        }
Пример #3
0
        public static Trafo3d FromToRH(Axis from, Axis to)
        {
            var s = Fun.Sign(((int)to) - ((int)from)); // +/- sin(90°)

            return(FromTo(from, to, s));
        }
Пример #4
0
 public __vt__ GetVector(double alpha)
 {
     return(Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha));
 }
Пример #5
0
        public bool HitsCylinder(Cylinder3d cylinder,
                                 double tmin, double tmax,
                                 ref RayHit3d hit)
        {
            var axisDir = cylinder.Axis.Direction.Normalized;

            // Vector Cyl.P0 -> Ray.Origin
            var op = Origin - cylinder.P0;

            // normal RayDirection - CylinderAxis
            var normal     = Direction.Cross(axisDir);
            var unitNormal = normal.Normalized;

            // normal (Vec Cyl.P0 -> Ray.Origin) - CylinderAxis
            var normal2 = op.Cross(axisDir);
            var t       = -normal2.Dot(unitNormal) / normal.Length;

            var radius = cylinder.Radius;

            if (cylinder.DistanceScale != 0)
            {   // cylinder gets bigger, the further away it is
                var pnt = GetPointOnRay(t);

                var dis = V3d.Distance(pnt, this.Origin);
                radius = ((cylinder.Radius / cylinder.DistanceScale) * dis) * 2;
            }

            // between enitre rays (caps are ignored)
            var shortestDistance = Fun.Abs(op.Dot(unitNormal));

            if (shortestDistance <= radius)
            {
                var s = Fun.Abs(Fun.Sqrt(radius.Square() - shortestDistance.Square()) / Direction.Length);

                var t1 = t - s; // first hit of Cylinder shell
                var t2 = t + s; // second hit of Cylinder shell

                if (t1 > tmin && t1 < tmax)
                {
                    tmin = t1;
                }
                if (t2 < tmax && t2 > tmin)
                {
                    tmax = t2;
                }

                hit.T     = t1;
                hit.Point = GetPointOnRay(t1);

                // check if found point is outside of Cylinder Caps
                var bottomPlane  = new Plane3d(cylinder.Circle0.Normal, cylinder.Circle0.Center);
                var topPlane     = new Plane3d(cylinder.Circle1.Normal, cylinder.Circle1.Center);
                var heightBottom = bottomPlane.Height(hit.Point);
                var heightTop    = topPlane.Height(hit.Point);
                // t1 lies outside of caps => find closest cap hit
                if (heightBottom > 0 || heightTop > 0)
                {
                    hit.T = tmax;
                    // intersect with bottom Cylinder Cap
                    var bottomHit = HitsPlane(bottomPlane, tmin, tmax, ref hit);
                    // intersect with top Cylinder Cap
                    var topHit = HitsPlane(topPlane, tmin, tmax, ref hit);

                    // hit still close enough to cylinder axis?
                    var distance = cylinder.Axis.Ray3d.GetMinimalDistanceTo(hit.Point);

                    if (distance <= radius && (bottomHit || topHit))
                    {
                        return(true);
                    }
                }
                else
                {
                    return(true);
                }
            }

            hit.T     = tmax;
            hit.Point = V3d.NaN;
            return(false);
        }
Пример #6
0
 /// <summary>
 /// Returns the Manhatten (or 1-) distance between two matrices.
 /// </summary>
 public static __ftype__ Distance1(__nmtype__ a, __nmtype__ b)
 {
     return/*# n.ForEach(i => { m.ForEach(j => { */
            (Fun.Abs(b.M__i____j__ - a.M__i____j__) /*# }, add); }, add); */);
 }
Пример #7
0
 /// <summary>
 /// Returns the p-distance between two matrices.
 /// </summary>
 public static __ctype__ Distance(__nmtype__ a, __nmtype__ b, __ctype__ p)
 {
     return((                                                 /*# n.ForEach(i => { m.ForEach(j => { */
                Fun.Abs(b.M__i____j__ - a.M__i____j__).Pow(p) /*# }, add); }, add); */
                ).Pow(1 / p));
 }
Пример #8
0
        // 2-Dimensional

        #region V2d - V2d

        public static bool IsParallelTo(this V2d u, V2d v)
        {
            return(Fun.IsTiny(u.X * v.Y - u.Y * v.X));
        }
Пример #9
0
        // 3-Dimensional

        #region V3d - V3d

        public static bool IsOrthogonalTo(this V3d u, V3d v)
        {
            return(Fun.IsTiny(u.Dot(v)));
        }
 public static __ft__ DistMax(this Vector <__ft__> v0, Vector <__ft__> v1)
 => v0.InnerProduct(v1, (x0, x1) => Fun.Abs(x1 - x0), __zero__, Fun.Max);
Пример #11
0
 static double GetArea(V2d axis0, V2d axis1)
 {
     return(Fun.Abs(axis0.X * axis1.Y - axis0.Y * axis1.X) * Constant.Pi);
 }
 public static __ft__ Dist2(this Vector <__ft__> v0, Vector <__ft__> v1)
 => Fun.Sqrt(v0.Dist2Squared(v1));
 public static __ft__ Dist2Squared(this Vector <__ft__> v0, Vector <__ft__> v1)
 => v0.InnerProduct(v1, (x0, x1) => Fun.Square(x1 - x0), __zero__, (s, p) => s + p);
Пример #14
0
 static double GetArea(V2d axis0, V2d axis1) => Fun.Abs(axis0.X * axis1.Y - axis0.Y * axis1.X) * Constant.Pi;
Пример #15
0
        private static void FastHartleyTransformRaw(
            this double[] v, long start, long size)
        {
            if (size < 2)
            {
                return;
            }

            /* ---------------------------------------------------------------
            *       The transforming part of the function.  It assumes that all
            *   indices are already bit-reversed.  For successive evaluation
            *   of the trigonometric functions the following recurrence is
            *   used:
            *
            *               a = 2 sin(square(d/2))
            *               b  = sin d
            *
            *               cos(t + d) = cos t - [ a * cos t + b sin t ]
            *               sin(t + d) = sin t - [ a * sin t - b cos t ]
            *
            *       The algorithm is based on the following recursion:
            *
            *               H[f] = Heven[f]
            + cos(2 PI f / n) Hodd[f]
            + sin(2 PI f / n) Hodd[n-f]	f in [0, n-1]
            +
            +               Heven[n/2 + g] = Heven[g]
            +               Hodd [n/2 + g] = Hodd [g]		g in [0, n/2-1]
            +  --------------------------------------------------------------- */
            long end = start + size;

            for (long i = start; i < end; i += 2)
            {
                double h0 = v[i], h1 = v[i + 1];
                v[i] = h0 + h1; v[i + 1] = h0 - h1;     // f = 0, PI
            }
            if (size < 4)
            {
                return;
            }

            for (long i = start; i < end; i += 4)
            {
                double h0 = v[i], h2 = v[i + 2];
                v[i] = h0 + h2; v[i + 2] = h0 - h2;     // f = 0, PI
                double h1 = v[i + 1], h3 = v[i + 3];
                v[i + 1] = h1 + h3; v[i + 3] = h1 - h3; // f = PI/2, 3 * PI/2
            }
            if (size < 8)
            {
                return;
            }

            for (long i = start; i < end; i += 8)
            {
                double h0 = v[i], h4 = v[i + 4];
                v[i] = h0 + h4; v[i + 4] = h0 - h4;     // f = 0, PI
                double one = Constant.Sqrt2Half * (v[i + 5] + v[i + 7]);
                double two = Constant.Sqrt2Half * (v[i + 7] - v[i + 5]);
                double h1 = v[i + 1], h3 = v[i + 3];
                v[i + 1] = h1 + one; v[i + 5] = h1 - one;
                v[i + 3] = h3 - two; v[i + 7] = h3 + two;
                double h2 = v[i + 2], h6 = v[i + 6];
                v[i + 2] = h2 + h6; v[i + 6] = h2 - h6; // f = PI/2, 3 * PI/2
            }
            if (size < 16)
            {
                return;
            }

            var sTable = new double[size / 4];
            var cTable = new double[size / 4];

            for (long len = 8, lenDiv2 = 4, lenMul2 = 16;
                 len < size;
                 lenDiv2 = len, len = lenMul2, lenMul2 = 2 * len)
            {
                double d = Constant.PiTimesTwo / lenMul2;
                double a = Fun.Sin(d * 0.5).Square() * 2.0;  // init trig. recurrence
                double b = Fun.Sin(d);
                double ct = 1.0, st = 0.0;

                for (long f = 1; f < lenDiv2; f++)                       // all freqs in the first quadrant
                {
                    double dct = a * ct + b * st, dst = a * st - b * ct; // trig. rec
                    ct       -= dct; st -= dst;                          // cos (t + d), sin (t + d)
                    cTable[f] = ct; sTable[f] = st;
                }

                for (long i0 = start; i0 < end; i0 += lenMul2)
                {
                    long   i4 = i0 + len;
                    double h0 = v[i0], h4 = v[i4];
                    v[i0] = h0 + h4; v[i4] = h0 - h4;   // f = 0, PI

                    for (long f = 1; f < lenDiv2; f++)  // all freqs in the first quadrant
                    {
                        long   i1 = i0 + f, i3 = i0 + len - f;
                        long   i5 = i1 + len, i7 = i3 + len;
                        double one = cTable[f] * v[i5] + sTable[f] * v[i7];
                        double two = cTable[f] * v[i7] - sTable[f] * v[i5];
                        double h1 = v[i1], h3 = v[i3];
                        v[i1] = h1 + one; v[i5] = h1 - one; // all four quadrants
                        v[i3] = h3 - two; v[i7] = h3 + two; //
                    }

                    long   i2 = i0 + lenDiv2, i6 = i4 + lenDiv2;
                    double h2 = v[i2], h6 = v[i6];
                    v[i2] = h2 + h6; v[i6] = h2 - h6;       // f = PI/2, 3 * PI/2
                }
            }
        }
Пример #16
0
        // 3-Dimensional

        #region V3d - V3d

        public static bool IsParallelTo(this V3d u, V3d v)
        {
            return(Fun.IsTiny(u.Cross(v).Norm1));
        }
Пример #17
0
 /// <summary>
 /// Returns the p-norm of the matrix. This is calculated as
 /// (|M00|^p + |M01|^p + ... )^(1/p)
 /// </summary>
 public __ctype__ Norm(__ctype__ p)
 {
     return((                               /*# n.ForEach(i => { m.ForEach(j => { */
                Fun.Abs(M__i____j__).Pow(p) /*# }, add); }, add); */
                ).Pow(1 / p));
 }
Пример #18
0
 /// <summary>
 /// Perform a QR factorization of the supplied m x n matrix using
 /// Householder transofmations, i.e. A = QR, where Q is orthogonal
 /// (a product of n-2 Householder-Transformations) and R is a right
 /// upper n x n triangular matrix. An array of the diagonal elements
 /// of R is returned. WARNING: the supplied matrix A is overwritten
 ///  with its factorization QR, both in the parameter aqr.
 /// </summary>
 public static double[] QrFactorize(this double[,] aqr)
 {
     double[] diag = new double[Fun.Min(aqr.GetLength(0), aqr.GetLength(1))];
     aqr.QrFactorize(diag);
     return(diag);
 }
Пример #19
0
 /// <summary>
 /// Returns the Euclidean (or 2-) distance between two matrices.
 /// </summary>
 public static __ctype__ Distance2(__nmtype__ a, __nmtype__ b)
 {
     return /*# if (ctype != "double") {*/ ((__ctype__)/*# } */ Fun.Sqrt(/*# n.ForEach(i => { m.ForEach(j => { */
                                                Fun.Square(b.M__i____j__ - a.M__i____j__) /*# }, add); }, add); */));
 }
Пример #20
0
 public Fraction(long numerator, long denominator)
 {
     // ensure positive denominator
     Numerator   = denominator < 0 ? -numerator : numerator;
     Denominator = Fun.Abs(denominator);
 }
Пример #21
0
 /// <summary>
 /// Transposes this matrix (and returns this).
 /// </summary>
 public void Transpose()
 {
     //# for (int r = 1; r < n; r++) { r.ForEach(s => {
     Fun.Swap(ref M__r____s__, ref M__s____r__);
     //# }); }
 }
Пример #22
0
        //# });
        #endregion

        #region LinCom

        //# foreach (var it in Meta.IntegerTypes) { var itn = it.Name;
        //# for (int tpc = 4; tpc < 7; tpc+=2) {
        //# foreach (var rt in Meta.RealTypes) { var rtn = rt.Name; var rtc = rt.Caps[0];
        public static __itn__ LinCom(
            /*# tpc.ForEach(i => { */ __itn__ p__i__ /*# }, comma); */, ref Tup__tpc__ <__rtn__> w)
        {
            return((__itn__)Fun.Clamp(/*# tpc.ForEach(i => { */ p__i__ * w.E__i__ /*# }, add); */, (__rtn__)__itn__.MinValue, (__rtn__)__itn__.MaxValue));
        }
Пример #23
0
 public __vt__ GetPoint(double alpha)
 {
     return(Center + Axis0 * Fun.Cos(alpha) + Axis1 * Fun.Sin(alpha));
 }
Пример #24
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 (V2d.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;
        }