/// <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); }
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)); }
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)); }