BPS #4: Vektoren - Auswertung

Übersicht BlitzBasic Beginners-Corner

Neue Antwort erstellen

Xeres

Moderator

Betreff: BPS #4: Vektoren - Auswertung

BeitragDo, März 17, 2011 21:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Damit ist die Zeit 'rum.

Das war die Aufgabe

Postet hier eure Ergebnisse, Codes, Gedanken. Lernt von den anderen, seht euch deren Quelltext an und versucht euren eigenen zu verbessern.

Diskussion
Postet zu euren Codes stets eine kurze Erklärung mit euren Gedanken in denen ihr simpel gesagt die Frage "Wieso habe ich XY auf diese Art gelöst?" beantwortet. Beiträge, die nur den Code enthalten werden wir aus dem Thread entfernen.

Nächste Aufgabe
In drei Tagen, am 20. März wird die Musterlösung nach editiert und die nächste Aufgabe eingestellt.

Viel Spaß & viel Erfolg!

Musterlösung:
BlitzBasic: [AUSKLAPPEN]
; BPS: Holzchopf - Vektoren

; ein paar Konstanten für die Übersichtlichkeit
Const WIDTH = 800 ; Breite (vom Grafikfenster)
Const HEIGHT = 600 ; Höhe
Const CENTER_X = WIDTH /2
Const CENTER_Y = HEIGHT /2

; Fenster initialisieren
Graphics WIDTH,HEIGHT,0,2
SetBuffer BackBuffer()
Global timer = CreateTimer(50)

; Deklarationen
Local mouseVector[1] ; Vektor zur Maus (0: X-Koordinate, 1: Y-Koordinate)
Local unitVector#[1] ; Normalisierter Maus-Vektor
Local orthVector[1] ; Vektor orthogonal zum Maus-Vektor

; Hauptschleife
While Not KeyDown(1)
; Vektor von der Bildschirmmitte zur Mausposition
mouseVector[0] = MouseX() -CENTER_X
mouseVector[1] = MouseY() -CENTER_Y

; Betrag (Länge) des Maus-Vektors
; Der Betrag kann mit dem Satz des Pythagoras berechnet werden.
Local mouseVectorLn# = Sqr(mouseVector[0]*mouseVector[0] +mouseVector[1]*mouseVector[1])
; Einheitsvektor bilden
; Einheitsvektoren sind Vektoren mit der Länge 1. Für einen gegebenen
; Vektor kann man den Einheitsvektor bilden, indem man ihn durch seinen
; Betrag (Länge) teilt.
; unitVector = mouseVector / ||mouseVector||
If mouseVectorLn>0 ; Nur normalisieren, wenn mouseVektor <> 0-Vektor
unitVector[0] = mouseVector[0] /mouseVectorLn
unitVector[1] = mouseVector[1] /mouseVectorLn
Else ; 0-Vektor -> Länge = 0 -> e-Vektor nicht definiert
unitVector[0] = 0
unitVector[1] = 0
EndIf

; orthogonalen Vektor erstellen...
; Orthogonale Vektoren lassen sich bilden, indem man die Komponenten
; eines Vektors vertauscht und bei einem das Vorzeichen wechselt.
; xo = -y1
; yo = x1
; ... und in der Länge halbieren
; Halbiert man die Komponenten eines Vektors, so halbiert sich auch der
; Betrag des ganzen Vektors.
orthVector[0] = -mouseVector[1] *0.5
orthVector[1] = mouseVector[0] *0.5

; Vektoren zeichnen (als Offset (Nullpunkt) wird immer die Bildschirm-
; mitte verwendet (deshalb werden CENTER_X /Y addiert)
; Maus-Vektor
Color 255,0,0
Line CENTER_X,CENTER_Y, CENTER_X+mouseVector[0], CENTER_Y+mouseVector[1]
; Einheitsvektor *(-100)
Color 0,0,255
Line CENTER_X,CENTER_Y, CENTER_X-unitVector[0] *100, CENTER_Y-unitVector[1]*100
; orthogonaler Vektor
Color 0,255,0
Line CENTER_X,CENTER_Y, CENTER_X+orthVector[0], CENTER_Y+orthVector[1]

; Double-Buffering
Flip 0
Cls
; FPS-Begrenzung
WaitTimer(timer)
Wend

End
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)
  • Zuletzt bearbeitet von Xeres am So, März 20, 2011 21:02, insgesamt einmal bearbeitet

darth

BeitragFr, März 18, 2011 15:25
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

ich habe den Tipp mit dem "Wähle Arrays (in BlitzMax) resp. BlitzArrays (in BlitzBasic) zum speichern der Vektoren" nicht wirklich verstanden. Statt eines Arrays benutze ich einen Type zum Sammeln der Koordinaten. (Sollte der Array natürlich so gemeint sein, dass ich meine Vektor-Instanzen in einem Array halte, dann ist es wieder klar :> ).

BlitzBasic: [AUSKLAPPEN]
Type TVector3D
Field x#
Field y#
Field z#

Field d#

Field u#
Field v#
End Type

Function newTVector3D.TVector3D(x#, y#, z#)
Local v.TVector3D = New TVector3D

v\x = x
v\y = y
v\z = z

Return v
End Function

Function vClone3D.TVector3D(v.TVector3D)
Local r.TVector3D

r\x = v\x
r\y = v\y
r\z = v\z

Return r
End Function

Function vAdd3D( v.TVector3D, o.TVector3D )
v\x = v\x + o\x
v\y = v\y + o\y
v\z = v\z + o\z
End Function

Function nAdd3D.TVector3D( a.TVector3D, b.TVector3D )
Local r.TVector3D = New TVector3D

r\x = a\x + b\x
r\y = a\y + b\y
r\z = a\z + b\z

Return r
End Function

Function vSub3D( v.TVector3D, o.TVector3D )
v\x = v\x - o\x
v\y = v\y - o\y
v\z = v\z - o\z
End Function

Function nSub3D.TVector3D( a.TVector3D, b.TVector3D )
Local r.TVector3D = New TVector3D

r\x = a\x - b\x
r\y = a\y - b\y
r\z = a\z - b\z

Return r
End Function

Function vMult3D( v.TVector3D, s# )
v\x = v\x *s
v\y = v\y *s
v\z = v\z *s
End Function

Function nMult3D.TVector3D( v.TVector3D, s# )
Local r.TVector3D = New TVector3D

r\x = v\x *s
r\y = v\y *s
r\z = v\z *s

Return r
End Function

Function vNormalise3D(v.TVector3D)
Local il# = 1./Sqr(v\x*v\x + v\y*v\y + v\z*v\z)

v\x = v\x *il
v\y = v\y *il
v\z = v\z *il
End Function

Function vDot3D#(v1.TVector3D, v2.TVector3D)
Return v1\x*v2\x + v1\y*v2\y + v1\z*v2\z
End Function

Function vCross3D.TVector3D(v1.TVector3D, v2.TVector3D)
Return newTVector3D(v1\y*v2\z-v2\y*v1\z, v2\x*v1\z-v1\x*v2\z, v1\x*v2\y-v2\x*v1\y)
End Function

Function vDist3D#(v1.TVector3D, v2.TVector3D)
Return Sqr( (v1\x-v2\x)*(v1\x-v2\x) + (v1\y-v2\y)*(v1\y-v2\y) + (v1\z-v2\z)*(v1\z-v2\z) )
End Function

Function vLength3D#(v.TVector3D)
Return Sqr( v\x*v\x + v\y*v\y + v\z*v\z )
End Function

Function vReflect3D.TVector3D(v.TVector3D, n.TVector3D)
Local vs.TVector3D
Local dp#, nl#

vs = New TVector3D

nl = vLength3D(n)
dp = 2*vDot3D(v, n) /(nl *nl)

vs\x = v\x -dp *n\x
vs\y = v\y -dp *n\y
vs\z = v\z -dp *n\z

Return vs
End Function

Function lineSegmentIntersect3D.TVector3D(p1.TVector3D, p2.TVector3D, p3.TVector3D, p4.TVector3D)
Local EPS#=10^-8

Local p13.TVector3D, p43.TVector3D, p21.TVector3D
Local d1343#, d4321#, d1321#, d4343#, d2121#
Local numer#, denom#, mua#, mub#

p13=newTVector3D(p1\x-p3\x, p1\y-p3\y, p1\z-p3\z)

p43=newTVector3D(p4\x-p3\x, p4\y-p3\y, p4\z-p3\z)
If Abs(p43\x)<EPS And Abs(p43\y)<EPS And Abs(p43\z)<EPS
Delete p13
Delete p43

Return Null
EndIf

p21=newTVector3D(p2\x-p1\x, p2\y-p1\y, p2\z-p1\z)
If Abs(p21\x)<EPS And Abs(p21\y)<EPS And Abs(p21\z)<EPS
Delete p13
Delete p43
Delete p21

Return Null
EndIf

d1343 = p13\x * p43\x + p13\y * p43\y + p13\z * p43\z
d4321 = p43\x * p21\x + p43\y * p21\y + p43\z * p21\z
d1321 = p13\x * p21\x + p13\y * p21\y + p13\z * p21\z
d4343 = p43\x * p43\x + p43\y * p43\y + p43\z * p43\z
d2121 = p21\x * p21\x + p21\y * p21\y + p21\z * p21\z

denom = d2121*d4343 -d4321*d4321
If Abs(denom)<EPS
Delete p13
Delete p43
Delete p21

Return Null
EndIf

numer=d1343*d4321 -d1321*d4343

mua=numer/denom
mub=(d1343+d4321*mua)/d4343

Local pA.TVector3D=newTVector3D(p1\x+mua*p21\x, p1\y+mua*p21\y, p1\z+mua*p21\z)
Local pB.TVector3D=newTVector3D(p3\x+mub*p43\x, p3\y+mub*p43\y, p3\z+mub*p43\z)

Delete p13
Delete p43
Delete p21

If equalPoints3D(pA, pB)
If mua>=0 And mua<=1 And mub>=0 And mub<=1
Delete pB
Return pA
EndIf
EndIf

Delete pA
Delete pB

Return Null
End Function

Function equalPoints3D(p1.TVector3D, p2.TVector3D)
Local dist#=0.5

If p1=p2
Return True
EndIf

If Abs(p1\x-p2\x)<dist And Abs(p1\y-p2\y)<dist And Abs(p1\z-p2\z)<dist
Return True
EndIf

Return False
End Function

Graphics 800, 600, 0, 2
SetBuffer BackBuffer()

Origin 400, 300

; O: Ursprung des Systems (für Maus-Transformation)
; N: Normale des Systems
Local O.TVector3D = newTVector3D(400, 300, 0)
Local N.TVector3D = newTVector3D(0, 0, 1)

Local M1.TVector3D, M2.TVector3D, M3.TVector3D

While Not KeyHit(1)

; Ursprung
Line -10, 0, 10, 0
Line 0, -10, 0, 10

; Weil die Mauskoordinaten sich nicht an den Origin angleichen,
; muss man den Mittelpunkt noch abziehen (verschieben)
M1 = newTVector3D(MouseX(), MouseY(), 0)
vSub3D(M1, O)

; Vektor umkehren, normalisieren, strecken
; (umkehren und strecken ginge in einem, aber dann müsste ich klonen)
M2 = nMult3D(M1, -1)
vNormalise3D(M2)
vMult3D(M2, 100)

; Kreuzprodukt zwischen Vektor und Bildschirmnormale gibt Normale
; Länge erhalten
M3 = vCross3D(M1, N)
vMult3D(M3, 0.5)

Line 0, 0, M1\x, M1\y
Line 0, 0, M2\x, M2\y
Line 0, 0, M3\x, M3\y

Flip 0
Cls
Wend
End


Ich habe das Problem in 3 Dimensionen implementiert. Der Grund ist ziemlich einfach, runterskalieren kann man immer, hochskalieren braucht Arbeit. Simpel gesagt: Wer von 3D auf 2D will, lässt einfach die letzte Dimension weg Smile
So kann man auch die Normale zu einem Vektor ziemlich einfach ausrechnen, indem man das Kreuzprodukt zwischen dem Vektor und der "Bildschirmnormale" (also der Vektor der senkrecht zur Bildschirmebene steht) berechnet. Natürlich kommt dabei immer nur ein 2D Vektor heraus, der die gleiche Länge hat wie der Alte.

Im Programm habe ich den BildschirmUrpsrung (Origin) auf die Mitte gesetzt. Leider hat dies keinen Einfluss auf die MausX() / MausY() Befehle, darum muss ich diesen Ursprung von meinem Maus-Vektor noch abziehen, danach kann man ganz normal weiterrechnen.

Es sind noch ein paar andere Funktionen dabei, die nicht zur Aufgabenstellung gehören, kann man getrost ignorieren. Sie sollten von den Namen her eigentlich ziemlich selbsterklärend sein, weshalb ich es hier (weil es ja nicht zur Aufgabe gehört) einfach so stehen lasse.

Das wärs von meiner Seite,
MfG,
Darth
Diese Signatur ist leer.

Holzchopf

Meisterpacker

BeitragSa, März 19, 2011 15:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Sehr schön. Der Ansatz mit der Skalierbarkeit gefällt mir. Ist ein sehr interessanter Gedanke. Types sind natürlich immer chic und eigentlich auch den Arrays vorzuziehen, da ihre Felder klar definiert sind und oft auch deutlich besser zu lesen sind und somit auch beim programmieren einfacher zu handhaben sind (meine Meinung). Allerdings (wieder meine Meinung) sind Arrays am Anfang (einer Programmiererkarriere) einfacher zu verstehen, daher der Tipp. Und "im mathematischen Sinne" sind ja Vektoren auch Arrays, wenn man sich mal an Taschenrechnern und Mathe-Programmen orientiert, daher ist es in diesem Fall gar nicht sooo verkehrt, auf Arrays zurückzugreifen.

Auf jeden Fall danke für deine saubere Lösung.

mfG
Holzchopf
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

ToeB

BeitragSa, März 19, 2011 15:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Sehr schön gemacht, aber wenn mich nicht alles Täuscht erstellst du jeden Schleifendurchgang einen Vektor und Löschst ihn hinterher nicht mehr.. Villeicht wäre das noch ne kleine Verbesserung.


mfg ToeB
Religiöse Kriege sind Streitigkeiten erwachsener Männer darum, wer den besten imaginären Freund hat.
Race-Project - Das Rennspiel der etwas anderen Art
SimpleUDP3.0 - Neuste Version der Netzwerk-Bibliothek
Vielen Dank an dieser Stelle nochmal an Pummelie, welcher mir einen Teil seines VServers für das Betreiben meines Masterservers zur verfügung stellt!

darth

BeitragSa, März 19, 2011 17:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

jup ToeB, du hast recht. Hab ich vergessen zu erwähnen. Ich haushalte meine Vektoren nicht \o/ Wenn man das Programm zu lange laufen lässt, wird es abstürzen, weil irgendwann der Speicher überquillt. Das ist (meine Meinung..) eine ziemlich nervige Eigenart der BB-Types. Aber so ist es einfacher, Listen seiner Objekte zu machen, ist halt ein abwägen.

Mit den Arrays hast du schon recht Holzchopf, ich (denke ich) verstehe nun wie der Tipp gemeint war. Man könnte es eigentlich auch verbinden und einen Blitz-Array statt x/y/z nehmen. Ich bin mir nicht ganz sicher, wie es mit den Zugriffszeiten wäre, aber (meine Meinung) ich halte es für einfacher lesbar wenn ich einfach v\x schreiben kann, statt v\entry[0] (oder nur vektor[0]). Ansichtssache Smile
Allerdings, da gebe ich dir recht, ist es für Einsteiger einfacher mit Arrays, v.a aufgrund des Punktes, den ToeB angesprochen hat. Sorgfalt ist nicht jedermanns Sache (und schon gar nicht meine, hihi).

Btw hab ich auch eine Implementation mit Matrizen, sollte irgendwo in meinem Worklog sein. (Schamlose Eigenwerbung, jup!)

MfG,
Darth
Diese Signatur ist leer.

Xeres

Moderator

BeitragSo, März 20, 2011 21:03
Antworten mit Zitat
Benutzer-Profile anzeigen
Besten Dank an darth... Schade das sich nicht mehr Beteiligt haben, aber vielleicht kommt mit der Zeit ja noch was dazu; Fragen & Anregungen sind und bleiben erwünscht.

Die Musterlösung findet sich im Eingangspost.
Win10 Prof.(x64)/Ubuntu 16.04|CPU 4x3Ghz (Intel i5-4590S)|RAM 8 GB|GeForce GTX 960
Wie man Fragen richtig stellt || "Es geht nicht" || Video-Tutorial: Sinus & Cosinus
T
HERE IS NO FAIR. THERE IS NO JUSTICE. THERE IS JUST ME. (Death, Discworld)

Nova

BeitragSa, Jun 02, 2012 8:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Xeres hat Folgendes geschrieben:
Schade das sich nicht mehr Beteiligt haben, aber vielleicht kommt mit der Zeit ja noch was dazu; Fragen & Anregungen sind und bleiben erwünscht.

Tja, über ein Jahr zu spät, aber jetzt kommt meine Lösung. Very Happy


Zu Anfang hatte ich ein Problem damit, überhaupt mal mitzukriegen, dass ich die Mitte des Fensters als Koordinate (0|0) definieren muss. Vorher hat sich mein orthogonaler Vektor immer irgendwo lang bewegt, nur nicht da, wo er hin sollte. ^^
Nachdem das aber behoben wurde war es recht einfach.

BlitzBasic: [AUSKLAPPEN]
; Definiere ein paar Konstanten
Const AUFLOESUNGX = 640
Const AUFLOESUNGY = 460
Const MITTEX = 320
Const MITTEY = 230

; Bereite alles vor, also die Grafik und die Timer
Graphics 640, 480, 0, 2
SetBuffer BackBuffer()
timer = CreateTimer(60)

; Definiere ein paar wichtige Variablen
Local normalX = 0
Local normalY = 0
Local orthogonalX = 0
Local orthogonalY = 0
Local normalLaenge# = 0
Local gegenX = 0
Local gegenY = 0


; Nun setzen wir noch die Hintergrundfarbe auf weiß...
ClsColor 255, 255, 255

; Und schon gehen wir in die Hauptschleife und starten das Programm
While Not KeyHit(1) ; Programm beenden mit Escape.
Cls
Color 0, 0, 0
Text 1, 1, "Escape zum Beenden des Programms"


Color 255, 0, 0
; Berechne den normalen Vektor:
normalX = MouseX () - MITTEX
normalY = MouseY () - MITTEY
; Zeichne ihn:
Line MITTEX, MITTEY, normalX + MITTEX, normalY + MITTEY


Color 0, 255, 0
; Berechne den "orthogonalen" Vektor:
If normalX = 0 Then
orthogonalX = 0
Else
orthogonalX = normalY / 2
EndIf
If normalY = 0 Then
orthogonalY = 0
Else
orthogonalY = normalX / -2
EndIf
; Zeichne ihn:
Line MITTEX, MITTEY, orthogonalX + MITTEX, orthogonalY + MITTEY


Color 0, 0, 255
; Berechne den Gegenvektor zum normalen Vektor:
normalLaenge = Sqr (normalX ^2 + normalY ^2)
Text 1, 22, normalLaenge
If normalLaenge = 0 Then
gegenX = 0
Else
gegenX = ((-normalX) / normalLaenge) *100
EndIf
If normalLaenge = 0 Then
gegenY = 0
Else
gegenY = ((-normalY) / normalLaenge) *100
EndIf
; Zeichne ihn:
Text 1, 11, gegenX + " " + gegenY
Line MITTEX, MITTEY, gegenX + MITTEX, gegenY + MITTEY


WaitTimer timer
Flip
Wend

End ; Hier wird das Programm dann beendet.


; Definition der verwendeten Funktionen.
Function abstand (x1, y1, x2, y2)
Local abstandX = Abs (x1 - x2)
Local abstandY = Abs (y1 - y2)

Return Sqr ((abstandX ^2) + (abstandY ^2))
End Function
AMD Athlon II 4x3,1GHz, 8GB Ram DDR3, ATI Radeon HD 6870, Win 7 64bit

Neue Antwort erstellen


Übersicht BlitzBasic Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group