Example #1
0
        /// <summary>
        /// Returns an array of two points, or null if tangent not possible.
        /// Never returns a single point, even if booth points are equal.
        /// </summary>
        public static Point2d[] CirclePoint(Circle2d ci, Point2d pt)
        {
            Circle2d tc = Circle2d.From2Points(ci.Center, pt);

            Point2d[] pts = Intersect2d.CircleCircle(tc, ci);
            if (pts == null)
            {
                return(null);
            }
            if (pts.Length == 1)
            {
                Array.Resize(ref pts, 2); pts[1] = pts[0];
            }
            return(pts);
        }
Example #2
0
        public static Circle2d[] CirclePointPoint(Circle2d ci, Point2d pt1, Point2d pt2)
        {
            // Solution by Robert.P. 2013-02-10
            // solved by intersecting the line which has equal distance to pt1 and pt2 at every point,
            // with the hyperbola that has equal distance to ci and pt1 at every point.


            List <Circle2d> res = null;

            //get squared constants of hyperbola
            double c2 = ci.Center.SquaredDistance(pt1) / 4.0; //center->focus distance squared

            double a = 0.5 * ci.Radius;
            double b = Math.Sqrt(c2 - a * a);

            if (double.IsNaN(b))
            {
                return(null);    //negative square root, no such hyperbola
            }
            // this hyperbola has equal distance to ci and pt1 at every point.
            // it also has focus at ci.Center and pt1
            Hyperbola2d hyper = new Hyperbola2d(new Point2d((ci.X + pt1.X) * 0.5, (ci.Y + pt1.Y) * 0.5), a, b, ci.Center.Angle(pt1));

            //get constants of line dx+ey+f=0, which is equal distance from p1,p2 on every point
            double dx = pt2.X - pt1.X, dy = pt2.Y - pt1.Y;
            double mx   = pt1.X + dx * 0.5;
            double my   = pt1.Y + dy * 0.5;
            Line2d perp = new Line2d(mx, my, mx - dy, my + dx);    //starts from mipoint pt1-pt2 and is perpendicular to that line

            var intpts = Intersect2d.HyperbolaLine(hyper, perp);

            if (intpts == null)
            {
                return(null);
            }

            foreach (Point2d intpt in intpts)
            {
                AddResult(ref res, intpt.X, intpt.Y, intpt.Distance(pt1));
            }

            return(MakeResult(res));
        }
Example #3
0
        public static Circle2d[] LineLinePoint(Line2d lin1, Line2d lin2, Point2d pnt)
        {
            // Compute the 2 circles (or 1 in special cases) that tangents two lines and a point.
            // Solving for parameter t on the bisector vector between lines that have the same
            // distance to point as the radius for that t (given using radfac computed below)
            // Solution by Robert.P. 2013-02-14

            List <Circle2d> res = null;

            Vector2d v1 = lin1.Direction;
            Vector2d v2 = lin2.Direction;
            Vector2d midvec;
            Point2d  linint;

            double[] ts;



            linint = Intersect2d.LineLineAsPoint(lin1, lin2); //basepoint for midline vector

            if (linint == null)                               //special case for parallel lines
            {
                //use vector and base point on midpoint of radical line of circles
                midvec = v1;
                Line2d radlin = new Line2d(lin1.ClosestPoint(pnt), lin2.ClosestPoint(pnt));
                linint = radlin.MidPoint;
                double r = radlin.Length * 0.5, i = pnt.X, j = pnt.Y, x0 = linint.X, y0 = linint.Y, dx = midvec.X, dy = midvec.Y;

                double tp2 = 1; //squared length of midlin => assume normalized
                double tp1 = 2 * (dy * y0 + dx * x0 - dy * j - dx * i);
                double tp0 = y0 * y0 - 2 * j * y0 - r * r + j * j + i * i + x0 * x0 - 2 * i * x0;

                ts = RealPolynomial.SolveQuadric(tp2, tp1, tp0, 0.0);
                if (ts == null)
                {
                    return(null);
                }

                foreach (double t in ts)
                {
                    Point2d center = linint + midvec * t;
                    AddResult(ref res, center.X, center.Y, r);
                }
            }
            else //normal case with non-parallel lines
            {
                if (pnt.Location(lin1.Start, lin1.End) == pnt.Location(lin2.Start, lin2.End))
                {
                    v2 = -v2;   //select correct bisector out of two (actually 4 but it does not matter if we solve for negative t)
                }
                midvec = v1.Bisect(v2);
                double radfac = Math.Sin(v1.AngleTo(v2) / 2.0); //multiplied with midvector t this gives radius of circle at that t

                //solve problem in space where pnt=origo
                Point2d org = new Point2d(linint.X - pnt.X, linint.Y - pnt.Y);
                double  t2  = -radfac * radfac + 1; //// 1 for squared length of midlin => assume normalized
                double  t1  = 2 * (midvec.Y * org.Y + midvec.X * org.X);
                double  t0  = org.X * org.X + org.Y * org.Y;
                ts = RealPolynomial.SolveQuadric(t2, t1, t0, 0.0);

                if (ts == null)
                {
                    return(null);
                }

                foreach (double t in ts)
                {
                    Point2d center = linint + midvec * t;
                    AddResult(ref res, center.X, center.Y, Math.Abs(t * radfac));
                }
            }

            return(MakeResult(res));
        }