Пример #1
0
        /// <summary>
        /// Calculates the points of intersection between 2 CircleF objects</summary>
        /// <param name="c1">First CircleF</param>
        /// <param name="c2">Second CircleF</param>
        /// <param name="p1">First intersection point</param>
        /// <param name="p2">Second intersection point</param>
        /// <returns>True iff there are 1 or 2 intersection points; false if there are none or an infinite number</returns>
        public static bool Intersect(CircleF c1, CircleF c2, ref Vec2F p1, ref Vec2F p2)
        {
            Vec2F        v1  = c2.Center - c1.Center;
            double       d   = v1.Length;
            const double EPS = 1.0e-6;

            if (d < EPS ||
                d > c1.Radius + c2.Radius)
            {
                return(false);
            }

            v1 *= (float)(1 / d);
            Vec2F v2 = v1.Perp;

            double cos = (d * d + c1.Radius * c1.Radius - c2.Radius * c2.Radius) / (2 * c1.Radius * d);
            double sin = Math.Sqrt(1 - cos * cos);

            Vec2F t1 = Vec2F.Mul(v1, (float)(c1.Radius * cos));
            Vec2F t2 = Vec2F.Mul(v2, (float)(c1.Radius * sin));

            p1 = c1.Center + t1 + t2;
            p2 = c1.Center + t1 - t2;

            return(true);

            // From http://mathforum.org/library/drmath/view/51710.html
            // First, let C1 and C2 be the centers of the Circlefs with radii r1 and
            // r2, and let d be the distance between C1 and C2.
            //
            // Now let V1 be the unit vector from C1 to C2, and let V2 be the unit
            // vector perpendicular to V1.
            //
            // Also let V3 be the vector from C1 to one of the intersection points.
            //
            // Finally, let A be the angle between V1 and V3.
            //
            // From the law of cosines we know that
            //
            //         r2^2 = r1^2 + d^2 - 2*r1*d*cos(A)
            //
            // With this equation we can solve for 'A'.
            //
            // The intersection points will be
            //
            //         C1 + [r1*cos(A)]*V1 + [r1*sin(A)]*V2
            //
            //         C1 + [r1*cos(A)]*V1 - [r1*sin(A)]*V2

            // a simple unit test
            //            CircleF test1 = new CircleF(new Vec2F(-0.5f, 0), 1);
            //            CircleF test2 = new CircleF(new Vec2F(0.5f, 0), 1);
            //            Vec2F result1 = new Vec2F();
            //            Vec2F result2 = new Vec2F();
            //            CircleF.Intersect(test1, test2, ref result1, ref result2);
        }
Пример #2
0
        /// <summary>
        /// Picks the specified curve</summary>
        /// <param name="curve">Curve</param>
        /// <param name="p">Picking point</param>
        /// <param name="tolerance">Pick tolerance</param>
        /// <param name="hitPoint">Hit point</param>
        /// <returns>True if curve found; false otherwise</returns>
        public static bool Pick(BezierCurve2F curve, Vec2F p, float tolerance, ref Vec2F hitPoint)
        {
            Queue <BezierCurve2F> curves = new Queue <BezierCurve2F>();

            curves.Enqueue(curve);

            float dMin         = float.MaxValue;
            Vec2F closestPoint = new Vec2F();

            while (curves.Count > 0)
            {
                BezierCurve2F current = curves.Dequeue();

                // project p onto segment connecting curve endpoints
                Seg2F seg        = new Seg2F(current.P1, current.P4);
                Vec2F projection = Seg2F.Project(seg, p);
                float d          = Vec2F.Distance(p, projection);

                // reject - point not near enough to segment, expanded by curve "thickness"
                float flatness = current.Flatness;
                if (d - flatness > tolerance)
                {
                    continue;
                }

                // accept - point within tolerance of curve
                if (flatness <= tolerance)
                {
                    if (d < dMin)
                    {
                        dMin         = d;
                        closestPoint = projection;
                    }
                }
                else
                {
                    BezierCurve2F left, right;
                    current.Subdivide(0.5f, out left, out right);
                    curves.Enqueue(left);
                    curves.Enqueue(right);
                }
            }

            if (dMin < tolerance)
            {
                hitPoint = closestPoint;
                return(true);
            }

            return(false);
        }
Пример #3
0
        /// <summary>
        /// Projects a point onto a circle</summary>
        /// <param name="p">Point to project</param>
        /// <param name="c">Circle to project onto</param>
        /// <param name="projection">Projected point</param>
        /// <returns>True iff projection is well defined</returns>
        public static bool Project(Vec2F p, CircleF c, ref Vec2F projection)
        {
            Vec2F d           = Vec2F.Sub(p, c.Center);
            float length      = d.Length;
            bool  wellDefined = false;

            if (length > 0.000001f * c.Radius)
            {
                wellDefined = true;
                float scale = c.Radius / length;
                projection = Vec2F.Add(c.Center, Vec2F.Mul(d, scale));
            }
            return(wellDefined);
        }
Пример #4
0
        /// <summary>
        /// Determines if 2 rays intersect, and if so, returns the ray parameters of the intersection point</summary>
        /// <param name="r1">Ray 1</param>
        /// <param name="r2">Ray 2</param>
        /// <param name="t1">Returned ray parameter 1</param>
        /// <param name="t2">Returned ray parameter 2</param>
        /// <returns>True iff the rays intersect (are not parallel)</returns>
        public static bool Intersect(Ray2F r1, Ray2F r2, ref double t1, ref double t2)
        {
            double denom = (r2.Direction.Y * r1.Direction.X - r2.Direction.X * r1.Direction.Y);

            if (Math.Abs(denom) < 0.000001f)
            {
                return(false);
            }

            Vec2F d = Vec2F.Sub(r1.Origin, r2.Origin);

            t1 = (r2.Direction.X * d.Y - r2.Direction.Y * d.X) / denom;
            t2 = (r1.Direction.X * d.Y - r1.Direction.Y * d.X) / denom;
            return(true);
        }
Пример #5
0
        /// <summary>
        /// Evaluates the curve on parameter t [0,1]</summary>
        /// <param name="t">Parameter</param>
        /// <returns>Point on the curve at the given parameter</returns>
        public Vec2F Evaluate(float t)
        {
            // use de Casteljau constuction

            float oneMinusT = 1.0f - t;

            Vec2F s11 = P1 * oneMinusT + P2 * t;
            Vec2F s12 = P2 * oneMinusT + P3 * t;
            Vec2F s13 = P3 * oneMinusT + P4 * t;

            Vec2F s21 = s11 * oneMinusT + s12 * t;
            Vec2F s22 = s12 * oneMinusT + s13 * t;

            Vec2F s31 = s21 * oneMinusT + s22 * t;

            return(s31);
        }
Пример #6
0
        /// <summary>
        /// Extends box to contain the given point</summary>
        /// <param name="p">Point</param>
        /// <returns>Extended box</returns>
        public Box2F Extend(Vec2F p)
        {
            if (m_empty)
            {
                Min     = Max = p;
                m_empty = false;
            }
            else
            {
                Min.X = Math.Min(Min.X, p.X);
                Min.Y = Math.Min(Min.Y, p.Y);

                Max.X = Math.Max(Max.X, p.X);
                Max.Y = Math.Max(Max.Y, p.Y);
            }

            return(this);
        }
Пример #7
0
        /// <summary>
        /// Subdivides the Bezier curve into two equivalent Bezier curves</summary>
        /// <param name="t">Parameter of subdivision point</param>
        /// <param name="left">Left or "less than or equal to t" parameter side</param>
        /// <param name="right">Right or "greater than or equal to t" parameter side</param>
        public void Subdivide(float t, out BezierCurve2F left, out BezierCurve2F right)
        {
            // use de Casteljau constuction

            float oneMinusT = 1.0f - t;

            Vec2F s11 = P1 * oneMinusT + P2 * t;
            Vec2F s12 = P2 * oneMinusT + P3 * t;
            Vec2F s13 = P3 * oneMinusT + P4 * t;

            Vec2F s21 = s11 * oneMinusT + s12 * t;
            Vec2F s22 = s12 * oneMinusT + s13 * t;

            Vec2F s31 = s21 * oneMinusT + s22 * t;

            left  = new BezierCurve2F(P1, s11, s21, s31);
            right = new BezierCurve2F(s31, s22, s13, P4);
        }
Пример #8
0
        private static Vector2 FindIntersection2D(Vector2 ptA, float mA, Vector2 ptB, float mB)
        {
            // High School algebra alert!
            // ptA.Y = mA * ptA.X + cA
            // cA = ptA.Y - mA * ptA.X
            var cA = ptA.Y - mA * ptA.X;
            var cB = ptB.Y - mB * ptB.X;
            // y = mA * x + cA
            // y = mB * x + cB
            // mA * x + cA = mB * x + cB
            // x * (mA - mB) = cB - cA
            // x = (cB - cA) / (mA - mB)
            float x = (cB - cA) / (mA - mB);
            float y = mA * x + cA;

            System.Diagnostics.Debug.Assert(Math.Abs((mB * x + cB) - y) < 0.001f);
            return(new Vector2(x, y));
        }
Пример #9
0
        /// <summary>
        /// Constructs the circle containing 3 points</summary>
        /// <param name="p1">Point 1</param>
        /// <param name="p2">Point 2</param>
        /// <param name="p3">Point 3</param>
        public CircleF(Vec2F p1, Vec2F p2, Vec2F p3)
        {
            Vec2F  o1 = Vec2F.Add(p1, p2); o1 *= 0.5f;
            Vec2F  o2 = Vec2F.Add(p3, p2); o2 *= 0.5f;
            Vec2F  d1 = Vec2F.Sub(p2, p1); d1 = d1.Perp;
            Vec2F  d2 = Vec2F.Sub(p3, p2); d2 = d2.Perp;
            double t1 = 0;
            double t2 = 0;

            if (Ray2F.Intersect(new Ray2F(o1, d1), new Ray2F(o2, d2), ref t1, ref t2))
            {
                Center = o1 + d1 * (float)t1;
                Radius = Vec2F.Distance(Center, p1);
            }
            else
            {
                Center = new Vec2F(float.PositiveInfinity, float.PositiveInfinity);
                Radius = float.PositiveInfinity;
            }
        }
Пример #10
0
 /// <summary>
 /// Constructor with min and max</summary>
 /// <param name="min">Minima of extents</param>
 /// <param name="max">Maxima of extents</param>
 public Box2F(Vec2F min, Vec2F max)
 {
     Min     = min;
     Max     = max;
     m_empty = false;
 }
Пример #11
0
 /// <summary>
 /// Constructor</summary>
 /// <param name="origin">Ray origin</param>
 /// <param name="direction">Ray direction</param>
 public Ray2F(Vec2F origin, Vec2F direction)
 {
     Origin    = origin;
     Direction = direction;
 }
Пример #12
0
 private static Vector2 FindIntersection2D(Vector2 ptA, float mA, Vector2 ptB, float mB)
 {
     // High School algebra alert!
     // ptA.Y = mA * ptA.X + cA
     // cA = ptA.Y - mA * ptA.X
     var cA = ptA.Y - mA * ptA.X;
     var cB = ptB.Y - mB * ptB.X;
     // y = mA * x + cA
     // y = mB * x + cB
     // mA * x + cA = mB * x + cB
     // x * (mA - mB) = cB - cA
     // x = (cB - cA) / (mA - mB)
     float x = (cB - cA) / (mA - mB);
     float y = mA * x + cA;
     System.Diagnostics.Debug.Assert(Math.Abs((mB * x + cB) - y) < 0.001f);
     return new Vector2(x, y);
 }
Пример #13
0
 /// <summary>
 /// Constructor using end points</summary>
 /// <param name="p1">First endpoint</param>
 /// <param name="p2">Second endpoint</param>
 public Seg2F(Vec2F p1, Vec2F p2)
 {
     P1 = p1;
     P2 = p2;
 }
Пример #14
0
 /// <summary>
 /// Constructor using 2D vector</summary>
 /// <param name="v">2D vector</param>
 public Vec3F(Vec2F v)
 {
     X = v.X;
     Y = v.Y;
     Z = 1;
 }
Пример #15
0
        /// <summary>
        /// Determines if point is inside circle</summary>
        /// <param name="p">Point</param>
        /// <returns>True iff point is inside circle</returns>
        public bool Contains(Vec2F p)
        {
            Vec2F d = Vec2F.Sub(p, Center);

            return(d.LengthSquared < (Radius * Radius));
        }
Пример #16
0
 /// <summary>
 /// Constructor with center and radius</summary>
 /// <param name="center">Center point</param>
 /// <param name="radius">Radius</param>
 public CircleF(Vec2F center, float radius)
 {
     Center = center;
     Radius = radius;
 }