Skip to content

Instantly share code, notes, and snippets.

@jkrumbiegel
Created September 1, 2025 07:19
Show Gist options
  • Save jkrumbiegel/84a5f5b7f1ae8cd432cbb569c12b26e7 to your computer and use it in GitHub Desktop.
Save jkrumbiegel/84a5f5b7f1ae8cd432cbb569c12b26e7 to your computer and use it in GitHub Desktop.
Tangent lines two circles Makie projected
using LinearAlgebra
"""
outertangents(c1::Circle, c2::Circle) -> Vector{Tuple{Point2f, Point2f}}
Compute the outer tangent lines between two circles.
Returns a vector of two tuples, each containing two Point2f objects representing the endpoints of the outer tangent lines.
"""
function outertangents(c1, c2)
# Extract centers and radii
center1 = c1.center
center2 = c2.center
radius1 = c1.r
radius2 = c2.r
# Determine which is the bigger circle
big_center, big_radius, small_center, small_radius =
radius1 > radius2 ? (center1, radius1, center2, radius2) : (center2, radius2, center1, radius1)
radius_difference = big_radius - small_radius
# Vector from small to big circle center
center_diff = big_center - small_center
center_distance = norm(center_diff)
# Angle from small circle center to big circle center
gamma = -atan(center_diff[2], center_diff[1])
# Angle for tangent calculation
beta = asin(radius_difference / center_distance)
alpha1 = gamma - beta
alpha2 = gamma + beta
# Calculate tangent points on small circle
small_tangent_point_1 = small_center + Point2f(
small_radius * cos(pi / 2 - alpha1),
small_radius * sin(pi / 2 - alpha1)
)
small_tangent_point_2 = small_center + Point2f(
small_radius * cos(-pi / 2 - alpha2),
small_radius * sin(-pi / 2 - alpha2)
)
# Calculate tangent points on big circle
big_tangent_point_1 = big_center + Point2f(
big_radius * cos(pi / 2 - alpha1),
big_radius * sin(pi / 2 - alpha1)
)
big_tangent_point_2 = big_center + Point2f(
big_radius * cos(-pi / 2 - alpha2),
big_radius * sin(-pi / 2 - alpha2)
)
# Return tuples of tangent line endpoints
return [
(small_tangent_point_1, big_tangent_point_1),
(small_tangent_point_2, big_tangent_point_2)
]
end
f = Figure()
c1 = Observable(Circle(Point2f(0, 0), 50))
ax1 = Axis(f[1, 1], aspect = DataAspect())
poly!(ax1, c1, color = (:tomato, 0.3))
c2 = Observable(Circle(Point2f(0, 0), 10))
ax2 = Axis(f[2:3, 2:3], aspect = DataAspect())
poly!(ax2, c2, color = (:teal, 0.3))
c1_proj = lift(c1, ax1.scene.viewport, ax1.scene.camera.projectionview) do c1, _, _
center = Makie.shift_project(ax1.scene, c1.center)
# assume that the circle is actually a circle
point_on_circle = Makie.shift_project(ax1.scene, c1.center + Point(c1.r, 0))
r_proj = norm(center - point_on_circle)
Circle(Point(center), r_proj)
end
c2_proj = lift(c2, ax2.scene.viewport, ax2.scene.camera.projectionview) do c2, _, _
center = Makie.shift_project(ax2.scene, c2.center)
# assume that the circle is actually a circle
point_on_circle = Makie.shift_project(ax2.scene, c2.center + Point(c2.r, 0))
r_proj = norm(center - point_on_circle)
Circle(Point(center), r_proj)
end
tangents = lift(outertangents, c1_proj, c2_proj)
linesegments!(f.scene, tangents, color = :black, linestyle = :dash)
f
@jkrumbiegel
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment