Page 1 of 1

Angle degree to X,Y and back (simple trig)

Posted: Fri Mar 17, 2017 1:21 am
by Keya
trying to brush some dust off my trigonometry! :)
I have a circle and want to draw a line exactly like a clock hand, so I'm converting degrees to X&Y and drawing that line ok

But how then to convert the X&Y back to degrees??? I've run out of combinations to try

Code: Select all

If OpenWindow(0, 0, 0, 200, 200, "Trig", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  If CreateImage(0, 200, 200) And StartDrawing(ImageOutput(0))
    
    #MiddleX = 100
    #MiddleY = 100
    #LineLen = 80
    Circle(#MiddleX,#MiddleY, #LineLen,$00A000) 
    
    ;// DEGREES to X,Y  (this part seems fine)
    Degrees = 90
    
    Debug "Degrees = " + Str(Degrees)        
    CalcDegrees = 360 - Degrees + 180
    XX.f = Sin(CalcDegrees * (2 * #PI / 360))
    YY.f = Cos(CalcDegrees * (2 * #PI / 360))
    LineXY(#MiddleX, #MiddleY, #MiddleX + (XX * #LineLen),
           #MiddleY + (YY * #LineLen),           $FFFFFF)
    Debug "X="+StrF(XX)  + "  Y=" + StrF(YY)
    
;?????????????????????????????????????????    
    ;// X,Y back to DEGREES  (not right!)
    rad.f = ATan2(#MiddleX+XX, #MiddleY+YY)
    deg.f = rad * 180.0 / #PI
    Debug "v1 Degrees  = " + StrF(deg)
    Debug "v2 Degree() = " + Degree(rad)
;?????????????????????????????????????????    
       
    StopDrawing() 
    ImageGadget(0, 0, 0, 200, 200, ImageID(0))
  EndIf
  
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf

Re: Angle degree to X,Y and back (simple trig)

Posted: Fri Mar 17, 2017 1:39 am
by MrMat
Hello,

Try this:

Code: Select all

rad.f = Mod(ATan2(-YY, XX)+2*#PI,2*#PI)
deg.f = rad * 180.0 / #PI
You don't really need the mod, it is just to convert to a range of 0...2*PI and 0...360.

Cheers,
Mat

Re: Angle degree to X,Y and back (simple trig)

Posted: Fri Mar 17, 2017 1:43 am
by Keya
super, thankyou and thanks for the Mod tip! it feels good to brush the dust off the trig in my mind so I can work outside the box

Re: Angle degree to X,Y and back (simple trig)

Posted: Mon Apr 15, 2019 2:19 pm
by vwidmer
I was trying to make a wind gauge from your code but not having luck to get it to show right.

It only shows nice which this but if I try to change then it all turns black.

Can some one help me with this please.

thanks

Code: Select all

Procedure windGauge(windDir.i,windMsg.s)
  
    If CreateImage(0, 200, 200,32,$FFFFFF) And StartDrawing(ImageOutput(0))
   
    MiddleX = ImageWidth(0) / 2
    MiddleY = ImageHeight(0) /2
    LineLen = ImageWidth(0) / 2 - 20
    Circle(MiddleX,MiddleY, LineLen+10,$818282)
    Circle(MiddleX,MiddleY, LineLen+5,$FFFFFF)
    
    Degrees = windDir   
    Debug "Degrees = " + Str(Degrees)    
    
    CalcDegrees = 360 - Degrees + 180
    XX.f = Sin(CalcDegrees * (2 * #PI / 360))
    YY.f = Cos(CalcDegrees * (2 * #PI / 360))
    LineXY(MiddleX, MiddleY, MiddleX + (XX * LineLen), MiddleY + (YY * LineLen), $FFFFFF)
    
    DrawText(MiddleX - (ImageWidth(0) * 0.04),(ImageHeight(0) * 0.10),"N",$0,$FFFFFF)
    ;DrawText(170,90,"E",$FFFFFF,$00A000)
    ;DrawText(95,165,"S",$FFFFFF,$00A000)
    ;DrawText(20,90,"W",$FFFFFF,$00A000)
    DrawText(MiddleX-20,MiddleY-10,windMsg,$0,$FFFFFF)
    
    ;- Arrow Stuff
    x1 = MiddleX
    y1 = MiddleY
    x2 = MiddleX + (XX * LineLen)
    y2 = MiddleY + (YY * LineLen)
    
    length = -20.0 ;length = arrow line length
    tightness = 2
    ;tightness = arrowhead tightness; range 1 -> 10, 1 is the least tight, 10 is the tightest.
    slopY = ATan2(x1 - x2, y1 - y2)
    cosY = Cos(slopY)
    sinY = Sin(slopY)
    
    LineXY(x2, y2, x2 + Int(length * cosY - length / tightness * sinY), y2 + Int(length * sinY + length / tightness * cosY ),$0)
    LineXY(x2 + Int(length * cosY + length / tightness * sinY ), y2 - Int(length / tightness * cosY  - length * sinY),x2, y2,$0)
    LineXY(x2 + Int(length * cosY - length / tightness * sinY), y2 + Int(length * sinY + length / tightness * cosY ),x2 + Int(length * cosY + length / tightness * sinY ), y2 - Int(length / tightness * cosY  - length * sinY),$0)
    
    FillArea(MiddleX + (XX * LineLen)+10, MiddleY + (YY * LineLen),$0,$0)
    
    Debug "X="+StrF(XX)  + "  Y=" + StrF(YY)
   
;?????????????????????????????????????????   
    rad.f = Mod(ATan2(-YY, XX)+2*#PI,2*#PI)
    deg.f = rad * 180.0 / #PI
    Debug "v1 Degrees  = " + StrF(deg)
    Debug "v2 Degree() = " + Degree(rad)
;?????????????????????????????????????????   

    StopDrawing()
    ImageGadget(0, 0, 0, 150, 150, ImageID(0))
  EndIf
  
EndProcedure

If OpenWindow(0, 0, 0, 200, 200, "Wind", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  
  windGauge(90,"20kn")
 
  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
EndIf

Re: Angle degree to X,Y and back (simple trig)

Posted: Mon Apr 15, 2019 2:27 pm
by STARGÅTE
1. If you calc Sin and Cos or Tan it should be stored in a float number!

Code: Select all

    slopY.f = ATan2(x1 - x2, y1 - y2)
    cosY.f = Cos(slopY)
    sinY.f = Sin(slopY)

2. Your FillArea() seems to be wrong. Without, it works
3. Try to work with the VectorDrawing lib, it is much more easier with rotation and filling.

Re: Angle degree to X,Y and back (simple trig)

Posted: Mon Apr 15, 2019 3:21 pm
by vwidmer
STARGÅTE wrote:1. If you calc Sin and Cos or Tan it should be stored in a float number!
3. Try to work with the VectorDrawing lib, it is much more easier with rotation and filling.
Thank you it is working now..

If you have a sec can you please give me more info on the VectorDrawing lib, an example or point me somewhere..

Thanks

Re: Angle degree to X,Y and back (simple trig)

Posted: Tue Apr 16, 2019 10:37 am
by STARGÅTE
Here a small example.
It shows a circle with an arrow and it shows the direction of you mouse:

Code: Select all

Enumeration
	#Window
	#Gadget
	#Timer
EndEnumeration

Procedure Update()
	
	Protected Angle.f
	
	If StartVectorDrawing(CanvasVectorOutput(#Gadget))
		
		VectorSourceColor($FFFFFFFF)
		FillVectorOutput() ; fill all with white
		
		VectorSourceColor($FF808080)
		AddPathCircle(200, 200, 180) 
		StrokePath(5) ; gray circle with 5px thickness
		
		Angle = ATan2(DesktopMouseX()-WindowX(#Window, #PB_Window_InnerCoordinate)-200, DesktopMouseY()-WindowY(#Window, #PB_Window_InnerCoordinate)-200) ; angle between mouse and center
		TranslateCoordinates(200, 200) ; Center
		RotateCoordinates(0, 0, Degree(Angle)) ; Rotation
		TranslateCoordinates(160, 0)  ; Shift to circle
		VectorSourceColor($FF00C040)
		MovePathCursor(30, 0)
		AddPathLine(-10, -15)
		AddPathLine(-10, 15)
		ClosePath()
		FillPath() ; green triangle filled
		
		StopVectorDrawing()
	EndIf
	
EndProcedure

OpenWindow(#Window, 0, 0, 400, 400, "Vector Demo", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))
AddWindowTimer(#Window, #Timer, 20)

Repeat
	
	Select WaitWindowEvent()
		Case #PB_Event_Timer
			Select EventTimer()
				Case #Timer
					Update()
			EndSelect
		Case #PB_Event_CloseWindow
			End
	EndSelect
ForEver

Re: Angle degree to X,Y and back (simple trig)

Posted: Mon Apr 22, 2019 3:50 pm
by vwidmer
Wow very nice example.. Thank you very much.

Re: Angle degree to X,Y and back (simple trig)

Posted: Mon Apr 22, 2019 7:55 pm
by Little John
Hi Stargate,

that's a nice example, thank you!

When I tested your code with PB 5.71 beta 1, it turned out that the DPI awareness flag was set in my IDE. Thus the circle wasn't in the center of the window, and the green arrow did not always point into the right direction.
As an exercise for myself, I changed your code so that it now works with and without the DPI awareness flag set:

Code: Select all

; tested with PB 5.71 beta 1 (x64) on Windows 10
; (compiled with and without the DPI awareness flag set)

EnableExplicit

Enumeration
   #Window
   #Gadget
   #Timer
EndEnumeration


Procedure Update (cx.i, cy.i)
   ; in: cx, cy: coordinates of the center of the circle
   Protected Angle.f, cxs.f, cys.f
   
   If StartVectorDrawing(CanvasVectorOutput(#Gadget))
      VectorSourceColor($FFFFFFFF)
      FillVectorOutput()             ; white background
      
      cxs = DesktopScaledX(cx)
      cys = DesktopScaledY(cy)
      
      VectorSourceColor($FF808080)
      AddPathCircle(cxs, cys, DesktopScaledX(cx-20))
      StrokePath(DesktopScaledX(5))  ; gray circle
      
      Angle = ATan2(DesktopMouseX()-WindowX(#Window, #PB_Window_InnerCoordinate)-cx, DesktopMouseY()-WindowY(#Window, #PB_Window_InnerCoordinate)-cy) ; angle between mouse and center
      TranslateCoordinates(cxs, cys)                         ; Center
      RotateCoordinates(0, 0, Degree(Angle))                 ; Rotation
      TranslateCoordinates(DesktopScaledX(cx-40), 0)         ; Shift to circle
      VectorSourceColor($FF00C040)
      MovePathCursor(DesktopScaledX(30), 0)
      AddPathLine(-DesktopScaledX(10), -DesktopScaledY(15))
      AddPathLine(-DesktopScaledX(10),  DesktopScaledY(15))
      ClosePath()
      FillPath()                     ; green triangle filled
      
      StopVectorDrawing()
   EndIf
EndProcedure


Define.i cx = 200, cy = 200

OpenWindow(#Window, 0, 0, 2*cx, 2*cy, "Vector Demo", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
CanvasGadget(#Gadget, 0, 0, WindowWidth(#Window), WindowHeight(#Window))
AddWindowTimer(#Window, #Timer, 20)

Repeat
   Select WaitWindowEvent()
      Case #PB_Event_Timer
         Select EventTimer()
            Case #Timer
               Update(cx, cy)
         EndSelect
      Case #PB_Event_CloseWindow
         End
   EndSelect
ForEver

Re: Angle degree to X,Y and back (simple trig)

Posted: Fri May 21, 2021 9:42 am
by Altenburger
trig student wrote:

It was quite simple. I tried some combinations from https://domyhomeworkonline.net/do-my-trigonometry-homework.php X&Y samples.
Simple trigonometry? As you wish ;)

I didn't find it that easy to grasp at the first time.

https://stackoverflow.com/questions/159 ... o-an-angle

Re: Angle degree to X,Y and back (simple trig)

Posted: Fri May 21, 2021 1:37 pm
by AZJIO
I tried to figure out which sector the mouse is in and ended up making buttons.

Code: Select all

EnableExplicit

#Window_1 = 1
Define h, m
Define i, j, EvnGd, EvWin

If OpenWindow(#Window_1, #PB_Ignore, #PB_Ignore, 500, 500, "Timer")
	j=0
	For i=0 To 359 Step 15
		ButtonGadget(j+1000 , 160 * Cos(Radian(i-90))+230 , 160 * Sin(Radian(i-90))+230 , 30 , 30 , Str(j), #PB_Button_Toggle)
		j+1
	Next
	j=0
	For i=0 To 359 Step 6
		ButtonGadget(j+1100 , 236 * Cos(Radian(i-90))+239 , 236 * Sin(Radian(i-90))+239 , 19 , 19 , Str(j), #PB_Button_Toggle)
		j+1
	Next
	
	h = 0
	m = 0
	
	; Обработать гаджеты только этого окна
	Repeat
		Select WaitWindowEvent()
			Case #PB_Event_Gadget
				EvnGd = EventGadget()
				Select EvnGd
					Case 1000 To 1023
						For i=1000 To 1023
							If GetGadgetState(EvnGd) = 1 And i <> EvnGd
								SetGadgetState(i , 0)
								h = EvnGd - 1000
							EndIf
						Next
					Case 1100 To 1159
						For i=1100 To 1159
							If GetGadgetState(EvnGd) = 1 And i <> EvnGd
								SetGadgetState(i , 0)
								m = EvnGd - 1100
							EndIf
						Next
				EndSelect
			Case #PB_Event_CloseWindow
				CloseWindow(#Window_1)
				Break
		EndSelect
	ForEver
EndIf

If h = 0 And m = 0
	MessageRequester("Message", "Specify timer time")
Else
	MessageRequester("Message", Str(h) + #LF$ + Str(m))
EndIf