Tangent lines between two circles (curves)

I am looking for a method to detect tangent lines between two circles, i.e. to obtain the tangent lines which ‘TanIn’ and ‘TanEx’ provide. Is it exist at all or maybe there is a snippet of code for that?

Hi @sadovshikov,

See if Line.TryCreateBetweenCurves gets you anywhere.

– Dale

3 Likes

Or this:

and this:

_
c.

1 Like

Hi @dale,

the help doc for Line.TryCreateBetweenCurves() seems to be slightly incorrect. At least using Python, the method outputs a tuple of 4 values on success, the result as boolean, first crv parameter, second crv parameter and the line.

_
c.

Hi @clement,

The docs are correct. Arguments “by ref” are a pain.

import Rhino.Geometry as rg
import scriptcontext as sc

def test_clement():
    plane = rg.Plane.WorldXY
    cir0 = rg.Circle(plane, 5.0)
    crv0 = rg.ArcCurve(cir0)
    
    plane.Origin = rg.Point3d(10, 5, 0)
    cir1 = rg.Circle(plane, 5.0)
    crv1 = rg.ArcCurve(cir1)
    
    rc, pt0, pt1 = crv0.ClosestPoints(crv1)
    if not rc:
        return
    
    rc, s0 = crv0.ClosestPoint(pt0)
    rc, s1 = crv1.ClosestPoint(pt1)
    
    rc, t0, t1, line = rg.Line.TryCreateBetweenCurves(crv0, crv1, s0, s1, False, False)
    if rc and line:
        sc.doc.Objects.AddCurve(crv0)
        sc.doc.Objects.AddCurve(crv1)
        sc.doc.Objects.AddPoint(pt0)
        sc.doc.Objects.AddPoint(pt1)
        sc.doc.Objects.AddLine(line)
        sc.doc.Views.Redraw()

if __name__ == "__main__":
    test_clement()

– Dale

ok, somehow i knew this is a Python only thing. But on the other hand, it would be more confusing to me if the input seed values passed to the method become the solution values without returning them seperately.

thanks,
c.

Interesting solution, thank you!

Well, almost… there does appear to be a copy/paste error in there.

1 Like

Hi @sadovshikov,

i’ve tried some of the online examples but since they all are 2D i wrote below which works 3D and limits the creation to the 2 outer tangents using Line.TryCreateBetweenCurves() method:

TangentLinesBetweenTwoCircles.py (3.3 KB)

_
c.

1 Like

Terrific, I’ll give your script a shot!

a (fast) 2d only solution in c#
might be spiced up with more error checking - but my problem is 2d - only…

based on this article

public class LineABC
{
    public double A { get; set; }
    public double B { get; set; }
    public double C { get; set; }

    public LineABC(double a, double b, double c)
    {
        A = a;
        B = b;
        C = c;
    }
    public Line ToLine()
    {
        // To find two points on the line ax + by + c = 0, we can choose arbitrary x or y values and solve for the other variable.
        Point3d pointA;
        Point3d pointB;

        if (B != 0)
        {
            pointA = new Point3d(0, -C / B,0);  // y-intercept
            pointB = new Point3d(1, -(A + C) / B,0);  // Point for x = 1
        }
        else if (A != 0)
        {
            pointA = new Point3d(-C / A, 0,0);  // x-intercept
            pointB = new Point3d(-(B + C) / A, 1,0);  // Point for y = 1
        }
        else
        {
            throw new InvalidOperationException("Invalid line equation.");
        }

        return new Line(pointA,pointB);
    }
    public override string ToString()
    {
        return $"{A}x + {B}y + {C} = 0";
    }
}

public class CircleTangentCalculator
{
    public static Line[] CommonTangentLine(Circle circA, Circle circB)
    {
        LineABC[] linesABC = CommonTangentLine(circA.Center.X,circA.Center.Y,circA.Radius,circB.Center.X,circB.Center.Y,circB.Radius);
        List<Line> lines = new List<Line>(4);
        foreach ( LineABC lineABCi in linesABC)
        {
            lines.Add(lineABCi.ToLine());
        }
        return lines.ToArray();
    }
    public static LineABC[] CommonTangentLine(double x1, double y1, double r1, double x2, double y2, double r2)
    {
        // Compute the common tangent line of two circles: (x1, y1) - r1 and (x2, y2) - r2
        // Return in the form of line equation: ax + by + c == 0

        double delta1 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) - (r1 + r2) * (r1 + r2);
        double delta2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) - (r1 - r2) * (r1 - r2);
        double p1 = r1 * (x1 * x2 + y1 * y2 - x2 * x2 - y2 * y2);
        double p2 = r2 * (x1 * x1 + y1 * y1 - x1 * x2 - y1 * y2);
        double q = x1 * y2 - x2 * y1;
        List<LineABC> results = new List<LineABC>();

        if (delta1 >= 0)
        {
            LineABC l11 = new LineABC(
                (x2 - x1) * (r1 + r2) + (y1 - y2) * Math.Sqrt(delta1),
                (y2 - y1) * (r1 + r2) + (x2 - x1) * Math.Sqrt(delta1),
                p1 + p2 + q * Math.Sqrt(delta1)
            );

            LineABC l12 = new LineABC(
                (x2 - x1) * (r1 + r2) - (y1 - y2) * Math.Sqrt(delta1),
                (y2 - y1) * (r1 + r2) - (x2 - x1) * Math.Sqrt(delta1),
                p1 + p2 - q * Math.Sqrt(delta1)
            );

            results.Add(l11);
            results.Add(l12);
        }

        if (delta2 >= 0)
        {
            LineABC l21 = new LineABC(
                (x2 - x1) * (r1 - r2) + (y1 - y2) * Math.Sqrt(delta2),
                (y2 - y1) * (r1 - r2) + (x2 - x1) * Math.Sqrt(delta2),
                p1 - p2 + q * Math.Sqrt(delta2)
            );

            LineABC l22 = new LineABC(
                (x2 - x1) * (r1 - r2) - (y1 - y2) * Math.Sqrt(delta2),
                (y2 - y1) * (r1 - r2) - (x2 - x1) * Math.Sqrt(delta2),
                p1 - p2 - q * Math.Sqrt(delta2)
            );

            results.Add(l21);
            results.Add(l22);
        }
        return results.ToArray();
    }
}
1 Like