Vektoren

    • VB.NET

    Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

      Hallo Forum, ich dachte ich schreibe mal drei Strukturen zu Vektoren (Vector2D, Vector3D, Vector4D).
      Ich habe folgende Funktionen eingebaut:

      Operatoren:
      - * (Vector & Double)
      - * (Double & Vector)
      - / (Vector & Double)
      - + (Vector & Vector)
      - - (Vector & Vector)

      Eigenschaften (alle Datentyp Double):

      Vector2D:
      - X
      - Y
      - Length

      Vector3D:
      - X
      - Y
      - Z
      - Length

      Vector4D:

      - X
      - Y
      - Z
      - W
      - Length

      Subs:

      - New (Konstruktor)

      Functions:

      - Normalize
      - ScalarProduct
      - IsOrthogonal
      - ToString
      - CrossProduct (bei Vector3D)

      Es sind also nur die wichtigsten Funktionen, damit man aber sieht wie man Vektoren in Visual Basic umsetzen kann, reicht es hoffentlich.

      Spoiler anzeigen

      VB.NET-Quellcode

      1. Option Strict On
      2. Imports System.Math
      3. Public Structure Vector2D
      4. Public Sub New(ByVal xx As Double, ByVal yy As Double)
      5. X = xx
      6. Y = yy
      7. End Sub
      8. Public Property X() As Double
      9. Public Property Y() As Double
      10. Public ReadOnly Property Length() As Double
      11. Get
      12. Return Sqrt(Pow(X, 2) + Pow(Y, 2))
      13. End Get
      14. End Property
      15. Public Shared Operator +(ByVal v1 As Vector2D, ByVal v2 As Vector2D) As Vector2D
      16. Return New Vector2D(v1.X + v2.X, v1.Y + v2.Y)
      17. End Operator
      18. Public Shared Operator -(ByVal v1 As Vector2D, ByVal v2 As Vector2D) As Vector2D
      19. Return New Vector2D(v1.X - v2.X, v1.Y - v2.Y)
      20. End Operator
      21. Public Shared Operator *(ByVal v1 As Vector2D, ByVal d As Double) As Vector2D
      22. Return New Vector2D(v1.X * d, v1.Y * d)
      23. End Operator
      24. Public Shared Operator *(ByVal d As Double, ByVal v1 As Vector2D) As Vector2D
      25. Return New Vector2D(v1.X * d, v1.Y * d)
      26. End Operator
      27. Public Shared Operator /(ByVal v1 As Vector2D, ByVal d As Double) As Vector2D
      28. Return New Vector2D(v1.X / d, v1.Y / d)
      29. End Operator
      30. Public Overrides Function ToString() As String
      31. Return String.Format("({0},{1})", x, y)
      32. End Function
      33. Public Shared Function Normalize(ByVal v1 As Vector2D) As Vector2D
      34. Return v1 / v1.Length
      35. End Function
      36. Public Shared Function ScalarProduct(ByVal v1 As Vector2D, ByVal v2 As Vector2D) As Double
      37. Return v1.X * v2.X + v1.Y * v2.Y
      38. End Function
      39. Public Shared Function IsOrthogonal(ByVal v1 As Vector2D, ByVal v2 As Vector2D) As Boolean
      40. If Double.Equals(ScalarProduct(v1, v2), 0) Then Return True
      41. Return False
      42. End Function
      43. End Structure
      44. Public Structure Vector3D
      45. Public Sub New(ByVal xx As Double, ByVal yy As Double, ByVal zz As Double)
      46. X = xx
      47. Y = yy
      48. Z = zz
      49. End Sub
      50. Public Property X() As Double
      51. Public Property Y() As Double
      52. Public Property Z() As Double
      53. Public ReadOnly Property Length() As Double
      54. Get
      55. Return Sqrt(Pow(X, 2) + Pow(Y, 2) + Pow(Z, 2))
      56. End Get
      57. End Property
      58. Public Shared Operator +(ByVal v1 As Vector3D, ByVal v2 As Vector3D) As Vector3D
      59. Return New Vector3D(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z)
      60. End Operator
      61. Public Shared Operator -(ByVal v1 As Vector3D, ByVal v2 As Vector3D) As Vector3D
      62. Return New Vector3D(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z)
      63. End Operator
      64. Public Shared Operator *(ByVal v1 As Vector3D, ByVal d As Double) As Vector3D
      65. Return New Vector3D(v1.X * d, v1.Y * d, v1.Z * d)
      66. End Operator
      67. Public Shared Operator *(ByVal d As Double, ByVal v1 As Vector3D) As Vector3D
      68. Return New Vector3D(v1.X * d, v1.Y * d, v1.Z * d)
      69. End Operator
      70. Public Shared Operator /(ByVal v1 As Vector3D, ByVal d As Double) As Vector3D
      71. Return New Vector3D(v1.X / d, v1.Y / d, v1.Z / d)
      72. End Operator
      73. Public Overrides Function ToString() As String
      74. Return String.Format("({0},{1},{2})", X, Y, Z)
      75. End Function
      76. Public Shared Function Normalize(ByVal v1 As Vector3D) As Vector3D
      77. Return v1 / v1.Length
      78. End Function
      79. Public Shared Function ScalarProduct(ByVal v1 As Vector3D, ByVal v2 As Vector3D) As Double
      80. Return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z
      81. End Function
      82. Public Shared Function IsOrthogonal(ByVal v1 As Vector3D, ByVal v2 As Vector3D) As Boolean
      83. If Double.Equals(ScalarProduct(v1, v2), 0) Then Return True
      84. Return False
      85. End Function
      86. Public Shared Function CrossProdukct(ByVal v1 As Vector3D, ByVal v2 As Vector3D) As Vector3D
      87. Return New Vector3D(v1.Y * v2.Z - v1.Z * v2.Y, v1.Z * v2.X - v1.X * v2.Z, v1.X * v2.Y - v1.Y * v2.X)
      88. End Function
      89. End Structure
      90. Public Structure Vector4D
      91. Public Sub New(ByVal xx As Double, ByVal yy As Double, ByVal zz As Double, ByVal ww As Double)
      92. X = xx
      93. Y = yy
      94. Z = zz
      95. W = ww
      96. End Sub
      97. Public Property X() As Double
      98. Public Property Y() As Double
      99. Public Property Z() As Double
      100. Public Property W() As Double
      101. Public ReadOnly Property Length() As Double
      102. Get
      103. Return Sqrt(Pow(X, 2) + Pow(Y, 2) + Pow(Z, 2) + Pow(W, 2))
      104. End Get
      105. End Property
      106. Public Shared Operator +(ByVal v1 As Vector4D, ByVal v2 As Vector4D) As Vector4D
      107. Return New Vector4D(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z, v1.W + v2.W)
      108. End Operator
      109. Public Shared Operator -(ByVal v1 As Vector4D, ByVal v2 As Vector4D) As Vector4D
      110. Return New Vector4D(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z, v1.W - v2.W)
      111. End Operator
      112. Public Shared Operator *(ByVal v1 As Vector4D, ByVal d As Double) As Vector4D
      113. Return New Vector4D(v1.X * d, v1.Y * d, v1.Z * d, v1.W * d)
      114. End Operator
      115. Public Shared Operator *(ByVal d As Double, ByVal v1 As Vector4D) As Vector4D
      116. Return New Vector4D(v1.X * d, v1.Y * d, v1.Z * d, v1.W * d)
      117. End Operator
      118. Public Shared Operator /(ByVal v1 As Vector4D, ByVal d As Double) As Vector4D
      119. Return New Vector4D(v1.X / d, v1.Y / d, v1.Z / d, v1.W / d)
      120. End Operator
      121. Public Overrides Function ToString() As String
      122. Return String.Format("({0},{1},{2},{3})", X, Y, Z, W)
      123. End Function
      124. Public Shared Function Normalize(ByVal v1 As Vector4D) As Vector4D
      125. Return v1 / v1.Length
      126. End Function
      127. Public Shared Function ScalarProduct(ByVal v1 As Vector4D, ByVal v2 As Vector4D) As Double
      128. Return v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z + v1.W * v2.W
      129. End Function
      130. Public Shared Function IsOrthogonal(ByVal v1 As Vector4D, ByVal v2 As Vector4D) As Boolean
      131. If Double.Equals(ScalarProduct(v1, v2), 0) Then Return True
      132. Return False
      133. End Function
      134. End Structure


      Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „TheVBTutorialsVB“ () aus folgendem Grund: Update

      Sieht doch richtig gut aus :thumbsup:. Das einzigste, was mir noch einfallen würde, wäre, dass du die Properties von X, Y, ... in der Kurzschreibweise (nur die erste Zeile der Property) verfasst, dann kannst du auch auf die Private xx, yy, ... verzichten :). Ansonsten ist es doch so gut wie perfekt.
      Welchen mathematischen Hintergrund haben diese Funktionen:

      TheVBTutorialsVB schrieb:

      VB.NET-Quellcode

      1. Public Shared Operator *(ByVal v1 As Vector2D, ByVal v2 As Vector2D) As Vector2D
      2. Return New Vector2D(v1.X * v2.X, v1.Y * v2.Y)
      3. End Operator
      4. Public Shared Operator /(ByVal v1 As Vector2D, ByVal v2 As Vector2D) As Vector2D
      5. Return New Vector2D(v1.X / v2.X, v1.Y / v2.Y)
      6. End Operator
      analog V3, V4 ?
      Bei der Funktion IsOrthogonal würde ich nicht auf = 0 testen, sondern auf Math.Abs(Skalarprodukt(...) < Epsilon)
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Das scheint mir ein Problem von so Lösungen ohne konkretes Problem: Da kann man sich jetzt tagelang weitere Features für ausdenken, etwa beim 2D-Vector Kompatiblität zu System.Drawing.PointF, und System.Drawing.Drawing2D.Matrix, damit man ordentliche Matrix-Transformationen mit dem Zeugs treiben kann.
      Oder man möchte die Konversion in Polar-Koordinaten haben, was manchmal ja auch sehr nützlich ist.

      Also lass dir hier kein Lebenswerk aufschwätzen, was am Ende doch keiner benutzt.
      Ach ja, ganz vergessen: Sowas hat Artentus schon in seinem Projekt MathUtils integriert, kannst ja da mal vorbeischauen: [OpenSource] MathUtils 2.4 - erweiterte Mathematikbibliothek
      Ich habe auch mal sowas gemacht. Siehe hier bzw. hier.

      Deine Vector2D-Klasse könnte noch einen Konstruktor oder einen Cast-Operator gebrauchen, um einen Vector2D aus einem Punkt zu erstellen. Außerdem könnte man noch eine Betrags-Funktion (Abs, Länge) hinzufügen und readonly, statische Eigenschaften/Felder wie "Zero" (Vector3D(0)), "Up" (Vector3D(1,0,0)), "Down" (usw.), "Left" für bestimtme Vektoren bereitstellen.

      Kannst dich ja auch noch von den XNA-Vektoren inspirieren lassen:
      msdn.microsoft.com/en-us/libra…work.vector2_members.aspx
      msdn.microsoft.com/en-us/libra…work.vector3_members.aspx
      Von meinem iPhone gesendet
      Danke an alle für die Kritik. Ich werde mich nochmal ransetzen, hatte in den letzten Tagen kaum Zeit.

      RodFromGermany schrieb:

      Bei der Funktion IsOrthogonal würde ich nicht auf = 0 testen, sondern auf Math.Abs(Skalarprodukt(...) < Epsilon)


      Dazu habe ich eine Frage. Es muss doch 0 sein, damit sie senkrecht sind. Wieso soll ichs dann anders überprüfen? Dauert der Methodenaufruf nicht länger als der direkte Vergleich? Ich glaub dir zwar dass das besser ist, aber ich verstehe nicht warum...kannste das bitte erklären? ^^

      @TheVBTutorialsVB
      Ein Double ist nicht genau. Wenn die Werte zu viele Stellen haben, dann kann ein korrektes Ergebnis auf != 0 nicht mehr gewährleistet werden. Wenn der Gleitkommafehler nur 0,0000000000001 beträgt, dann ist es schon != 0. Deswegen prüft man nicht auf == 0, sondern ob es fast 0 ist. Epsilon gibt dabei die Toleranz an.

      TheVBTutorialsVB schrieb:

      Es muss doch 0 sein, damit sie senkrecht sind.
      Das ist mathematisch gesehen vollkommen korrekt. In der Informatik kommt es allerdings vor, dass bei einer Kommazahl nicht die gleiche Zahl rauskommt, wie ursprünglich abgespeichert wurde. Das hängt damit zusammen, wie Floats im Speicher abgelegt werden.
      Dieser Effekt äußert sich z. B. so:
      ideone.com/ub9ovu
      Siehe dort:
      msdn.microsoft.com/en-us/library/system.double.epsilon.aspx

      TheVBTutorialsVB schrieb:

      Dauert der Methodenaufruf nicht länger als der direkte Vergleich?
      Das ist korrekt, allerdings ist so mehr sichergestellt, dass das "richtige" Ergebnis rauskommt. Wenn man auf performanz aus ist, würde man das wahrscheinlich auch anders lösen.
      Von meinem iPhone gesendet

      TheVBTutorialsVB schrieb:

      VB.NET-Quellcode

      1. Public Structure Vector2D

      VB.NET-Quellcode

      1. Public Overrides Function ToString() As String
      2. Return "(" & X.ToString & "," & Y.ToString & ")"
      3. End Function
      4. Public Shared Function Normalize(ByVal v1 As Vector2D) As Vector2D
      5. Return 1 / v1.Length * v1
      6. End Function
      Mach da und aus den anderen dies draus:

      VB.NET-Quellcode

      1. Public Overrides Function ToString() As String
      2. Return String.Format("({0},{1})", x, y)
      3. End Function
      4. Public Shared Function Normalize(ByVal v1 As Vector2D) As Vector2D
      5. Return v1 / v1.Length
      6. End Function
      Und mach da ggf. eine serialisierbare Klasse draus.
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!

      ErfinderDesRades schrieb:

      oder?
      Nein, ich meine eine

      VB.NET-Quellcode

      1. <Serializable()> Public Class Vector2D
      2. ' Stuff
      3. End Class
      Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
      Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
      Ein guter .NET-Snippetkonverter (der ist verfügbar).
      Programmierfragen über PN / Konversation werden ignoriert!
      Hi
      Structure ist in diesem Fall besser geeignet, zumal auch die Effizienz besser ist, gerade, weil sehr viele Referenzen benötigt würden. So würden nur durch Boxing weitere Instanzen erzeugt. Vector# ist außerdem an sich eine atomare Größe und benötigt semantisch keine Verweise auf eine ihrer Instanzen.

      Gruß
      ~blaze~