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)
cir2 = rg.Circle(rg.Plane.WorldXY, cir0.Radius)
cir3 = rg.Circle(rg.Plane.WorldXY, cir1.Radius)
cir3.Center = rg.Point3d(num1, 0.0, 0.0)
if cir0.Radius + cir1.Radius < num1:
d = Clamp((cir0.Radius + cir1.Radius) / num1, -1.0, 1.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)))
if num1 + cir0.Radius > cir1.Radius and num1 + cir1.Radius > cir0.Radius:
if abs(cir0.Radius - cir1.Radius) < 1E-09:
tangents.append(rg.Line(0.0, cir0.Radius, 0.0, num1, cir1.Radius, 0.0))
tangents.append(rg.Line(0.0, -cir0.Radius, 0.0, num1, -cir1.Radius, 0.0))
elif cir0.Radius < cir1.Radius:
d = Clamp((cir1.Radius - cir0.Radius) / num1, -1.0, 1.0)
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:
d = Clamp((cir0.Radius - cir1.Radius) / num1, -1.0, 1.0)
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.Objects.AddLine(ggp.line)
doc.Views.Redraw()
if __name__=="__main__":
RunCommand()
CircleTangents.py (3.4 KB)