Punto con tangenza su cerchio

giusto per essere sicuro, sto scrivendo uno script per trovare la tangenza di un cerchio da un punto

in Gh c’è un componente preposto, in Py sto notando che fare tutti i passaggi matematici/geometrici

è un bello intreccio (sto quasi alla fine) mi chiedo se per caso come Gh non esista una funzione?

Ciao Salvio

( Suppongo che la tangente in questione sia una retta )

Non trovo niente di gia’ pronto,
ma ho provato a cercare un modo (tra i tanti) per ricavare le rette, usando solo
rhinoscriptsyntax e/o RhinoCommon, a scelta … :grinning:
… Tanto per cercare di dipanare l’intreccio … :wink:

Vedi tu se la procedura funziona o meno … io ho solo fatto uno schizzo su Rhino. :wink:

L’idea e’ ricavare la distanza tra punto esterno e punto di tangenza,
in modo da poter disegnare un cerchio ausiliario per intersecare il nostro cerchio
e ricavare cosi’ i punti di tangenza.

Il nostro cerchio, chiamiamolo ‘C1’, ha centro ‘A’ e raggio ‘R1’
Il punto esterno lo chiamiamo ‘B’
Ricaviamo la distanza tra ‘A’ e ‘B’ e la chiamiamo ‘R2’

Ora facciamo una piccola costruzione per ricavare, come detto, la distanza tra punto esterno
e punto di tangenza:

Disegniamo ‘C1’ centrato sull’origine.
Disegniamo un altro cerchio, sempre sull’origine, di raggio ‘R2’, lo chiamiamo ‘C2’
Il punto ‘C’ e’ l’intersezione tra asse Y e ‘C1’
Disegniamo una retta orizzontale passante per ‘C’, la chiamiamo ‘L’
Il punto ‘B’ e’ l’intersezione tra ‘C2’ ed ‘L’
La distanza tra ‘C’ e ‘B’ la chiamiamo ‘R3’
… E’ quella che stavamo cercando. :slight_smile:

( In pratica, nello script, credo basti disegnare/definire ‘C2’ ed ‘L’ e intersecare
‘R3’ e’ la X del punto di intersezione )

Conoscendo ‘R3’, puoi disegnare un cerchio centrato sul tuo punto esterno, di raggio ‘R3’
e intersecare il tuo cerchio (nella costruzione e’ ‘C3’ )
I 2 punti di intersezione, uniti al punto esterno, definiscono le 2 rette tangenti.

… Se ho detto cavolate, avvisami … :confused:

Emilioooooooooooooooooooooo

:exploding_head: :exploding_head: :exploding_head:

non saprei :sweat_smile: :rofl: :joy:

io ero rimasto al metodo: metà distanza tra centro cerchio ed il punto
creare un cerchio con il raggio della stessa distanza indicata sopra
e l’intersezioni tra i due cerchi indicano le tangenze col punto
“sembra” che in questo modo lo script trovi le tangenze

spero che non sbaglio nulla :wink:

ps quindi deduco che una funzione specifica nada. . . .

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…

:laughing:

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;
  }
1 Mi Piace

OK Emilio, Riccardo :+1:

Ciao

condivido altra soluzione ma più compatta senza l’ausilio di rhino.

Option Explicit
Call Main()
Sub Main()

	Dim IDC: IDC = rhino.GetObject("Select circle", 4)
	If isnull(IDC) Then Exit Sub
	If rhino.IsCircle(IDC) = False Then
		rhino.Print "The curve is not a circle."
		Exit Sub
	End If
	
	Dim PT: PT = rhino.GetPoint("pick a point")
	If Not isarray(PT) Then Exit Sub
	
	Dim CP: CP = Rhino.CircleCenterPoint(IDC)
	Dim R: R = Rhino.CircleRadius(IDC)
	
	Dim D: D = ((CP(0) - PT(0)) ^ 2 + (CP(1) - PT(1)) ^ 2 + (CP(2) - PT(2)) ^ 2) ^ 0.5

	If D <= R Then
		rhino.Print "The point is inside the cirlce!"
		Exit Sub
	End If
	
	Dim L: L = (D ^ 2 - R ^ 2) ^ 0.5
	
	Dim V: V = array((PT(0) - CP(0)) / D, (PT(1) - CP(1)) / D, (PT(2) - CP(2)) / D)
	
	Dim N: N = R * L / D
	Dim D1: D1 = (R ^ 2 - N ^ 2) ^ 0.5
	
	Dim P1: P1 = array(CP(0) + D1 * V(0) - N * V(1), CP(1) + D1 * V(1) + N * V(0), 0.0)
	Dim P2: P2 = array(CP(0) + D1 * V(0) + N * V(1), CP(1) + D1 * V(1) - N * V(0), 0.0)
	
	rhino.AddPoint PT
	rhino.AddLine PT, P1
	rhino.AddLine PT, P2
	
End Sub

3 Mi Piace

ciao Sergio, grazie per il codice :+1:
ho provato e funziona perfettamente,

con le soluzioni geometriche mettendomi d’impegno cerco di farcela,
con quelle matematiche anche volendo ma non’é proprio per me,
però, debbo dire che il modo analitico è molto affascinante.