Finding the tangent points of a circle

Just starting out? Need help? Post your questions and find answers here.
Justin
Addict
Addict
Posts: 956
Joined: Sat Apr 26, 2003 2:49 pm

Finding the tangent points of a circle

Post by Justin »

I need to find the 2 tangent points of 2 intersecting lines to a circle as shown in the image.
I had to use chatgpt because i could not do it. The following code draws the circle at the correct position you can increase or decrease the radius pressing up and down keys.
How to find the tangent points marked in the image?
Image

Code: Select all

EnableExplicit

Structure PointD
	x.d
	y.d
EndStructure

Global.d g_radius
Global.PointD g_intersection, g_endPoint1, g_endPoint2

;TODO 
Procedure findTangentPoint(*intersection.PointD, *endPoint.PointD, *circleCenter.PointD, radius.d, *outTangentPoint.PointD)

EndProcedure

Procedure drawCircle(*intersection.PointD, *endPoint1.PointD, *endPoint2.PointD, radius.d)
	Protected.d angle1, angle2, bisectorAngle, angleDifference, distance
	Protected.PointD circleCenter
	
	;Calculate the angles formed by the lines With respect To the intersection point
	angle1 = ATan2(*endPoint1\x - *intersection\x, *endPoint1\y - *intersection\y)
	angle2 = ATan2(*endPoint2\x - *intersection\x, *endPoint2\y - *intersection\y)

	;Find the bisector of the angle formed by the two lines
	bisectorAngle = (angle1 + angle2) / 2.0
	
	;Calculate the distance from the intersection point To the point where the circle is tangent To both lines
	angleDifference = Abs(angle1 - angle2)
	If angleDifference > #PI
		angleDifference = 2 * #PI - angleDifference
	EndIf
	
	distance = radius / Sin(angleDifference / 2.0)
	
	;Find the center of the circle using the bisector angle And the calculated distance
	circleCenter\x = *intersection\x + distance * Cos(bisectorAngle)
	circleCenter\y = *intersection\y + distance * Sin(bisectorAngle)

	AddPathCircle(circleCenter\x, circleCenter\y, radius)
	
	;TODO FIND TANGENT POINTS
	Protected.PointD tangentPoint1, tangentPoint2
	findTangentPoint(*intersection, *endPoint1, @circleCenter, radius, @tangentPoint1)
	findTangentPoint(*intersection, *endPoint2, @circleCenter, radius, @tangentPoint2)
EndProcedure

Procedure drawCanvas(*intersection.PointD, *endPoint1.PointD, *endPoint2.PointD, radius.d)
	StartVectorDrawing(CanvasVectorOutput(0))	
	;Clear
	VectorSourceColor(RGBA(255, 255, 255, 255))	
	FillVectorOutput()
	
	VectorSourceColor(RGBA(0, 0, 255, 255))	
		
	;Lines
	MovePathCursor(*intersection\x, *intersection\y)
	AddPathLine(*endPoint1\x, *endPoint1\y)

	MovePathCursor(*intersection\x, *intersection\y)
	AddPathLine(*endPoint2\x, *endPoint2\y)

	StrokePath(4)
	
	;Circle
	VectorSourceColor(RGBA(255, 0, 0, 255))	
	drawCircle(*intersection, *endPoint1, *endPoint2, radius)

	StrokePath(4)
	StopVectorDrawing()
EndProcedure

Procedure onKeyDown()
	If GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_Up
		g_radius + 1.0
		drawCanvas(@g_intersection, @g_endPoint1, @g_endPoint2, g_radius)

	ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_Down
		g_radius - 1.0
		If g_radius < 0
			g_radius = 1
		EndIf
		drawCanvas(@g_intersection, @g_endPoint1, @g_endPoint2, g_radius)
	EndIf 
EndProcedure

Procedure main()
	Protected.l ev
	Protected.PointD intersection, endPoint1, endPoint2
	
	g_radius = DesktopScaledX(40)
	g_intersection\x = DesktopScaledX(400)
	g_intersection\y = DesktopScaledY(300)
	g_endPoint1\x = DesktopScaledX(500)
	g_endPoint1\y = DesktopScaledY(10)

	g_endPoint2\x = DesktopScaledX(600)
	g_endPoint2\y = DesktopScaledY(200)
	
	OpenWindow(0, 0, 0, 800, 600, "VectorDrawing", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	CanvasGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), #PB_Canvas_Keyboard)
	BindGadgetEvent(0, @onKeyDown(), #PB_EventType_KeyDown)
	
	drawCanvas(@g_intersection, @g_endPoint1, @g_endPoint2, g_radius)
	
	SetActiveGadget(0)
	
	Repeat
		ev = WaitWindowEvent()
	Until ev = #PB_Event_CloseWindow
EndProcedure

main()
infratec
Always Here
Always Here
Posts: 7662
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Finding the tangent points of a circle

Post by infratec »

firace
Addict
Addict
Posts: 947
Joined: Wed Nov 09, 2011 8:58 am

Re: Finding the tangent points of a circle

Post by firace »

IMHO the top answer by Rory Daulton seems to be the easiest to implement in PB:

https://stackoverflow.com/questions/499 ... om-a-point
infratec
Always Here
Always Here
Posts: 7662
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Finding the tangent points of a circle

Post by infratec »

https://stackoverflow.com/questions/499 ... om-a-point

Code: Select all

Procedure findTangentPoint(*intersection.PointD, *circleCenter.PointD, radius.d, *outTangentPoint1.PointD, *outTangentPoint2.PointD)
  
  Protected.d b, th, d, d1, d2
  
  
  b = Sqr(((*intersection\x - *circleCenter\x) * (*intersection\x - *circleCenter\x)) + ((*intersection\y - *circleCenter\y) * (*intersection\y - *circleCenter\y)))
  th = ACos(radius / b)
  d = ATan2(*intersection\x - *circleCenter\x, *intersection\y - *circleCenter\y)
  d1 = d + th
  d2 = d - th
  
  *outTangentPoint1\x = *circleCenter\x + radius * Cos(d1)
  *outTangentPoint1\y = *circleCenter\y + radius * Sin(d1)
  
  *outTangentPoint2\x = *circleCenter\x + radius * Cos(d2)
  *outTangentPoint2\y = *circleCenter\y + radius * Sin(d2)
  
EndProcedure

Procedure drawCircle(*intersection.PointD, *endPoint1.PointD, *endPoint2.PointD, radius.d)
	Protected.d angle1, angle2, bisectorAngle, angleDifference, distance
	Protected.PointD circleCenter
	
	;Calculate the angles formed by the lines With respect To the intersection point
	angle1 = ATan2(*endPoint1\x - *intersection\x, *endPoint1\y - *intersection\y)
	angle2 = ATan2(*endPoint2\x - *intersection\x, *endPoint2\y - *intersection\y)

	;Find the bisector of the angle formed by the two lines
	bisectorAngle = (angle1 + angle2) / 2.0
	
	;Calculate the distance from the intersection point To the point where the circle is tangent To both lines
	angleDifference = Abs(angle1 - angle2)
	If angleDifference > #PI
		angleDifference = 2 * #PI - angleDifference
	EndIf
	
	distance = radius / Sin(angleDifference / 2.0)
	
	;Find the center of the circle using the bisector angle And the calculated distance
	circleCenter\x = *intersection\x + distance * Cos(bisectorAngle)
	circleCenter\y = *intersection\y + distance * Sin(bisectorAngle)

	AddPathCircle(circleCenter\x, circleCenter\y, radius)
	
	StrokePath(4)
	
	
	
	;TODO FIND TANGENT POINTS
	Protected.PointD tangentPoint1, tangentPoint2
	findTangentPoint(*intersection, @circleCenter, radius, @tangentPoint1, @tangentPoint2)
	
	VectorSourceColor(RGBA(0, 0, 0, 255))
	
	AddPathCircle(tangentPoint1\x, tangentPoint1\y, 8)
	AddPathCircle(tangentPoint2\x, tangentPoint2\y, 8)
	
EndProcedure
Justin
Addict
Addict
Posts: 956
Joined: Sat Apr 26, 2003 2:49 pm

Re: Finding the tangent points of a circle

Post by Justin »

Hi infratec,

i did the same with firace's link, it was very helpful.
Thanks to both!
Complete code here:

Code: Select all

EnableExplicit

Structure PointD
	x.d
	y.d
EndStructure

Global.d g_radius
Global.PointD g_intersection, g_endPoint1, g_endPoint2

;distance : distance from circle center and intersection point
;ref : https://stackoverflow.com/questions/49968720/find-tangent-points-in-a-circle-from-a-point
Procedure findTangentPoints(*intersection.PointD, *circleCenter.PointD, radius.d, distance.d, *outTangentPoint1.PointD, *outTangentPoint2.PointD)
	Protected.d d2, th, d, d1
	Protected.PointD tangentPoint1, tangentPoint2

	th = ACos(radius / distance) ;angle theta
	d = ATan2(*intersection\x - *circleCenter\x, *intersection\y - *circleCenter\y) ;direction angle of point P from C
	d1 = d + th ;direction angle of point T1 from C
	d2 = d - th ;direction angle of point T2 from C
	
	*outTangentPoint1\x = *circleCenter\x + radius * Cos(d1)
	*outTangentPoint1\y = *circleCenter\y + radius * Sin(d1)
	
	*outTangentPoint2\x = *circleCenter\x + radius * Cos(d2)
	*outTangentPoint2\y = *circleCenter\y + radius * Sin(d2)
EndProcedure

Procedure drawCircle(*intersection.PointD, *endPoint1.PointD, *endPoint2.PointD, radius.d)
	Protected.d angle1, angle2, bisectorAngle, angleDifference, distance
	Protected.PointD circleCenter
	Protected.PointD tangentPoint1, tangentPoint2

	;Calculate the angles formed by the lines With respect To the intersection point
	angle1 = ATan2(*endPoint1\x - *intersection\x, *endPoint1\y - *intersection\y)
	angle2 = ATan2(*endPoint2\x - *intersection\x, *endPoint2\y - *intersection\y)

	;Find the bisector of the angle formed by the two lines
	bisectorAngle = (angle1 + angle2) / 2.0
	
	;Calculate the distance from the intersection point To the point where the circle is tangent To both lines
	angleDifference = Abs(angle1 - angle2)
	If angleDifference > #PI
		angleDifference = 2 * #PI - angleDifference
	EndIf
	
	distance = radius / Sin(angleDifference / 2.0)
	
	;Find the center of the circle using the bisector angle And the calculated distance
	circleCenter\x = *intersection\x + distance * Cos(bisectorAngle)
	circleCenter\y = *intersection\y + distance * Sin(bisectorAngle)
	
	AddPathCircle(circleCenter\x, circleCenter\y, radius)
	
	findTangentPoints(*intersection, @circleCenter, radius, distance, @tangentPoint1, @tangentPoint2)
	AddPathCircle(tangentPoint1\x, tangentPoint1\y, 4)
	AddPathCircle(tangentPoint2\x, tangentPoint2\y, 4)
EndProcedure

Procedure drawCanvas(*intersection.PointD, *endPoint1.PointD, *endPoint2.PointD, radius.d)
	StartVectorDrawing(CanvasVectorOutput(0))	
	;Clear
	VectorSourceColor(RGBA(255, 255, 255, 255))	
	FillVectorOutput()
	
	VectorSourceColor(RGBA(0, 0, 255, 255))	
		
	;Lines
	MovePathCursor(*intersection\x, *intersection\y)
	AddPathLine(*endPoint1\x, *endPoint1\y)

	MovePathCursor(*intersection\x, *intersection\y)
	AddPathLine(*endPoint2\x, *endPoint2\y)

	StrokePath(4)
	
	;Circle
	VectorSourceColor(RGBA(255, 0, 0, 255))	
	drawCircle(*intersection, *endPoint1, *endPoint2, radius)

	StrokePath(4)
	StopVectorDrawing()
EndProcedure

Procedure onKeyDown()
	If GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_Up
		g_radius + 1.0
		drawCanvas(@g_intersection, @g_endPoint1, @g_endPoint2, g_radius)

	ElseIf GetGadgetAttribute(0, #PB_Canvas_Key) = #PB_Shortcut_Down
		g_radius - 1.0
		If g_radius < 0
			g_radius = 1
		EndIf
		drawCanvas(@g_intersection, @g_endPoint1, @g_endPoint2, g_radius)
	EndIf 
EndProcedure

Procedure main()
	Protected.l ev
	Protected.PointD intersection, endPoint1, endPoint2
	
	g_radius = DesktopScaledX(40)
	g_intersection\x = DesktopScaledX(400)
	g_intersection\y = DesktopScaledY(300)
	g_endPoint1\x = DesktopScaledX(500)
	g_endPoint1\y = DesktopScaledY(10)

	g_endPoint2\x = DesktopScaledX(600)
	g_endPoint2\y = DesktopScaledY(200)
	
	OpenWindow(0, 0, 0, 800, 600, "VectorDrawing", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	CanvasGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), #PB_Canvas_Keyboard)
	BindGadgetEvent(0, @onKeyDown(), #PB_EventType_KeyDown)
	
	drawCanvas(@g_intersection, @g_endPoint1, @g_endPoint2, g_radius)
	
	SetActiveGadget(0)
	
	Repeat
		ev = WaitWindowEvent()
	Until ev = #PB_Event_CloseWindow
EndProcedure

main()
Post Reply