# BUG : "Line Tangent Two Curves" not robust

Here’s a case of “Line Tangent Two Curves” playing with my nerves :

If there was a way to make it create the 4 possible lines, one could erase the un-wanted ones and move on whith his work.
This tool, along with “Line Tangent-Perpendicular”, and others are a mediocre excuse for not having proper dynamic sketch constraints in Rhino, but at least, they should be robust.

Hi Olivier -
I’m trying to reproduce that behavior here but am failing miserably. Would you be able to post those curves in a 3dm file?
-wim

``````from Rhino.Input.Custom import GetPoint
from Rhino.RhinoMath import Clamp
from Rhino.Commands import Result
from System.Drawing import Color
from scriptcontext import doc
import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
import math

class GeGuidePoint(GetPoint):
def __init__(self, lines):
self.m_lines = lines
self.line = rg.Line.Unset
def OnDynamicDraw(self, e):
ds = []
for line in self.m_lines:
ds.append(line.DistanceTo(e.CurrentPoint, True))
self.line = self.m_lines[ds.index(min(ds))]
e.Display.DrawLine(self.line, Color.White)

def circleGeometryFilter(rhObject, geometry, componentIndex):
return rs.coercecurve(geometry).TryGetCircle()[0]

def SolveTangents(cir0, cir1):
tangents = []
num1 = cir0.Center.DistanceTo(cir1.Center)
cir3.Center = rg.Point3d(num1, 0.0, 0.0)
num2 = math.acos(d)
tangents.append(rg.Line(cir2.PointAt(num2), cir3.PointAt(math.pi + num2)))
tangents.append(rg.Line(cir2.PointAt(-num2), cir3.PointAt(math.pi - num2)))
num2 = math.acos(d)
tangents.append(rg.Line(cir2.PointAt(math.pi - num2), cir3.PointAt(math.pi - num2)))
tangents.append(rg.Line(cir2.PointAt(math.pi + num2), cir3.PointAt(math.pi + num2)))
else:
num2 = math.acos(d)
tangents.append(rg.Line(cir2.PointAt(num2), cir3.PointAt(num2)))
tangents.append(rg.Line(cir2.PointAt(-num2), cir3.PointAt(-num2)))
if cir0.Plane != rg.Plane.WorldXY:
xform = rg.Transform.ChangeBasis(cir0.Plane, rg.Plane.WorldXY)
for tan in tangents:
tan.Transform(xform)
plane = cir0.Plane
rc, u, v = plane.ClosestParameter(cir1.Center)
if u != 0.0 or v != 0.0:
xform = rg.Transform.Rotation(math.atan2(v, u), cir0.Normal, cir0.Center)
for tan in tangents:
tan.Transform(xform)
return tangents

def RunCommand():
cir0id = rs.GetObject("Select first circle", rs.filter.curve, False, False, circleGeometryFilter)
if not cir0id: return
cir1id = rs.GetObject("Select second circle", rs.filter.curve, False, False, circleGeometryFilter)
if not cir1id: return
cir0 = rs.coercecurve(cir0id).TryGetCircle()[1]
cir1 = rs.coercecurve(cir1id).TryGetCircle()[1]
if cir0.Plane.DistanceTo(cir1.Center) > 0:
print "Input circles must be co-planar"
return
tangents = SolveTangents(cir0, cir1)
ggp = GeGuidePoint(tangents)
ggp.SetCommandPrompt("Guide point")
ggp.Get()
if ggp.CommandResult() <> Result.Success:
return ggp.CommandResult()
doc.Views.Redraw()

if __name__=="__main__":
RunCommand()
``````

CircleTangents.py (3.4 KB)

4 Likes

Lost it , sorry.

Anyways, I think that the erogonomy of Mahdiyar’s script is much better.
It might take one click more, but I like the visual interaction.