예제 #1
0
        /// <summary>Return the closest point on 'rect' to 'pt'</summary>
        public static v2 ClosestPoint(BRect rect, v2 pt)
        {
            v2 lower = rect.Lower;
            v2 upper = rect.Upper;
            v2 closest;

            if (rect.IsWithin(pt))
            {
                // if pt.x/pt.y > rect.sizeX/rect.sizeY then the point
                // is closer to the Y edge of the rectangle
                if (Math_.Abs(pt.x * rect.SizeY) > Math_.Abs(pt.y * rect.SizeX))
                {
                    closest = new v2(pt.x, Math_.Sign(pt.y) * rect.SizeY);
                }
                else
                {
                    closest = new v2(Math_.Sign(pt.x) * rect.SizeX, pt.y);
                }
            }
            else
            {
                closest = new v2(
                    Math_.Clamp(pt.x, lower.x, upper.x),
                    Math_.Clamp(pt.y, lower.y, upper.y));
            }
            return(closest);
        }
예제 #2
0
 public v4(v2 xy_, float z_, float w_)
     : this()
 {
     xy = xy_;
     z  = z_;
     w  = w_;
 }
예제 #3
0
        /// <summary>Create a Monic from 2 points</summary>
        public static Monic FromPoints(v2 a, v2 b)
        {
            var A = (b.y - a.y) / (b.x - a.x);
            var B = a.y - A * a.x;

            return(new Monic(A, B));
        }
예제 #4
0
        // Make an orientation matrix from a direction.
        public static m2x2 OrientationFromDirection(v2 direction, int axis)
        {
            var ans = m2x2.Identity;

            ans.x = Normalise(direction);
            ans.y = new v2(ans.x.y, -ans.x.x);
            return(PermuteRotation(ans, axis));
        }
예제 #5
0
        /// <summary>Return the closest point between two line segments</summary>
        public static void ClosestPoint(v2 s0, v2 e0, v2 s1, v2 e1, out float t0, out float t1)
        {
            v2    line0           = e0 - s0;
            v2    line1           = e1 - s1;
            v2    separation      = s0 - s1;
            float f               = Math_.Dot(line1, separation);
            float c               = Math_.Dot(line0, separation);
            float line0_length_sq = line0.LengthSq;
            float line1_length_sq = line1.LengthSq;

            // Check if either or both segments are degenerate
            if (Math_.FEql(line0_length_sq, 0f) && Math_.FEql(line1_length_sq, 0f))
            {
                t0 = 0.0f; t1 = 0.0f; return;
            }
            if (Math_.FEql(line0_length_sq, 0f))
            {
                t0 = 0.0f; t1 = Math_.Clamp(f / line1_length_sq, 0.0f, 1.0f); return;
            }
            if (Math_.FEql(line1_length_sq, 0f))
            {
                t1 = 0.0f; t0 = Math_.Clamp(-c / line0_length_sq, 0.0f, 1.0f); return;
            }

            // The general non-degenerate case starts here
            float b     = Math_.Dot(line0, line1);
            float denom = line0_length_sq * line1_length_sq - b * b;             // Always non-negative

            // If segments not parallel, calculate closest point on infinite line 'line0'
            // to infinite line 'line1', and clamp to segment 1. Otherwise pick arbitrary t0
            t0 = denom != 0.0f ? Math_.Clamp((b * f - c * line1_length_sq) / denom, 0.0f, 1.0f) : 0.0f;

            // Calculate point on infinite line 'line1' closest to segment 'line0' at t0
            // using t1 = Dot3(pt0 - s1, line1) / line1_length_sq = (b*t0 + f) / line1_length_sq
            t1 = (b * t0 + f) / line1_length_sq;

            // If t1 in [0,1] then done. Otherwise, clamp t1, recompute t0 for the new value
            // of t1 using t0 = Dot3(pt1 - s0, line0) / line0_length_sq = (b*t1 - c) / line0_length_sq
            // and clamped t0 to [0, 1]
            if (t1 < 0.0f)
            {
                t1 = 0.0f; t0 = Math_.Clamp((-c) / line0_length_sq, 0.0f, 1.0f);
            }
            else if (t1 > 1.0f)
            {
                t1 = 1.0f; t0 = Math_.Clamp((b - c) / line0_length_sq, 0.0f, 1.0f);
            }
        }
예제 #6
0
        /// <summary>
        /// Return the intercept between a 2d line that passes through 'a' and 'b' and another
        /// that passes through 'c' and 'd'. Returns true if the lines intersect, false if they don't.
        /// Returns the point of intersect in </summary>
        public static bool Intersect(v2 a, v2 b, v2 c, v2 d, out v2 intersect)
        {
            v2    ab    = b - a;
            v2    cd    = d - c;
            float denom = ab.x * cd.y - ab.y * cd.x;

            if (Math_.FEql(denom, 0.0f))
            {
                intersect = v2.Zero;
                return(false);
            }

            float e = b.x * a.y - b.y * a.x;
            float f = d.x * c.y - d.y * c.x;

            intersect.x = (cd.x * e - ab.x * f) / denom;
            intersect.y = (cd.y * e - ab.y * f) / denom;
            return(true);
        }
예제 #7
0
        /// <summary>Finds the closest point to the 2d line segment a->b returning the parametric value</summary>
        public static float ClosestPoint(v2 a, v2 b, v2 pt)
        {
            v2 ab = b - a;

            // Project 'pt' onto 'ab', but defer divide by 'ab.Length2Sq'
            float t = Math_.Dot(pt - a, ab);

            if (t <= 0.0f)
            {
                return(0.0f);                // 'point' projects outside 'line', clamp to 0.0f
            }
            float denom = ab.LengthSq;

            if (t >= denom)
            {
                return(1.0f);             // 'point' projects outside 'line', clamp to 1.0f
            }
            return(t / denom);            // 'point' projects inside 'line', do deferred divide now
        }
예제 #8
0
        /// <summary>Create a quadratic from 3 points</summary>
        public static Quadratic FromPoints(v2 a, v2 b, v2 c)
        {
            //' Aa.x2 + Ba.x + C = a.y
            //' Ab.x2 + Bb.x + C = a.y
            //' Ac.x2 + Bc.x + C = a.y
            //' => Ax = y
            //' A = |a.x² a.x 1| x = |A| y = |a.y|
            //'     |b.x² b.x 1|     |B|     |b.y|
            //'     |c.x² c.x 1|     |C|     |c.y|
            var M = Math_.Transpose(new m3x4(
                                        new v4(a.x * a.x, a.x, 1, 0),
                                        new v4(b.x * b.x, b.x, 1, 0),
                                        new v4(c.x * c.x, c.x, 1, 0)));

            var y = new v4(a.y, b.y, c.y, 0);
            var x = Math_.Invert(M) * y;

            return(new Quadratic(x.x, x.y, x.z));
        }
예제 #9
0
 /// <summary>
 /// Returns the closest points between 'lhs' and 'rhs'.
 /// If 'lhs' and 'rhs' overlap, returns the points of deepest penetration.</summary>
 public static void ClosestPoint(BRect lhs, BRect rhs, out v2 pt0, out v2 pt1)
 {
     pt0 = lhs.Centre;
     pt1 = rhs.Centre;
     if (rhs.Centre.x > lhs.Centre.x)
     {
         pt0.x += lhs.Radius.x; pt1.x += rhs.Radius.x;
     }
     if (rhs.Centre.x < lhs.Centre.x)
     {
         pt0.x -= lhs.Radius.x; pt1.x -= rhs.Radius.x;
     }
     if (rhs.Centre.y > lhs.Centre.y)
     {
         pt0.y += lhs.Radius.y; pt1.y += rhs.Radius.y;
     }
     if (rhs.Centre.y < lhs.Centre.y)
     {
         pt0.y -= lhs.Radius.y; pt1.y -= rhs.Radius.y;
     }
 }
예제 #10
0
        // Create a cubic from 4 points
        public static Cubic FromPoints(v2 a, v2 b, v2 c, v2 d)
        {
            //' Aa.x³ + Ba.x² + Ca.x + D = a.y
            //' Ab.x³ + Bb.x² + Cb.x + D = a.y
            //' Ac.x³ + Bc.x² + Cc.x + D = a.y
            //' Ad.x³ + Bd.x² + Cd.x + D = a.y
            //' => Ax = y
            //' A = |a.x² a.x 1| x = |A| y = |a.y|
            //'     |b.x² b.x 1|     |B|     |b.y|
            //'     |c.x² c.x 1|     |C|     |c.y|
            var M = Math_.Transpose(new m4x4(
                                        new v4(a.x * a.x * a.x, a.x * a.x, a.x, 1),
                                        new v4(b.x * b.x * b.x, b.x * b.x, b.x, 1),
                                        new v4(c.x * c.x * c.x, c.x * c.x, c.x, 1),
                                        new v4(d.x * d.x * d.x, d.x * d.x, d.x, 1)));

            var y = new v4(a.y, b.y, c.y, d.y);
            var x = Math_.Invert(M) * y;

            return(new Cubic(x.x, x.y, x.z, x.w));
        }
예제 #11
0
        //public m2x2(v2 axis_norm, v4 axis_sine_angle, float cos_angle) :this() { set(axis_norm, axis_sine_angle, cos_angle); }
        //public m2x2(v2 axis_norm, float angle) :this()                         { set(axis_norm, angle); }
        //public m2x2(v2 from, v4 to) :this()                                    { set(from, to); }

        /// <summary>Get/Set columns by index</summary>
        public                       v2 this[int c]
        {
            get
            {
                switch (c)
                {
                case 0: return(x);

                case 1: return(y);
                }
                throw new ArgumentException("index out of range", "i");
            }
            set
            {
                switch (c)
                {
                case 0: x = value; return;

                case 1: y = value; return;
                }
                throw new ArgumentException("index out of range", "i");
            }
        }
예제 #12
0
        /// <summary>Returns the squared distance from 'point' to 'brect'</summary>
        public static float DistanceSq(v2 point, BRect brect)
        {
            float dist_sq = 0.0f;
            v2    lower   = brect.Lower;
            v2    upper   = brect.Upper;

            if (point.x < lower.x)
            {
                dist_sq += Math_.Sqr(lower.x - point.x);
            }
            else if (point.x > upper.x)
            {
                dist_sq += Math_.Sqr(point.x - upper.x);
            }
            if (point.y < lower.y)
            {
                dist_sq += Math_.Sqr(lower.y - point.y);
            }
            else if (point.y > upper.y)
            {
                dist_sq += Math_.Sqr(point.y - upper.y);
            }
            return(dist_sq);
        }
예제 #13
0
 public static m4x4 Translation(v2 dxy, float dz)
 {
     return(Translation(new v4(dxy, dz, 1f)));
 }
예제 #14
0
 public m2x2(v2 x, v2 y) : this()
 {
     this.x = x;
     this.y = y;
 }
예제 #15
0
 public v4(v2 xy_, v2 zw_)
     : this()
 {
     xy = xy_;
     zw = zw_;
 }
예제 #16
0
 /// <summary>Increase the size of the bounding rect by 'delta'. i.e. grows by half 'delta' in each direction</summary>
 public BRect Inflate(v2 delta)
 {
     return(new BRect(m_centre, m_radius + delta / 2f));
 }
예제 #17
0
 /// <summary>Returns the bounding rectangle shifted by [dx,dy]</summary>
 public BRect Shifted(v2 offset)
 {
     return(new BRect(m_centre + offset, m_radius));
 }
예제 #18
0
 /// <summary>Returns true if 'point' is within this bounding rectangle (within 'tol'erance)</summary>
 public bool IsWithin(v2 point, float tol = 0f)
 {
     return
         (Math.Abs(point.x - m_centre.x) <= m_radius.x + tol &&
          Math.Abs(point.y - m_centre.y) <= m_radius.y + tol);
 }
예제 #19
0
 public void  set(v2 centre, v2 radius)
 {
     m_centre = centre; m_radius = radius;
 }
예제 #20
0
 // Constructors
 public BRect(v2 centre, v2 radius)
 {
     m_centre = centre; m_radius = radius;
 }
예제 #21
0
        public static bool Intersect(v2 a, v2 b, v2 c, v2 d)
        {
            v2 intersect;

            return(Intersect(a, b, c, d, out intersect));
        }
예제 #22
0
 public v3(v2 xy_, float z_)
     : this()
 {
     xy = xy_;
     z  = z_;
 }