Mi ricordavo anch’io quel metodo…
cmq… questo è un metodo puramente matematico, usando le equazioni del cerchio e della retta (tipo y=mx+k ecc ecc).
Ricordo di fare esercizi simili a mano su carta, alle medie, ma alla fine ho copiato (e modificato un po) una soluzione da stackexchange:
( la risposta di gboffi How to find the equation of a line, tangent to a circle, that passes through a given external point - Mathematics Stack Exchange )
c# circle point tangents.gh (6,1 KB)
Dato che gestire il cerchio e punto in 3d sarebbe stato inutilmente complicato, ho rimappato il punto sul piano del cerchio (tipo una proiezione), proceduto quindi come se il cerchio fosse centrato sull’origine (risparmiando quindi qualche addizione/sottrazione) , e generate le tangenti. Infine ri-mappate (orientate) le tangenti in 3d.
Nel caso che il punto sia sul cerchio, viene creata una linea tangente al cerchio passante per quel punto lunga come il diametro del cerchio…
Questo metodo proietta implicitamente il punto.
Se così non è voluto, basta aggiungere dopo il “RemapToPlaneSpace” questa riga:
if(Math.Abs(pt.Z)>t) return null;
Non conosco python, ma non dovrebbe essere troppo difficile tradurre il ““mio”” metodo da c# a py… il metodo originale di gboffi in effetti era già python…
private void RunScript(Circle C, Point3d P, ref object T)
{
T = PointCircleTangents(C, P);
}
// <Custom additional code>
public List<Line> PointCircleTangents(Rhino.Geometry.Circle C, Rhino.Geometry.Point3d P){
// code by gboffi from https://math.stackexchange.com/questions/543496/how-to-find-the-equation-of-a-line-tangent-to-a-circle-that-passes-through-a-g
double t = this.RhinoDocument.ModelAbsoluteTolerance;
Point3d pt;
Plane plane = C.Plane;
plane.RemapToPlaneSpace(P, out pt);
double r = C.Radius;
double px = pt.X;
double py = pt.Y;
double d = Math.Sqrt(px * px + py * py);
List<Line> tangents = new List<Line>();
if((r - d) > t) return null; // P inside C, no solutions!
double rho = r / d;
double ad = rho * rho;
double bd = rho * Math.Sqrt(1 - ad);
double T1x = ad * px + bd * (-py);
double T1y = ad * py + bd * (+px);
Rhino.Geometry.Transform reorient = Transform.PlaneToPlane(Rhino.Geometry.Plane.WorldXY, plane);
if((Math.Abs(r - d)) < t){ // P is on C, one solution!
Line T = new Line(T1x + T1y, T1y - T1x, 0, T1x - T1y, T1y + T1x, 0);
T.Transform(reorient);
tangents.Add(T);
}else{ // P is outside C, two solutions!
double T2x = ad * px - bd * (-py);
double T2y = ad * py - bd * (+px);
Line T1 = new Line(px, py, 0, T1x, T1y, 0);
Line T2 = new Line(px, py, 0, T2x, T2y, 0);
T1.Transform(reorient);
T2.Transform(reorient);
tangents.Add(T1);
tangents.Add(T2);
}
return tangents;
}