Tangents to circle from point and intersection line/circle

I am trying to create an animation showing a collision avoidance system. To do it, I need to find and display the evasion courses at every point in the animation. For that reason, I would like to have, if possible, the logic encapsulated in a single C# component.

The procedure is straightforward geometrically. It is shown in the following diagram:

In essence, you need to find the two tangents from the target to a circle that represents the minimum desired distance centered on our ship. Then determine the intersection of these tangent lines with a circle that has as a radius our ship’s speed and is placed at the end point of the target ship velocity vector.

I have not been able to find suitable RhinoCommon functions, and my analytic geometry skills are not what they used to be.

Any tips will be most welcomed.

You can find the tangent points by constructing a circle with diameter (ship position, target position) and intersecting it with your minimum distance circle.

Circle intersection algorithm here

Here’s how I would do it in Python using the rhinoscriptsyntax methods for curve intersection.

import Rhino
import rhinoscriptsyntax as rs

target_start = Rhino.Geometry.Point3d(T0)
target_end = Rhino.Geometry.Point3d(T1)
self_start = Rhino.Geometry.Point3d(S0)
self_end = Rhino.Geometry.Point3d(S1)
min_distance = float(D)

def curve_intersection(curve1, curve2):
    results = rs.CurveCurveIntersection(curve1, curve2)
    points = []
    for result in results:
        event, location = result[:2]
        if event == 1: points.append(location)
    return points

circle_distance = rs.AddCircle(self_start, min_distance)
midpoint = (self_start + target_start)/2
separation = self_start.DistanceTo(target_start)
circle_separation = rs.AddCircle(midpoint, separation/2)
tangent_points = curve_intersection(circle_distance, circle_separation)
tangent_lines = [rs.AddLine(target_start, Rhino.Geometry.Point3d(pt)) for pt in tangent_points]
self_speed = self_start.DistanceTo(self_end)
circle_speed = rs.AddCircle(target_end, self_speed)
intersect_points = sum([curve_intersection(circle_speed, line) for line in tangent_lines], start=[])
evasion_points = sorted(intersect_points, key=lambda pt: pt.DistanceTo(self_start))[:2]
evasion_points = [self_start + target_end - pt for pt in evasion_points]

EP = evasion_points

rhinocommon has a lot of intersection methods

https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.intersect.intersection

you might use curve-curve intersection or Circle Circle
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.intersect.intersection/circlecircle

there is also
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.intersect.intersection/linecircle

note the speciality of line parameters
t Type: double
Parameter to evaluate line segment at. Line parameters are normalized parameters.
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.line/pointat#(double)

the rs. … commands that are used by @Measure will (and need) RhinoObjects being added to the document. This is not nice in a Gh-component.
if you really want to use this approach, make sure to delete the objects after the solution is computed.

for the initial tangents there is:
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.curve/getlocaltangentpoint

don’t forget at the beginning of your scipt to check that the setup is planar.

hope above or Meassure’s post help as a starting point - feel free to post some code or gh-definition to get further feedback.

happy coding - kind regards -tom

@Measure
Thank you very much for your code. It works beautifully!

Now, all I need to do is to translate it to C# and incorporate it to my solution.

Tom,

Thank you very much for your information. Actually, I already solved myself the first part of the problem, get the tangents to a circle through a point, using simple trigonometry.

In case someone is interested, here is the solution to find the tangents to a circle from an external point:

        // Tangents
        Double Theta = Math.Asin(minDist / dist);
        Double tanDist = Math.Sqrt(dist * dist - minDist * minDist);
        Vector3d v1 = ownOrig - tgtOrig;
        v1.Unitize();
        v1.Rotate(Theta, -Vector3d.ZAxis);
        Line tangent1 = new Line(tgtOrig, tgtOrig + v1 * tanDist);

        Vector3d v2 = ownOrig - tgtOrig;
        v2.Unitize();
        v2.Rotate(-Theta, -Vector3d.ZAxis);
        Line tangent2 = new Line(tgtOrig, tgtOrig + v2 * tanDist);

It is really straight forward and gives very good results. Actually, this was my first intuition, but I made a mistake in my first implementation, and discarded the method before posting my question.

Finally, the implementation of the intersection between the circle and the two tangent lines is similarly easy:

        Circle velCircle = new Circle(tgtVel, ownSpeed / 15);
        circles.Add(velCircle);
        Double t1, t2;
        Point3d p1, p2, p3, p4;
        Rhino.Geometry.Intersect.Intersection.LineCircle(tangent1, velCircle, 
            out t1, out p1, out t2, out p2);

        Rhino.Geometry.Intersect.Intersection.LineCircle(tangent2, velCircle, 
            out t1, out p3, out t2, out p4);