Kürzeste Drehrichtung um von Winkel A zu Winkel B zu kommen

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

DC

Sieger des B2D Retro Wettbewerb / Aug 04

Betreff: Kürzeste Drehrichtung um von Winkel A zu Winkel B zu kommen

BeitragDo, Dez 23, 2004 15:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Mein Problem klingt eigentlich ganz simpel aber komme auf keine Lösung! Wirrer Winkelmist!

Ich habe 2 verschiedene Winkel. Sozusagen einen IST-Winkel und einen SOLL-Winkel. Der IST-Winkel soll sich schrittweise zum SOLL-Winkel drehen bis er mit ihm übereinstimmt. Allerdings stets über den kürzesten Weg. Aber wie finde ich raus, ob ich nun nach Links oder Rechts drehen, sprich den Winkel erhhöhen oder senken muss um den kürzesten "Drehweg" zu erhalten?

Praktisches Beispiel falls das jetzt unverständlich war: Eine um 360° drehbare Überwachungskamera, die sich auf kürzestem Weg von der aktuellen Drehung zu einem beliebigen Zielobjekt drehen können soll.
Core i5 4670K | 4 x 3,40 GHZ | 16 GB Ram | GeForce GTX 960 | HTC Vive | Win 10 Pro
www.UnrealSoftware.de | www.StrandedOnline.de | www.CS2D.com |
www.CarnageContest.com | www.Stranded3.com
 

Edlothiol

BeitragDo, Dez 23, 2004 15:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Code: [AUSKLAPPEN]
Function CompareAngles#(a#,b#)
   if (b - a) < -180 then b = b + 360
   if (b - a) > 180 then a = a + 360
   return b - a
End Function
Je nachdem ob die Funktion einen Wert > oder < 0 ergibt, den Winkel erhöhen oder verringern. Die beiden Ifs sind für sowas wie a = 0 b = 359 Wink
Die Winkel müssen natürlich >0 und <360 sein.
 

walski

Ehemaliger Admin

BeitragDo, Dez 23, 2004 16:46
Antworten mit Zitat
Benutzer-Profile anzeigen
Edlothiol Lösung ist falsch, wenn ich die mal mit a = 0 und b = 270 durchgeh kommt dabei folgendes raus:

b - a = -270

also b - a < -180 also b = b +360 = 630

b - a = 630

also b - a > 180 also a = a +360 = 360

b - a = 270

Das ist zwar richtig für ne Rechtsdrehung aber eben ist es nicht der kürzeste Weg, der wäre eben 90 Grad Linksdrehung.

Hier mein Vorschlag:

Code: [AUSKLAPPEN]


Function approachAngle( AngleA# ,AngleB# )

; AngleA -> smaller Angle
; AngleB -> bigger Angle

If AngleB = AngleA Return 0

AngleA = AngleA Mod 360
AngleB = AngleB Mod 360

While AngleA < 0

 AngleA = AngleA + 360

Wend

While AngleB < 0

 AngleB = AngleB + 360

Wend

Return -1 + ( 2 * ( ( ( AngleB - AngleA  ) < ( 360.0 - ( AngleB - AngleA ) ) ) And ( Not ( AngleB < AngleA And ( ( AngleA - AngleB  ) < ( 360.0 - ( AngleA - AngleB ) ) ) ) ) ) )

End Function



walski

[EDIT]
Achja, der Rückgabewert ist eben -1 bei ner Linksdrehung und 1 bei ner Rechtsdrehung Wink

Hier eingebaut in Rallimenscode:
Code: [AUSKLAPPEN]


Function approachAngle( AngleA# ,AngleB# )

; AngleA -> smaller Angle
; AngleB -> bigger Angle

If AngleB = AngleA Return 0

AngleA = AngleA Mod 360
AngleB = AngleB Mod 360

While AngleA < 0

 AngleA = AngleA + 360

Wend

While AngleB < 0

 AngleB = AngleB + 360

Wend

Return -1 + ( 2 * ( ( ( AngleB - AngleA  ) < ( 360.0 - ( AngleB - AngleA ) ) ) And ( Not ( AngleB < AngleA And ( ( AngleA - AngleB  ) < ( 360.0 - ( AngleA - AngleB ) ) ) ) ) ) )

End Function

Graphics  800,600,16,2
SetBuffer BackBuffer()
Dim Panzer (360)
;PanzerGrafik_berechnen > 360 Einzelbilder <
      Rect 9,0,2,20
      Rect 0,10,20,20,1
      Flip
      Panzer(0) = CreateImage (20,30)
      GrabImage Panzer(0),0,0
      MidHandle Panzer(0)
       
   For z= 1 To 359
      panzer(z) = CopyImage (Panzer(0))
      RotateImage panzer(z),z
      MidHandle Panzer(z)
      Text 500,500," Berechne Panzer : "+z
      Flip
      Cls
   Next
x=  400: y= 30 ; damit der zielpunkt zu sehen ist

Repeat

   If MouseDown(1) Then
      x= MouseX ()
      Y= MouseY ()      ;Winkel bezieht sich auf den Panzer
      winkel = Objekt_richtung_grad(x,y ,400 ,300)
   End If

   ;kürzeren Weg suchen
   posPanzer = posPanzer + approachAngle(posPanzer,Winkel)
   posPanzer = (posPanzer+360) Mod 360 ; < 0   oder >359

   
   Oval  x-5,y-5,10,10,1 ;Klickpunkt malen
   DrawBlock Panzer(posPanzer),400,300;Panzer malen
   Text 100,30, posPanzer + " Panzer"
   Text 100,60, winkel +      " Grad"

   Flip
   Cls
   Until KeyHit (1)
End

Function Objekt_richtung_grad(Zielpunkt_X,Zielpunkt_Y,Ausgangspunkt_X,Ausgangspunkt_Y )
grad =ATan2(Zielpunkt_Y -Ausgangspunkt_Y, Zielpunkt_X -Ausgangspunkt_X)+90
grad = (grad+360) Mod 360
Return grad

End Function


[/EDIT]
buh!
  • Zuletzt bearbeitet von walski am Fr, Dez 24, 2004 13:50, insgesamt 2-mal bearbeitet

Rallimen

Sieger des 30-EUR-Wettbewerbs

BeitragDo, Dez 23, 2004 18:26
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo, hab da noch so ein BeispielCode den ich mal hier gepostet habe !Code: [AUSKLAPPEN]
Graphics  800,600,16,2
SetBuffer BackBuffer()
Dim Panzer (360)
;PanzerGrafik_berechnen > 360 Einzelbilder <
      Rect 9,0,2,20
      Rect 0,10,20,20,1
      Flip
      Panzer(0) = CreateImage (20,30)
      GrabImage Panzer(0),0,0
      MidHandle Panzer(0)
       
   For z= 1 To 359
      panzer(z) = CopyImage (Panzer(0))
      RotateImage panzer(z),z
      MidHandle Panzer(z)
      Text 500,500," Berechne Panzer : "+z
      Flip
      Cls
   Next
x=  400: y= 30 ; damit der zielpunkt zu sehen ist

Repeat

   If MouseDown(1) Then
      x= MouseX ()
      Y= MouseY ()      ;Winkel bezieht sich auf den Panzer
      winkel = Objekt_richtung_grad(x,y ,400 ,300)
   End If

   ;kürzeren Weg suchen
   If posPanzer > Winkel  And  posPanzer -180 < Winkel  Then posPanzer = posPanzer -1
   If posPanzer > Winkel  And  posPanzer -180 > Winkel  Then posPanzer = posPanzer +1
   If posPanzer < Winkel  And  posPanzer +180 < Winkel  Then posPanzer = posPanzer -1
   If posPanzer < Winkel  And  posPanzer +180 > Winkel  Then posPanzer = posPanzer +1
   If posPanzer = Winkel -180  Or posPanzer -180  = Winkel  Then posPanzer = posPanzer +1
   posPanzer = (posPanzer+360) Mod 360 ; < 0   oder >359

   
   Oval  x-5,y-5,10,10,1 ;Klickpunkt malen
   DrawBlock Panzer(posPanzer),400,300;Panzer malen
   Text 100,30, posPanzer + " Panzer"
   Text 100,60, winkel +      " Grad"

   Flip
   Cls
   Until KeyHit (1)
End

Function Objekt_richtung_grad(Zielpunkt_X,Zielpunkt_Y,Ausgangspunkt_X,Ausgangspunkt_Y )
grad =ATan2(Zielpunkt_Y -Ausgangspunkt_Y, Zielpunkt_X -Ausgangspunkt_X)+90
grad = (grad+360) Mod 360
Return grad
End Function


sollte verständlich sein

hier noch eine gekürzte Version !Code: [AUSKLAPPEN]
   If posPanzer > Winkel Then
       If posPanzer -180 < Winkel  Then posPanzer = posPanzer -1
       If posPanzer -180 => Winkel  Then posPanzer = posPanzer +1
   Else 
       If posPanzer +180 < Winkel  Then posPanzer = posPanzer -1
       If posPanzer +180 => Winkel  Then posPanzer = posPanzer +1
   End If
   posPanzer = (posPanzer+360) Mod 360 ; < 0   oder >359

   
[BB2D | BB3D | BB+]
  • Zuletzt bearbeitet von Rallimen am Do, Dez 23, 2004 18:47, insgesamt einmal bearbeitet
 

walski

Ehemaliger Admin

BeitragDo, Dez 23, 2004 18:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Ok, ich glaub ich stänkere grad etwas rum, aber ich finde die 5 Ifs oder wieviele das sind für diese Lösung nicht gerade sehr schön.

Aber das ist ja zum Glück Geschmackssache Wink

Bitte nicht zu böse nehmen oder denken ich sei ein dreckiger Egoman.

walski
buh!

Rallimen

Sieger des 30-EUR-Wettbewerbs

BeitragDo, Dez 23, 2004 19:05
Antworten mit Zitat
Benutzer-Profile anzeigen
@Walski:
nicht böse gemeint, aber bei meiner etwas gekürzten Version werden max 3 If´s abgearbeitet Wink

Zitat:
Aber das ist ja zum Glück Geschmackssache
Mein ich auch so....
[BB2D | BB3D | BB+]
 

Edlothiol

BeitragDo, Dez 23, 2004 19:08
Antworten mit Zitat
Benutzer-Profile anzeigen
Walski, du bist meinen Code falsch durchgegangen: b-a ist nicht -270, sondern 270. Deshalb kommt am Ende ein Wert <0 raus, und es ist doch richtig...
 

walski

Ehemaliger Admin

BeitragDo, Dez 23, 2004 19:36
Antworten mit Zitat
Benutzer-Profile anzeigen
Du hast recht, ich hab dich wirklich verunglimpft... Embarassed

Tut mir leid.
Ich habe meinen Code auch nocheinmal verbessert, er kommt jetzt ohne die If-Klauseln zur Abfrage aus, damit besteht die eigentliche Prüfung jetzt nurnoch aus einer Zeile.

walski
buh!

Travis

BeitragDo, Dez 23, 2004 23:41
Antworten mit Zitat
Benutzer-Profile anzeigen
@ walski

Angenommen ein Spieler schiesst zielsuchende Waffen ab.

Ist DirectionToObject denn der Winkel vom Spieler zum Ziel. Ist DirectionOfCam dann der Winkel des Spielers?

Ich schlage mich für mein Projekt auch mit diesem Problem rum. Meine bisherige Lösung ist der von Rallimen ähnlich. Ist natürlich auch nicht sehr elegant.

Code: [AUSKLAPPEN]

  ; Rakete auf Ziel ausrichten
  winkel = (450 - ATan2((zx - r\x), (zy - r\y))) Mod 360
 
  If Abs(s\winkel-winkel) < 180 Then
   If r\winkel < winkel Then r\winkel = r\winkel + 1
   If r\winkel > winkel Then r\winkel = r\winkel - 1
  Else
   If r\winkel < winkel Then r\winkel = r\winkel - 1
   If r\winkel > winkel Then r\winkel = r\winkel + 1
  EndIf


Dabei ist Winkel der Winkel vom Spieler zum Ziel und s\Winkel der Winkel des Spielers. Weil das aber ziemlich umständlich ist, würde ich deine Methode mal probieren wollen. Dazu müsste ich aber wissen, was deine zwei Variablen genau bedeuten.

EDIT: Und gehört der obere Code auch noch zu der Lösung. Dann wäre das ja auch nicht unbedingt der kürzeste Weg. ich verstehe deinen Lösungsweg leider total nicht. Embarassed
www.funforge.org

Ich hasse WASD-Steuerung.

Man kann alles sagen, man muss es nur vernünftig begründen können.
 

walski

Ehemaliger Admin

BeitragFr, Dez 24, 2004 0:26
Antworten mit Zitat
Benutzer-Profile anzeigen
Meine obere Lösung ist teilweise falsch, ich habe gerade keine Zeit werde aber später noch dazu Stellung nehmen Wink

Es gibt noch ein Problem mit dem vertauschen der Winkel, das macht natrlürlich alles etwas kaputt, ich verbessere das.

Generell sind halt beides Winkel. Das eine der "Ist-Winkel" und das andere der "Soll-Winkel". Alles klar?

walski
buh!

Rallimen

Sieger des 30-EUR-Wettbewerbs

BeitragFr, Dez 24, 2004 0:44
Antworten mit Zitat
Benutzer-Profile anzeigen
habs nochmal gekürzt und in eine Function gepackt!
Code: [AUSKLAPPEN]
Function DrehAufZiel (pospanzer,winkel)
   If posPanzer > Winkel Then
       If posPanzer -180 < Winkel  Then Return -1
   Else 
       If posPanzer +180 < Winkel  Then Return -1
   End If
   Return 1
End Function

Code: [AUSKLAPPEN]
posPanzer =(posPanzer + drehAufZiel(pospanzer,winkel)+360)Mod 360
[BB2D | BB3D | BB+]

DC

Sieger des B2D Retro Wettbewerb / Aug 04

BeitragFr, Dez 24, 2004 11:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke an alle für die Hilfe. Jetzt funktionierts Smile
Core i5 4670K | 4 x 3,40 GHZ | 16 GB Ram | GeForce GTX 960 | HTC Vive | Win 10 Pro
www.UnrealSoftware.de | www.StrandedOnline.de | www.CS2D.com |
www.CarnageContest.com | www.Stranded3.com

Ctuchik

BeitragFr, Dez 24, 2004 13:31
Antworten mit Zitat
Benutzer-Profile anzeigen
bei mir siehts so aus, sollte auch funktionieren:
Code: [AUSKLAPPEN]

aenderung#=zielwinkel-startwinkel
If aenderung# > 180 Or aenderung# < -180
aenderung# = (360 - Abs(aenderung#)) * Sgn(aenderung#) * -1
End If


Frage: Ist das mit Sgn() und Abs() spürbar langsamer als zum Beispiel der Code von Edlothiol?
Zu den Nebenwirkungen gehören trockener Mund, Übelkeit, Erbrechen, Harnstau, schmerzhafter rektaler Juckreiz, Halluzinationen, Demenz, Psychose, Koma, Tod und Mundgeruch!
Magie eignet sich nicht für alle!
Fraget euren Arzt oder Apotheker!
 

walski

Ehemaliger Admin

BeitragFr, Dez 24, 2004 13:52
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe meinen Code oben jetzt mal überarbeitet...

Er funktioniert jetzt zwar, ich halt ihn aber nicht mehr für ne gute Lösung Wink
Auch wenn er ahrscheinlich nicht langsam ist, ist er doch etwas... unübersichtlich.

Die ganzen Abfragen ob die Winkel auch größer 0 und nicht größer 360 sind kann man sich natürlich sparen, wenn man das sowieso im Code abfängt, also würde man da noch etwas Speed rausholen.

Zu Funktionen wie Abs und Sgn würd ich sagen: Vermeide sie wo es geht und bei diesem Ansatz geht es sicher.

walski
buh!
 

zocker2150

BeitragFr, Dez 24, 2004 14:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Die Funktion...
Code: [AUSKLAPPEN]
Function Drehzuwinkel(IW#,SW#)
   Local W# = IW# - SW#
   
   If W# < -180 Then W# = W# + 360
   If W# > 180 Then W# = W# - 360
   
   If W# < 0 Then
      Return 1
   Else
      Return -1
   End If
   
End Function

Zum Aufrufen...
Code: [AUSKLAPPEN]
IstW# = ((IstW# + Speed * drehvari)+360) Mod 360

Code: [AUSKLAPPEN]
DrawImage bild(IstW#), BildX,BildY
  • Zuletzt bearbeitet von zocker2150 am Fr, Dez 24, 2004 14:58, insgesamt einmal bearbeitet

MVB

BeitragFr, Dez 24, 2004 14:24
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich weiß nicht, villeicht bin ich auch zu dumm, aber irgendwas stimmt mit Rallimans Code nicht.
Nehmen wirmal an der IST-Winkel ist 10; und der SOLL-Winkel ist 20;

Jetzt nehmen wir den Code und setzen wir das ein:
Code: [AUSKLAPPEN]
posPanzer =(10 + -1 +360)Mod 360

Da kommt 9 raus?!

Das "drehAufZiel(pospanzer,winkel)" hab ich durch -1 ersetzt weil das bei der Funktion herauskäme; 10-180 ist bekanntlich kleiner als 20.
Verstehe ich was falsch, oder funktioniert das nicht?
EDIT: Sorry! Ich hab was übersehen. Embarassed
EDIT2: Jetzt wo ichs mir nochmal angucke ist wieder etwas falsch.
Bei dem was ich oben geschrieben habe müsste "-1" durch "1" ersetzt werden. Jetzt kommt 11 raus?!
Ich bin verwirrt. Rolling Eyes
aquamonit.de|BlitzMax|MaxGUI

Rallimen

Sieger des 30-EUR-Wettbewerbs

BeitragFr, Dez 24, 2004 14:53
Antworten mit Zitat
Benutzer-Profile anzeigen
das soll doch auch so sein, immer 1 grad weiter in richtige richtung drehen und zeichnen!
sonst könnte man sich das viel einfacher machen >> PosPanzer = winkel
hier nochmal der Code mit Function Code: [AUSKLAPPEN]
Graphics  800,600,16,2
SetBuffer BackBuffer()
Dim Panzer (360)
;PanzerGrafik_berechnen > 360 Einzelbilder <
      Rect 9,0,2,20
      Rect 0,10,20,20,1
      Flip
      Panzer(0) = CreateImage (20,30)
      GrabImage Panzer(0),0,0
      MidHandle Panzer(0)
       
   For z= 1 To 359
      panzer(z) = CopyImage (Panzer(0))
      RotateImage panzer(z),z
      Text 500,500," Berechne Panzer : "+z
      If z Mod 10 = 0 Flip
      Cls
   Next
x=  400: y= 30 ; damit der zielpunkt zu sehen ist

Repeat

   If MouseDown(1) Then
      x= MouseX ()
      Y= MouseY ()      ;Winkel bezieht sich auf den Panzer
      winkel = Objekt_richtung_grad(x,y ,400 ,300)
   End If

posPanzer =(posPanzer + drehAufZiel(pospanzer,winkel)+360)Mod 360


   Oval  x-5,y-5,10,10,1 ;Klickpunkt malen
   DrawBlock Panzer(posPanzer),400,300;Panzer malen
   Text 100,30, posPanzer + " Panzer"
   Text 100,60, winkel +      " Grad"

   Flip
   Cls
   Until KeyHit (1)
End

Function Objekt_richtung_grad(Zielpunkt_X,Zielpunkt_Y,Ausgangspunkt_X,Ausgangspunkt_Y )
grad =ATan2(Zielpunkt_Y -Ausgangspunkt_Y, Zielpunkt_X -Ausgangspunkt_X)+90
grad = (grad+360) Mod 360
Return grad
End Function


Function drehAufZiel (pospanzer,winkel)
   If posPanzer > Winkel Then
       If posPanzer -180 < Winkel  Then Return -1
   Else 
       If posPanzer +180 < Winkel  Then Return -1
   End If
   Return 1
End Function
[BB2D | BB3D | BB+]

MVB

BeitragFr, Dez 24, 2004 15:24
Antworten mit Zitat
Benutzer-Profile anzeigen
Auchso ist klar. Ich hab irgendwie falsch gedacht. Ich dachte jetzt werden zu den 10 nochmal 11 addiert. Laughing
aquamonit.de|BlitzMax|MaxGUI
 

zocker2150

BeitragFr, Dez 24, 2004 15:38
Antworten mit Zitat
Benutzer-Profile anzeigen
@ Rallimen
Haha das hab ich mir auch so ausgedacht... ( nettes Programm Wink )
Sie selber; ist nicht abgeschrieben!

Code: [AUSKLAPPEN]
Const GrafikX = 640
Const GrafikY = 480

Graphics GrafikX,GrafikY,32,0
SetBuffer BackBuffer()   
TFormFilter False

Dim Panzer(360)

Panzer(0) = CreateImage(20,30)
SetBuffer ImageBuffer(Panzer(0))
Color 50,50,250
Rect 5,0,4,30
Rect 0,10,20,20

MidHandle Panzer(0)

For i = 1 To 360
   Panzer(i) = CopyImage(Panzer(0))
   RotateImage Panzer(i),-i
Next

Speed    = 1
IstW#    = 90
SollW#    = 50
BildX    = GrafikX/2
BildY    = GrafikY/2
Color 0,0,0

SetBuffer BackBuffer()
Repeat
   ClsColor 255,255,255
   Cls
   
   MausX = MouseX()
   MausY = MouseY()
   
   If MouseHit(1) Then
      SaveX = MausX
      SaveY = MausY
   End If

   SollW# = (ATan2(BildX-SaveX,BildY-SaveY)+360) Mod 360

   drehvari = Drehzuwinkel(IstW#,SollW#)
   IstW# = ((IstW# + Speed * drehvari)+360) Mod 360
   
   Color 0,0,0 : Text 20,20,"ISTW " + IstW#
   Text 20,40,"SollW " + SollW#

   DrawImage Panzer(IstW#), BildX,BildY
   Color 255,0,0 : Rect SaveX,SaveY,5,5,1
   
   Flip
   
Until KeyHit(1)
End

Function Drehzuwinkel(IW#,SW#)
   Local W# = IW# - SW#
   
   If W# < -180 Then W# = W# + 360
   If W# > 180 Then W# = W# - 360
   
   If W# < 0 Then
      Return 1
   Else
      Return -1
   End If
   
End Function

Kabelbinder

Sieger des WM-Contest 2006

BeitragFr, Dez 24, 2004 16:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Als ich den Code mit den Suchraketen gemacht hatte, musste ich mich auch damit rumschlagen:
https://www.blitzforum.de/viewtopic.php?t=5986

Ich hatte da einfach geprüft, ob der IST-winkel < 180 ist wenn ja, rechnet er in einer anderen Variable 180 dazu und überprüft dann, ob diese Variable immer noch kleiner ist, als der SOLL-Winkel.
Wenn nicht: winkel=winkel-1
Wenn ja: winkel = winkel+1
Ist der IST-winkel > 180 halt 180 davon abziehen.

Edit: Man, die haben meine alten Texte ja total verstümmelt, hab das grad mal wieder im Ordnung gebracht.
<Wing Avenger Download> ◊◊◊ <Macrophage Download>

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group