[GELÖST] Punkt auf Rechteck rotieren lassen

Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Neue Antwort erstellen

 

CO2

ehemals "SirMO"

Betreff: [GELÖST] Punkt auf Rechteck rotieren lassen

BeitragSa, März 10, 2018 16:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallöchen,

ich hätte da mal wieder eine Frage, diesmal geht es um Geometrie. Angenommen ich habe ein Rechteck von der Größe 10 x 5 px und möchte auf den Außenkanten einen Punkt rotieren lassen, wie stelle ich soetwas an? Noch ein paar Informationen: Ich habe eine Klasse, welche ein solches Rect darstellen kann. Diese besitzt eine Methode, mit der ein beliebiges Bild auf den Außenkanten dieses Rechtecks unter Angabe eines Winkels gezeichnet werden kann. Sprich: Wenn ich den Winkel 0 an die Methode übergebe, soll das Bild Oben Mittig auf der Außenkante gezeichnet werden.
Ich hatte zur Lösung zunächst mit Trigonometrie angefangen und die Position des Bildes in einem Einheitskreis ermittelt. Anschließend habe ich diese Koordinaten auf die Größe meines Rechtecks gebracht. Nun bewegt sich das Bild im Kreis, wenn ich immer einen ändernden Winkel an die Methode übergebe. Das Problem ist, mit fehlt nun die "Übersetzung" der Punkte, welche noch nicht genau auf den Außenkanten des Rechtecks liegen. Bisheriger Code BlitzMax: [AUSKLAPPEN]
Graphics(800, 600)
Local fpslimiter:TTimer = CreateTimer(60)

Type TRect
Field x:Double
Field y:Double
Field w:Double
Field h:Double

Function Create:TRect(x:Double, y:Double, w:Double, h:Double)
Local RetVal:TRect = New TRect
RetVal.x = X
RetVal.y = Y
RetVal.W = W
RetVal.H = H
Return RetVal
End Function

Method Draw(rot:Double)
DrawLine(x, y, x + W, y)
DrawLine(x, y, x, y + H)
DrawLine(x + W, y, x + W, y + H)
DrawLine(x, y + h, x + w, y + h)

Rem
x1 = x*cos - y*sin
y1 = x*sin + y*cos
End Rem


Local posxOnCircle:Double = Cos(rot)
Local posyOnCircle:Double = Sin(rot)

Local relposx:Double = posxOnCircle * (Self.w / 2.0)
Local relposy:Double = posyOnCircle * (Self.h / 2.0)

' Hier muss noch irgendetwas passieren, sodass relposx und relposy immer auf den Außenkanten des Rechtecks landen... Aber was?

DrawOval(((Self.x + Self.w / 2.0) + relposx) - 2.5, ((Self.y + Self.h / 2.0) + relposy) - 2.5, 5, 5)
End Method
End Type

Local Rot:Double = 0
Local Rect:TRect = TRect.Create(100, 100, 100, 100)

Repeat
WaitTimer(FPSLimiter)
Cls()

Rect.Draw(rot)

rot = (rot + 0.5) Mod 360

Flip(0)
Until KeyHit(KEY_ESCAPE)
End
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti
  • Zuletzt bearbeitet von CO2 am So, März 11, 2018 19:02, insgesamt einmal bearbeitet

Midimaster

BeitragSa, März 10, 2018 17:05
Antworten mit Zitat
Benutzer-Profile anzeigen
bin mir nicht sicher, ob ich deine Frage verstanden habe... aber müsste man nicht bei der Brechnung des Radius ebenso die halbe Kugeldicke abziehen?

BlitzMax: [AUSKLAPPEN]
		Local relposx:Double = posxOnCircle * ((Self.w-2.5) / 2.0)
Local relposy:Double = posyOnCircle * ((Self.h-2.5) / 2.0)


und wie meinst Du das mit den Bildern? Sollen da Images rotieren? Kannst Du mal in einer Skizze zeigen wie das Endergebnis mit einem Image z.b. bei 50° aussehen soll?
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe
 

CO2

ehemals "SirMO"

BeitragSa, März 10, 2018 17:30
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

ich habe den Code mal umgeschrieben, sodass das Ergebnis so ist, wie es hinterher aussehen soll BlitzMax: [AUSKLAPPEN]
Graphics(800, 600)
Local fpslimiter:TTimer = CreateTimer(60)

Type TRect
Field x:Double
Field y:Double
Field w:Double
Field h:Double

Function Create:TRect(x:Double, y:Double, w:Double, h:Double)
Local RetVal:TRect = New TRect
RetVal.x = X
RetVal.y = Y
RetVal.W = W
RetVal.H = H
Return RetVal
End Function

Method Draw(rot:Double)
DrawLine(x, y, x + W, y)
DrawLine(x, y, x, y + H)
DrawLine(x + W, y, x + W, y + H)
DrawLine(x, y + h, x + w, y + h)
End Method
End Type

Local Rot:Double = 0
Local Rect:TRect = TRect.Create(100, 100, 100, 100)

Local posx:Double = 0
Local posy:Double = 0

Local posxmod:Double = 1
Local posymod:Double = 0

Repeat
WaitTimer(FPSLimiter)
Cls()

Rect.Draw(rot)

Rot = (Rot + 0.5) Mod 360

DrawOval((posx + Rect.x) - 2.5, (posy + Rect.y) - 2.5, 5, 5)

posx = posx + posxmod
posy = posy + posymod

DebugLog(posx + " | " + posy + " (" + posxmod + " | " + posymod + ")")

If (posx >= Rect.w)
posx = Rect.w

posxmod = 0
posymod = 1
End If

If (posy >= Rect.h)
posy = Rect.h

posxmod = -1
posymod = 0
End If

If (posx < 0)
posx = 0

posxmod = 0
posymod = -1
End If

If (posy < 0)
posy = 0

posxmod = 1
posymod = 0
End If

Flip(0)
Until KeyHit(KEY_ESCAPE)
End


Dies möchte ich jedoch nicht durchiterieren, sondern soll für einen genauen Winkel passieren. Wenn ich also in meinem quadratischen Rechteck einen Winkel von 45° an die Methode Draw übergebe, so soll der Punkt oben rechts in meinem Quadrat erscheinen. Bei 50° entsprechend ein wenig darunter, auf gleicher x-Position wie bei 45°, jedoch in der y-Position leicht nach unten verschoben... Ich hoffe, es ist nun verständlicher.
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Thunder

BeitragSo, März 11, 2018 1:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Bei dir sieht die Bewegung recht linear aus. Die Frage ist, willst du es nur linear interpolieren oder willst du den Schnittpunkt von einer Gerade durch den Mittelpunkt mit den Rechteckkanten modellieren?
Du brauchst auf jeden Fall Fallunterscheidungen für die vier Kanten des Quadrats (je nach Winkel, siehe unten im Code).

Linear interpoliert wäre die obere Kante (45° <= rot < 135°): Plot x+(rot-45)/90.0*w, y

Für zweiteres hab ich bisschen Mathe: https://www.blitzforum.de/upload/file.php?id=13340

und ein Beispiel:

BlitzMax: [AUSKLAPPEN]

Graphics 800,600

rot = 45

x = 50
y = 50
w = 400
h = 400

Repeat
Cls

SetColor 255,255,255
DrawText "Angle: "+rot, 5, 5

DrawLine x,y,x+w,y
DrawLine x,y,x,y+h
DrawLine x+w,y,x+w,y+h
DrawLine x,y+h,x+w,y+h

SetColor 255,0,0
' rot ist zwischen 0° und 360°
' x,y sind koordinaten w,h breite und höhe des rechtecks

'die bedingung gilt nur für w=h
If rot >= 45 And rot < 135 Then
bigPlot x+w/2-h/2*Cos(rot)/Sin(rot),y
ElseIf rot >= 135 And rot < 225 Then
bigPlot x+w,y+h/2+h/2*Sin(rot)/Cos(rot)
Else
' zwei kanten fehlen noch
EndIf

SetColor 255,0,255
DrawLine x+w/2,y+h/2,x+w/2-500*Cos(rot),y+h/2-500*Sin(rot)

If KeyDown(KEY_RIGHT) Then
rot :+ 1
ElseIf KeyDown(KEY_LEFT) Then
rot :- 1
EndIf

Flip
Until AppTerminate()

Function BigPlot(x,y)
DrawOval x-2,y-2,4,4
EndFunction


Ich hab jetzt für das Beispiel angenommen dass 0° links ist und 90° oben, das kann man natürlich phasenverschieben.
Der Code funktioniert auch für w <> h, aber dann ist 45° nicht in der Ecke.
Meine Sachen: https://bitbucket.org/chtisgit https://github.com/chtisgit

Midimaster

BeitragSo, März 11, 2018 10:51
Antworten mit Zitat
Benutzer-Profile anzeigen
hier ein Nachtrag für unterschiedliche w und h:
BlitzMax: [AUSKLAPPEN]
...
'jetzt auch für alle w<>h
Local wi#=ATan2(h,w)

If rot >= wi And rot < 180-wi Then
bigPlot x+w/2-h/2*Cos(rot)/Sin(rot),y
ElseIf rot >= wi And rot < 180+wi Then
bigPlot x+w , y+h/2+w/2*Sin(rot)/Cos(rot)
Else
' zwei kanten fehlen noch
EndIf
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe
 

CO2

ehemals "SirMO"

BeitragSo, März 11, 2018 15:15
Antworten mit Zitat
Benutzer-Profile anzeigen
Vielen Dank für eure Antworten! Ich habe das mal in meinem Code ergänzt BlitzMax: [AUSKLAPPEN]
Graphics(800, 600)
Local fpslimiter:TTimer = CreateTimer(60)

Type TRect
Field x:Double
Field y:Double
Field w:Double
Field h:Double

Function Create:TRect(x:Double, y:Double, w:Double, h:Double)
Local RetVal:TRect = New TRect
RetVal.x = X
RetVal.y = Y
RetVal.W = W
RetVal.H = H
Return RetVal
End Function

Method Draw(rot:Double)
DrawLine(x, y, x + W, y)
DrawLine(x, y, x, y + H)
DrawLine(x + W, y, x + W, y + H)
DrawLine(x, y + h, x + w, y + h)

If (Self.w = Self.h)
If (rot >= 45 And rot < 135)
DrawIndicator(x + w / 2 - h / 2 * Cos(rot) / Sin(rot), y)
Else If (rot >= 135 And rot < 225)
DrawIndicator(x + w, y + h / 2 + h / 2 * Sin(rot) / Cos(rot))
Else If (rot >= 225 And rot < 315)
DrawIndicator(x + w - w / 2 + h / 2 * Cos(rot) / Sin(rot), y + h)
Else If ((rot >= 315 And rot <= 360) Or (rot >= 0 And rot < 45))
DrawIndicator(x, y + h - h / 2 - h / 2 * Sin(rot) / Cos(rot))
End If
Else
Local wi:Double = ATan2(h, w)

If (rot >= wi And rot < 180 - wi)
DrawIndicator(x + w / 2 - h / 2 * Cos(rot) / Sin(rot), y)
Else If (rot >= wi And rot < 180 + wi)
DrawIndicator(x + w, y + h / 2 + w / 2 * Sin(rot) / Cos(rot))
Else
' Zwei Seiten fehlen noch...
EndIf
End If
End Method

Method DrawIndicator(posx:Double, posy:Double)
DrawOval(PosX - 5, PosY - 5, 10, 10)
End Method
End Type

Local Rot:Double = 0
Local Rect:TRect = TRect.Create(100, 100, 200, 100)

Repeat
WaitTimer(FPSLimiter)
Cls()

Rect.Draw(rot)

Rot = (Rot + 0.5) Mod 360

Flip(0)
Until KeyHit(KEY_ESCAPE)
End


@Midimaster: Wie werden die anderen beiden Seiten ermittelt? Ich verstehe die Bedingung nicht so ganz. wi ist ein konstanter Wert für ein Rechteck (es sei denn, Höhe oder Breite werden angepasst). In welchem Bezug steht dieser Wert zu 180, Sprich: Wie kommen die Bedingungen zustande?
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Midimaster

BeitragSo, März 11, 2018 15:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Wi steht für den Winkel vom Mittelpunkt aus zu den 4 Ecken. Im Quadrat ist das immer 45°. Bei ungleichseitigem Rechteck berechnet sich der Winkel aus ATan2(h,w)

Die "waagrechte Achse" durch den Mittelpunkt ist 0° bzw. 180°. Davon weicht der Eckpunkt um den Winkel wi nach oben bzw. nach unten ab

Code: [AUSKLAPPEN]
      0°+wi      180°-wi
        ------------
        |           |
0°------|     °M    |----------- 180°
        |           |
         ------------
      0°-wi      180°+wi



Also gilt für die 4 Fälle

oben= (0°+wi) bis (180°-wi)
rechts= (180°-wi) bis (180°+wi)
unten= (180°+wi) bis (360°-wi)
rechts (360°-wi) bis (0°) und zusätzlich (0°) bis (0°+wi)


BlitzMax: [AUSKLAPPEN]
If rot >= wi And rot < 180-wi Then
'oben
bigPlot ...
ElseIf rot >= wi And rot < 180+wi Then
' rechts
bigPlot ...
ElseIf rot >= 180+wi And rot < 360+wi Then
'unten
bigPlot ...
ElseIf rot >= 360+wi And rot < 360 Then
'links bis 360°
bigPlot ...
ElseIf rot >= 0 And rot < wi Then
'links ab 0°
bigPlot ...
EndIf
.....
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe
 

CO2

ehemals "SirMO"

BeitragSo, März 11, 2018 19:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Ah, ok, verstanden Smile

Ich habe den Code nochmal editiert, jetzt klappt es für alle Winkel und alle Seiten BlitzMax: [AUSKLAPPEN]
Graphics(800, 600)
Local fpslimiter:TTimer = CreateTimer(60)

Type TRect
Field x:Double
Field y:Double
Field w:Double
Field h:Double

Function Create:TRect(x:Double, y:Double, w:Double, h:Double)
Local RetVal:TRect = New TRect
RetVal.x = X
RetVal.y = Y
RetVal.W = W
RetVal.H = H
Return RetVal
End Function

Method Draw(rot:Double)
DrawLine(x, y, x + W, y)
DrawLine(x, y, x, y + H)
DrawLine(x + W, y, x + W, y + H)
DrawLine(x, y + h, x + w, y + h)

If (rot < 0)
Repeat
rot = rot + 360
Until rot >= 0
End If

Local wi:Double = ATan2(h, w)

If (rot >= wi And rot < 180 - wi)
DrawIndicator(x + w / 2 - h / 2 * Cos(rot) / Sin(rot), y)
Else If (rot >= 180 - wi And rot < 180 + wi)
DrawIndicator(x + w, y + h / 2 + w / 2 * Sin(rot) / Cos(rot))
Else If (rot >= 180 + wi And rot < 360 - wi)
DrawIndicator(x + w - w / 2 + h / 2 * Cos(rot) / Sin(rot), y + h)
Else If ((rot >= 360 - wi And rot < 360) Or (rot >= 0 And rot < wi))
DrawIndicator(x, y + h - (h / 2 + w / 2 * Sin(rot) / Cos(rot)))
EndIf
End Method

Method DrawIndicator(posx:Double, posy:Double)
DrawOval(PosX - 5, PosY - 5, 10, 10)
End Method
End Type

Local Rot:Double = 360
Local Rect:TRect = TRect.Create(100, 100, 200, 100)

Repeat
WaitTimer(FPSLimiter)
Cls()

Rect.Draw(rot)

Rot = (Rot + 0.5) Mod 360

Flip(0)
Until KeyHit(KEY_ESCAPE)
End


Vielen Dank für eure Hilfe!
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti
  • Zuletzt bearbeitet von CO2 am Mo, März 12, 2018 19:26, insgesamt einmal bearbeitet

Midimaster

BeitragMo, März 12, 2018 9:24
Antworten mit Zitat
Benutzer-Profile anzeigen
Du musst keine Unterscheidung zwischen gleichseitigen und ungleichseitigen Rechtecken machen . Der ATan2() funktioniert in jeder Situation
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe
 

CO2

ehemals "SirMO"

BeitragMo, März 12, 2018 19:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe den Code im vorherigen Post angepasst, Danke nochmal Wink
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group