Drehung und Projektion einer Ebene.

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 35 Antworten in diesem Thema. Der letzte Beitrag () ist von Bartosz.

    @Bartosz

    Bartosz schrieb:

    @-Franky- Danke für den Link. Wie kann ich das einbauen / aufrufen? Hast du ein kleines Beispiel?

    Im Prinzip läuft die ganze Geschichte dann über diverse WIC-, D2D1-, D3D11- und DXGI-COM Interfaces (WIC nur weil ich darüber das Bild von der Platte lade). Das kann man nicht so einfach erklären bzw. würde hier den Rahmen sprengen. Das was Du auf dem Bild von mir siehst, ist mal vor 2 Jahren in VB6 entstanden. Entsprechend habe ich auch nur VB6-Code. Das nach .NET umzubauen, ohne Fremdkomponenten\Wrapper\Verweise, wäre zwar machbar, braucht aber halt viel Zeit und man muss sich mit DirectX beschäftigen. Allein das Interface ID2D1DeviceContext besitzt schon sehr viele Funktionen und erbt Funktionen von ID2D1RenderTarget und das wiederum Funktionen von ID2D1Resource und das von IUnknown. Gebraucht werden aber nur ein paar Funktionen aus diesen COM Interfaces. Nur allein diese COM Interfaces direkt in .NET einzubauen ist schon eine Aufgabe (das ist in VB6 bedeutend einfacher), falls man keine externen Komponenten, Wrapper bzw Verweise verwenden möchte.

    Falls Du Dich dennoch darin einlesen möchtest:
    docs.microsoft.com/en-us/windo…ply-effects-to-primitives
    docs.microsoft.com/en-us/windo…vices-and-device-contexts
    Mfg -Franky-
    Vielleicht ist das ja hilfreich:

    Es gibt verschiedene Arten etwas zu Projizieren, hier in aller Kürze ein paar:

    Projektion auf die XY-Ebene:

    $P_{xy} = \begin{pmatrix}1 & 0 & 0 \\ 0 &1 & 0 \\ 0 & 0 & 0 \end{pmatrix}$


    Multipliziert man einen Vektor
    $(x,y,z)^T$
    mit der Matrix
    $P_{xy}$
    werden nur die X,Y Komponenten verwendet:

    $ P_{xy} \cdot \begin{pmatrix}x \\ y \\ z \end{pmatrix} = \begin{pmatrix}1 & 0 & 0 \\ 0 &1 & 0 \\ 0 & 0 & 0\end{pmatrix} \begin{pmatrix}x \\ y \\ z \end{pmatrix} = \begin{pmatrix}x \\ y \\ 0 \end{pmatrix}$


    Projektion auf die Z-Achse:

    $P_{z} = \begin{pmatrix}0 & 0 & 0 \\ 0 &0 & 0 \\ 0 & 0 & 1\end{pmatrix}$


    Multipliziert man einen Vektor
    $(x,y,z)^T$
    mit der Matrix
    $P_{z}$
    wird nur die Z Komponente verwendet:

    $P_{z} \cdot \begin{pmatrix}x \\ y \\ z \end{pmatrix}= \begin{pmatrix}0 & 0 & 0 \\ 0 &0 & 0 \\ 0 & 0 & 1\end{pmatrix} \cdot \begin{pmatrix}x \\ y \\ z \end{pmatrix} = \begin{pmatrix}0 \\ 0 \\ z \end{pmatrix}$


    Translation:

    $\begin{pmatrix} 1 & 0 & 0 & X \\ 0 & 1 & 0 & Y \\ 0 & 0 & 1 & Z \\ 0 & 0 & 0 & 1\end{pmatrix}\begin{pmatrix} a_1 \\ a_2 \\ a_3 \\ 1\end{pmatrix} = \begin{pmatrix} a_1 + X \\ a_2 + Y \\ a_3 + Z \\ 1\end{pmatrix} $


    Allgemein
    wird eine Projektionsmatrix zu einem Vektor
    $\mathbf{a}$
    so bestimmt:

    $P = \frac{aa^T}{a^Ta}$


    Das ist recht nett, weil mit
    $P$
    kann ich nun jeden Vektor
    $\mathbf{b}$
    auf
    $\mathbf{a}$
    projizieren :)

    Vielleicht noch nebenbei gesagt, der Punkt in deiner Gleichung oben mit dem
    $N$
    ist, dass es sich hierbei um ein Skalarprodukt handelt!

    Dieser Beitrag wurde bereits 17 mal editiert, zuletzt von „VB.neter0101“ ()

    @Bartosz

    Ich gesell mich auch noch kurz dazu.

    Dein Projekt in #5 habe ich mir kurz runtergeladen. Scheint mir tatsächlich ein schöner Gimbal Lock Effekt zu sein.
    de.wikipedia.org/wiki/Gimbal_Lock

    Und wahrscheinlich hast du es mittlerweile schon gelöst bekommen.


    Ich habe dir hier zwei Links für die gewünschten Matrix-Formeln.

    Einfach eine genial erklärte Übersicht. Besser findet man es wahrscheinlich nirgendswo.
    docplayer.org/30910350-Repraes…ometrischen-objekten.html

    Und hier eine weitere kleine gute Zusammenfassung.
    cg.tuwien.ac.at/courses/CG1/textblaetter/02 Geometrische Transformationen.pdf


    Eventuell wäre ein Wechsel zu den Quaternionen auch eine passende Alternative. Anschauen lohnt sich auf jeden Fall.
    https://de.wikipedia.org/wiki/Quaternion
    cbcity.de/tutorial-rotationsma…n-din70000-zyx-konvention

    Freundliche Grüsse

    exc-jdbi
    Gut, ich hab's nun ein wenig anders gemacht. Ich wollte eh von trigonometrischen Funktionen weg...
    Folgendes Beispiel: Ich habe wieder meine um 20° um die y-Achse gedreht Ebene. Wieder mit dem Online-Tool gezeichnet. Ich habe festgestellt, dass das Tool die Ansicht bös falsch darstellt. Die Ebene wird viel länger gezeichnet, als sie zu sein hat. Logisch, denn ich kann ja keine Begrenzung eingeben, demnach läuft sie nach mathematischer Definition ins Unendliche und das Tool stellt sie viel breiter dar, als sie sein soll. Also nehmen wir an, die Ebene soll 10 LE in jede Richtung haben. Also endet sie an den roten Linien, die ich ins Bild gezeichnet habe!
    Ich habe, wie im letzten Post erwähnt, eine neue Klasse geschrieben. Hier ist die Dokumentation.
    Vektor a1 läuft auf der Ebene mit, a2 ist der runterprojizierte Vektor (danke hier an @VB.neter0101). a2 ist also die blanke Entfernung vom Ursprung zum Rand, und das Ganze
    $ ursprüngliche Länge der Ebene \cdot cos(α)$
    , da die Seite beim Drehen kleiner aussehen muss. In die andere Richtung läuft b2, der hat einfach nur ein anderes Vorzeichen, also auch nichts Schlimmes.
    Um jetzt von a2 nach oben in die linke Ecke zu kommen – und da hab ich mich in der Vergangenheit etwas schwer getan – habe ich jetzt mal probehalber C1 gebildet. Der Vektor läuft auf der Ebene lang. Ich habe festgestellt, C2 ist einfach der Pythagoras von der eingestellten Größe (10) und der z-Komponente der Ebene, also
    $\sqrt(10^{2}+3,4202^{2})=10,568 $
    .
    Die rechte Seite, C3, ist dann
    $ 10-( \sqrt(10^{2}+3,4202^{2})-10)=9,43 $

    Ja, und nach unten einfach umgekehrte Vorzeichen.

    Für die Drehung um die x-Achse gilt: was links unten war, wird links oben. xneu = y und yneu = -x



    Worum ich euch gerne bitten würde: Sieht das für euch korrekt aus?
    Ich lade mal das Projekt hoch. Mit dieser Form könnt ihr eine neue Ebene erstellen. Die Zahlen bitte erstmal so lassen, weil ich noch nicht alle erdenklichen Kombinationen implementiert habe. Die Ebene drehen könnt ihr mit W, A , S, D (aber ein Winkel von beiden muss immer 0° sein).



    Drehung einer Ebene.zip

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Bartosz“ ()

    Bartosz schrieb:

    Sieht das für euch korrekt aus?


    ich hab nicht jedes Detail gelesen, folge diesem Thread aber mit Interesse.
    Grad fällt mir ein, dass zur Darstellung der perspektivischen Verkürzung ein entscheidender Faktor noch garnet erwähnt wurde (oder ich übersehen): Die Position der Kamera.
    Weil je näher ein Beobachter an einem Objekt dran ist, desto stärker wirkt sie sich aus.
    Oder anders: Womöglich jedes Viereck sieht richtig aus als Projektion einer gedrehten Ebene. Ist nur eine Frage der CameraPosition.
    Ich habe noch ne gute Idee, wie man das Ganze besser berechnet (mit den Mitteln die ich habe). Ich muss nur im Programm aus der Parameterform der Ebene die Koordinatenform machen können und dann eine Gerade in die Ebenengleichung (daher KO-Form) einsetzen, um den Durchstoßpunkt zu berechnen. Ich habe mir NCalc heruntergeladen. Das Problem: Es ist irre langsam. Kennt hier jemand bitte eine Möglichkeit, dies zu verwursten und s zu finden? Im Programm? Das müsste schon auf die 3te Nachkommastelle genau sein... Ich habe versucht, das mit ne For-Schleife zu machen, aber das Programm hat mir die Nachkommastellen versaut. Es kam (nach Minuten) s = 0,9.. heraus


    total langsam

    VB.NET-Quellcode

    1. For i As Double = 0 To 1 Step 0.0001
    2. Zwischenspeicher = alles_verrechnet.Replace("s", i.ToString())
    3. Zwischenspeicher = Zwischenspeicher.Replace(","c, "."c)
    4. Dim This As New NCalc.Expression(Zwischenspeicher)
    5. Ergebnis = CDbl(This.Evaluate)
    6. Debug.WriteLine(CInt(Ergebnis * 1000.0))
    7. If CInt(Ergebnis * 1000.0) = 0 OrElse CInt(Ergebnis * 1000.0) = 1 OrElse CInt(Ergebnis * 1000.0) = -1 Then
    8. yFuerDSP = i
    9. End If
    10. Next



    Schönen Fußballabend :thumbsup:

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Bartosz“ ()

    Hallo @VB.neter0101, auf meinem Bild , erste Zeile, das ist bereits die Koordinatenform, die ich mit dem Kreuzprodukt berechnet habe. Meine Frage war, ob das das Programm machen könnte. Das habe ich auch hinbekommen. Dann aber muss die Gerade* eingesetzt werden und wie du siehst ergibt das einen langen Term mit Buchstaben drin . Meine Frage war gestern Abend, ob mein Programm verrechnen könnte, was geht, um letzten Endes auf z.B. -31,507*s+28,294=0 zu kommen. Dann muss ich nämlich nicht solven, um an s zu kommen, sondern kann einfach 28,294 durch 31,507 dividieren. Naja, das habe ich verworfen. Ich habe es anders gemacht. Dazu gleich mehr.

    *Von welcher Gerade redet er?

    Ich habe mir das nun so gedacht. Ich habe einmal die gedrehte Ebene (lila) und einmal die runterprojizierte (grün). Bitte beachte, dass sie im Onlinetool korrekt in x-Richtung etwas kleiner geworden ist, aber in y-Richtung zu groß dargestellt wird. Das ist einfach eine Sache des Tools. Und jetzt nutze ich die Kameraposition, wie von @ErfinderDesRades erwähnt. Sie ist zwar fix, aber von ihr geht ein Vektor zy1 auf die Ecke der gekippten Ebene. Es gibt auch einen Vektor von der Kamera auf die platte Ebene, er heißt zyplatt. Wie man sieht, durchstößt zyplatt auf seinem Weg die gekippte Ebene. Schau mal auf die Stelle. Von dort aus muss ich nur weiter hoch (y erhöhen). Aber wie viel? Das geht, wenn man den Durchstoßpunkt berechnet und die Differenz y des zyplatt und y des DSP nimmt und dieses Differenz-y für den Vektor Kante nutzt. 10+(10-8,98) = 11,02. Ja, dazu brauchte ich gestern Abend die Automatisierung: Koordinatenform bilden, Gerade einsetzen, Durchstoßpunkt berechnen.





    Ich hatte es gestern Nacht noch so gelöst, dass ich mir einfach alle Werte bei Excel generiert habe. So konnte ich einen Faktor bilden und weiß nun, um wie viel breiter die Ebene in y-Richtung bei Drehung aussehen muss.



    Das werde ich heute programmieren. Mal schauen, wie's wird.
    Kurzes Update: diesen Thread werde ich bis auf Weiteres pausieren.

    1.)
    Ich hatte Folgendes gemacht. Ich habe ein "Spinnennetz" von der Kamera aus zu den 4 Eckpunkten gebildet. Das sind meine Vektoren. Aber: Wir reden von der runterprojizierten Ebene (grün), die auch zusammenschrumpft. Der eine Vektor durchstößt auf seinem Weg die lilane Ebene, und von diesem Durchstoßpunkt, den ich berechnen kann, gehe ich etwas in y-Richtung hoch und schon bin ich auf der Kante und weiß, um wie viel breiter die lilane Ebene erscheint, also wie ich die grüne zeichnen muss... Tja, hat besser geklappt als am Anfang dieses Threads, weil ich auch von cos und sin weg bin... Jedoch kam es bei 2 großen Winkeln immer noch zu einer Verzerrung.

    Ich habe jetzt 3 Tage Pause gemacht und habe heute Nachmittag mit meinem Nachbarn gesprochen. (Das ist auch so ne Sache..wen soll ich fragen...dafür kann keiner was, aber ist halt so.) Er sagte, dieses Online-Tool arbeitet mit einer 3D-Darstellung und Code, der das verarbeiten kann. Das Tool weiß aus jedem Blickwinkel (x,y,z), wie die Szenerie auszusehen hat. Es ist eine 3D-Engine. Sie könnte auch die Natur wiedergeben. Es wurde ja eigentlich nur ein lilanes Rechteck gemalt und das Tool weiß - aus jedem Blickwinkel, wie das auszusehen hat. Eine mathematische Ebene wird ja auch in der Schule durch 3 Achsen definiert... Selbst, wenn ich die Ebene im Tool plattdrücke (z=0), und mich gefreut habe, dass es richtig aussieht (weil die platte kürzer wird), so ist das trotzdem falsch, denn ich gehe vom falschen System aus. So, wie ich das programmiert habe, sah die Projektion ja nur gut aus, wenn ich um eine Achse gedreht habe. Kam eine zweite Drehung um eine andere Achse dazu, hatte ich diese Verzerrung. Das ist genau der Punkt. Er hat ein Poster gesehen, bei dem Bahnschienen genau in die Bildtiefe gehen. Und er hat gesagt, "schau mal, du siehst hier an den Bahnschienen sehr schön die räumliche Tiefe (trotz dieses 2D-Posters), die Original-Szenerie kommt aber aus einer echten 3D-Welt. Würdest du jetzt das so kopierend programmieren, also fester Blickwinkel, und das Bild um beide Achsen kippen, wären die Schienen nicht mehr gerade, sondern so mit steigender Tiefe immer verzerrter / "verbogener" wie bei dir im Programm." Es ist also ein Unterschied im Kopf zu machen (auch wenn man denkt "Es wird ja immer sowieso alles auf einem 2D-Monitor projiziert"), ob man entweder eine 3D-(Spiele)-Welt baut, oder ob sie nicht vorhanden ist und man einen 3D-Sachverhalt aus der echten Welt nachahmen will. Der letztere Fall trifft bei mir zu. Eine Lösung kann sein, ein 2D-Array zu kreieren, welches für den Menschen so aussieht, als wäre es eine 3D-Welt... Das Array ist aber nie 3D gewesen. Wenn man Spiele entwickelt, sagt er, wird das auch so gemacht. Das macht dir die 3D-Engine.

    Na gut, durch Fehler lernt man... Hätte ich immer gleich aufgegeben, wär ich heut nicht da, wo ich bin.

    Wir können gerne noch etwas drüber diskutieren. Ich musste mir auch gerade Mühe geben, das in Worte zu fassen. Gar nicht so einfach online...

    Ich bedanke mich bei allen, die hier einen Beitrag geschrieben haben.
    :saint: , bleibt gesund, ich mach bestimmt bald wieder den nächsten Thread auf.

    Viele Grüße
    Bartosz


    Achja, und falls doch noch einer was weiß, immer her damit.
    Lösung
    Allgemein löst man eine Projektion so, als würde man im realen Leben durch ein Fenster nach draußen sehen und dort etwas beobachten. Im Auge laufen alle Linien zusammen. Dies habe ich einmal mit dem Online-Tool dargestellt. Am Koordinatenursprung sei das Auge; und die Linien, die von markanten Punkten – den Ecken – des Quaders kommen, werden auf dem Fenster (grüne Ebene) dargestellt.


    Wer das eingeben möchte:
    Link und Formeln für das Online-Tool

    matheretter.de/geoservant/de
    quader(8|0|1 2|2|3)[00 -35 0]
    ebene(2|0|0 2|0|2 2|2|0)
    vektor(0|0|0 7,31|0|3,15 "a")
    vektor(0|0|0 7,31|2|3,15 "b")
    vektor(0|0|0 9|0|0,7 "c")
    vektor(0|0|0 9|2|0,7 "d")
    vektor(0|0|0 9|2|4,25 "e")
    vektor(0|0|0 9|0|4,25 "f")
    vektor(2|0|0 0|0|0,8618 "p1")
    vektor(2|0|0 0|0,547|0,8618 "p2")
    vektor(2|0|0 0|0|0,1555 "p3")
    vektor(2|0|0 0|0,4444|0,9444 "p4")

    Die 2D-Vektoren werden wie folgt berechnet (Achtung, in diesem Beispiel läuft +x Richtung Quader, +y nach links und z nach oben):
    $$ z_{neu} = \frac{d}{x} \cdot z $$
    mit d = Abstand Auge zum Fenster; z = z-Komponente des Vektors vom Ursprung zum Quader
    $$ y_{neu} = \frac{d}{x} \cdot y $$
    mit d = Abstand Auge zum Fenster; y = y-Komponente des Vektors vom Ursprung zum Quader.


    Konkretes Beispiel: Wir nehmen den Vektor a = (0|0|0 7,31|0|3,15)
    $$ \frac{2}{7.31} \cdot 3.15 = 0.86 $$

    $$ \frac{2}{7.31} \cdot 0 = 0 $$

    Daher lautet der neue 2D-Vektor p1 = 0|0|0,8618
    Jetzt muss man noch bedenken, dass bei der Darstellung in VB.Net das y nach unten positiv läuft. Für das y im Programm wird dann -z genommen! (In diesem Beispiel, es kann ja sein, dass die Achsen bei eurem Projekt anders sind).



    Nun zum eigentlichen Thema „eine Ebene (im mathematischen Sinn) in 3D rotieren und auf 2D darstellen“
    Ich komme direkt zum Punkt. Ich schaue hier in Draufsicht (also -z Richtung) auf die Situation. Man sieht die gemischt-gedrehte Ebene (20° um y und 10° um x). Diese hat dementsprechend die Parameterform

    $$ E: \vec{x} = \left( \begin{array}{c} 0 \\\ 0 \\\ 0 \end{array}\right) + s \cdot \left( \begin{array}{c} 0.9396926 \\\ 0 \\\ -0,34202 \end{array}\right) + t \cdot \left( \begin{array}{c} 0 \\\ 0,9848 \\\ 0,173648 \end{array}\right) $$






    Hier sieht auch wieder das „Fenster“ (auch wieder eine grüne Ebene). Dieses Fenster ist auf der Höhe z = 20; die Kamera sitzt über dem Ursprung und befindet sich auf der Höhe = 30,1. Nun werden die 4 Vektoren p1 bis p4 mit der oben genannten Formel berechnet. Hinweis: Da ich in Draufsicht auf die Szene schaue, kommt mir die blaue Ebene beim Drehen ja entgegen, also ist die einzusetzende Höhe

    $$ \underbrace{30.1}_{Kamerahöhe} -(-|0.34202| \cdot 10+|0,1736| \cdot 10) $$

    Die 10 dienen nur der Vergrößerung. Je nachdem, an welcher Ecke man ist, muss man die Minuszeichen durchtauschen, denn
    $\vec{p1}$
    soll immer links oben sein,
    $\vec{p2}$
    immer oben rechts,
    $\vec{p3}$
    unten rechts,
    $\vec{p4}$
    unten links - egal, wie die Ebene sich dreht.

    Dies hab ich implementiert. Das Programm funktioniert, was die Mathematik angeht, korrekt. Ich muss nur noch die Fälle "beide Winkel negativ", "Winkel Phi positiv und Theta negativ" und "Winkel Phi negativ und Theta positiv" einbauen. Edit: Erledigt. Nun ist es so, dass diese darzustellende Ebene nunmal per Definition platt ist. Sie selbst hat keine Tiefe. Das macht den Anblick etwas ungewohnt schwierig, weil man beim Drehen keine Seite sieht.




    Edit: 1) mit-projiziertes Gitternetz und 2) Normalenvektor hinzugefügt. 3) Asynchrone Berechnung. 4) Code vereinfacht.





    Anbei der Code:


    Class_Ebene_Mathematik2

    Quellcode

    1. #Disable Warning IDE1006 ' Benennungsstile
    2. #Disable Warning CA1707 ' Bezeichner dürfen keine Unterstriche enthalten
    3. Imports System.Windows.Media.Media3D
    4. Imports Microsoft.WindowsAPICodePack.Dialogs
    5. Imports Microsoft.VisualBasic.ControlChars
    6. Public NotInheritable Class Class_Ebene_Mathematik2
    7. Private ReadOnly Deu As New System.Globalization.CultureInfo("de-DE")
    8. ''' <summary>
    9. ''' In Längeneinheiten. Es wird ein Vergrößerungsfaktor benutzt, da die Vektoren anfangs nur Einsen haben.
    10. ''' </summary>
    11. Private enlargement_factor As Double ' wird in Form_neue_Ebene_erstellen zugewiesen.
    12. ' Alle verwendeten Benennungen und Rechnungen basieren auf folgender Vorzeichenkonvention, wie man sie auch in der Dokumentation sieht.
    13. ' +x nach rechts
    14. ' +y nach oben
    15. ' +z aus der Zeichenebene heraus (man schaut auf die Pfeilspitze der z-Achse; Draufsicht).
    16. ' Die Ebene, die immer als Beispiel genommen wurde, lag in der xy-Ebene. (0|0|0) + s·(1|0|0) + t·(0|1|0)
    17. ' Die um die y-Achse um 20° gedrehte Ebene ist laut Drehmatrix: (0|0|0) + s·(0,94|0|-0,342) + t·(0|1|0)
    18. ' Die um die x-Achse um 20° gedrehte Ebene ist laut Drehmatrix: (0|0|0) + s·(1|0|0) + t·(0|0,94|0,342)
    19. ' Beim Zeichnen ist der Koordinatenursprung in der Mitte der PictureBox.
    20. ' Da in VB.Net die y-Achse positiv nach unten gezählt wird, wird in den Rechnungen das Vorzeichen gewechselt.
    21. Private A0 As Vector3D
    22. ' →
    23. Private AB As Vector3D
    24. ' →
    25. Private AC As Vector3D
    26. ''' <summary>
    27. ''' Winkel für Drehung um die x-Achse in Grad.
    28. ''' </summary>
    29. Public Phi As Double '= 0.0
    30. ''' <summary>
    31. ''' Winkel für Drehung um die y-Achse in Grad.
    32. ''' </summary>
    33. Public Theta As Double '= 0.0
    34. ''' <summary>
    35. ''' Die Kamera hängt genau über dem Ursprung, auf einer bestimmten Höhe.
    36. ''' </summary>
    37. Private Kameraposition_z As Double = 40.0
    38. ' Die Vektoren p1, p2, p3 und p4 laufen von der Mitte des Fensters zu den 4 Ecken der Projektion.
    39. ' → → → →
    40. Private p1, p2, p3, p4 As PointF
    41. Public Koordinatenform As String = ""
    42. Private Fensterhoehe As Double = 20.0
    43. ''' <summary>
    44. ''' Hilfslinien / Gitternetz
    45. ''' </summary>
    46. Private Grid_vertical As List(Of PointF)
    47. Private Grid_horizontal As List(Of PointF)
    48. Private Normal_projected As PointF
    49. Private ReadOnly point_of_origin As New PointF(0.0F, 0.0F)
    50. Public Sub um_x_und_y_Achsen_drehen(ByVal dphi As Double, ByVal dtheta As Double)
    51. Phi += dphi
    52. If Phi = 90.0 OrElse Phi = (-90.0) Then
    53. Phi = 0.0
    54. End If
    55. Theta += dtheta
    56. If Theta = 90.0 OrElse Theta = (-90.0) Then
    57. Theta = 0.0
    58. End If
    59. 'Theta = (20.0) : Phi = (-10.0) : Kameraposition_z = 30.1 : enlargement_factor = 1.0
    60. ' Für die Drehung um die y-Achse:
    61. ' nimmt man die "Drehmatrix für y" * RV1
    62. ' cos(α) 0 sin(α) 1 cos(α)
    63. ' 0 1 0 * 0 = 0
    64. '-sin(α) 0 cos(α) 0 -sin(α)
    65. AB = New Vector3D(Math.Cos(Theta * Math.PI / 180.0), 0.0, -Math.Sin(Theta * Math.PI / 180.0))
    66. ' Für die Drehung um die x-Achse:
    67. ' nimmt man die "Drehmatrix für x" * RV2
    68. ' 1 0 0 0 0
    69. ' 0 cos(α) -sin(α) * 1 = cos(α)
    70. ' 0 sin(α) cos(α) 0 sin(α)
    71. AC = New Vector3D(0.0, Math.Cos(Phi * Math.PI / 180.0), Math.Sin(Phi * Math.PI / 180.0))
    72. erstell_Koordinatenform()
    73. ' ============================================================================================================
    74. ' DOKUMENTATION der Darstellungs-Fälle nach Reihenfolge.
    75. ' 1.) Darstellung, die nur eine positive oder negative Drehung um die y-Achse behandelt.
    76. ' 2.) Darstellung, die nur eine positive oder negative Drehung um die x-Achse behandelt.
    77. ' p1, p2, p3 und p4 bleiben allerdings an denselben Ecken wie vorher; das heißt, die Formeln sind vertauscht.
    78. ' Was bei "links unten" war, ist nun bei "links oben".
    79. ' 3.) gemischte Drehungen
    80. ' ============================================================================================================
    81. If Phi = 0.0 AndAlso (Theta >= -90.0 OrElse Theta <= 90.0) Then ' um y-Achse gedreht.
    82. nur_um_yAchse_drehen()
    83. ElseIf Theta = 0.0 AndAlso (Phi >= -90.0 OrElse Phi <= 90.0) Then ' um x-Achse gedreht.
    84. nur_um_xAchse_drehen()
    85. ElseIf Phi > 0.0 AndAlso Theta > 0.0 Then ' mixed rotation, both angles positive
    86. 'Debug.WriteLine(Math.Round(AB.X, 3).ToString() & " " & Math.Round(AC.Y, 3).ToString() & " " & Math.Round(AB.Z, 3).ToString() & " " & Math.Round(AC.Z, 3).ToString())
    87. p1 = New PointF(
    88. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    89. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    90. p2 = New PointF(
    91. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    92. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    93. 'Debug.WriteLine("p2X = " & Math.Round(p2.X, 3).ToString() & "p2Y = " & Math.Round(p2.Y, 3).ToString())
    94. p3 = New PointF(
    95. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    96. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    97. p4 = New PointF(
    98. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    99. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    100. ElseIf Phi > 0.0 AndAlso Theta < 0.0 Then
    101. p1 = New PointF(
    102. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    103. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    104. p2 = New PointF(
    105. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    106. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    107. p3 = New PointF(
    108. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    109. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    110. p4 = New PointF(
    111. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    112. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    113. ElseIf Phi < 0.0 AndAlso Theta < 0.0 Then
    114. p1 = New PointF(
    115. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    116. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    117. p2 = New PointF(
    118. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    119. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    120. p3 = New PointF(
    121. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    122. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    123. p4 = New PointF(
    124. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    125. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    126. ElseIf Phi < 0.0 AndAlso Theta > 0.0 Then
    127. p1 = New PointF(
    128. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    129. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    130. p2 = New PointF(
    131. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    132. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 - Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    133. p3 = New PointF(
    134. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    135. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (-Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    136. p4 = New PointF(
    137. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AB.X * 10.0 * enlargement_factor),
    138. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * 10.0 + Math.Abs(AC.Z) * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    139. End If
    140. create_Grid()
    141. create_Normal()
    142. End Sub
    143. Private Sub create_Grid()
    144. Grid_vertical = New List(Of PointF)
    145. Dim aktueller_Punkt As PointF
    146. For x As Integer = 10 To -10 Step -1
    147. For y As Integer = 10 To -10 Step -1
    148. If Phi > 0.0 AndAlso Theta > 0.0 Then
    149. aktueller_Punkt = New PointF(
    150. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AB.X * x * enlargement_factor),
    151. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AC.Y * y * enlargement_factor)
    152. )
    153. ElseIf Phi > 0.0 AndAlso Theta < 0.0 Then
    154. aktueller_Punkt = New PointF(
    155. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AB.X * x * enlargement_factor),
    156. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AC.Y * y * enlargement_factor)
    157. )
    158. ElseIf Phi < 0.0 AndAlso Theta > 0.0 Then
    159. aktueller_Punkt = New PointF(
    160. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AB.X * x * enlargement_factor),
    161. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AC.Y * y * enlargement_factor)
    162. )
    163. ElseIf Phi < 0.0 AndAlso Theta < 0.0 Then
    164. aktueller_Punkt = New PointF(
    165. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AB.X * x * enlargement_factor),
    166. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AC.Y * y * enlargement_factor)
    167. )
    168. End If
    169. Grid_vertical.Add(aktueller_Punkt)
    170. Next
    171. Next
    172. '===========================================================================
    173. Grid_horizontal = New List(Of PointF)
    174. Dim aktueller_Punkt2 As PointF
    175. For y As Integer = 10 To -10 Step -1
    176. For x As Integer = 10 To -10 Step -1
    177. If Phi > 0.0 AndAlso Theta > 0.0 Then
    178. aktueller_Punkt2 = New PointF(
    179. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AB.X * x * enlargement_factor),
    180. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AC.Y * y * enlargement_factor)
    181. )
    182. ElseIf Phi > 0.0 AndAlso Theta < 0.0 Then
    183. aktueller_Punkt2 = New PointF(
    184. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AB.X * x * enlargement_factor),
    185. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AC.Y * y * enlargement_factor)
    186. )
    187. ElseIf Phi < 0.0 AndAlso Theta > 0.0 Then
    188. aktueller_Punkt2 = New PointF(
    189. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AB.X * x * enlargement_factor),
    190. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AC.Y * y * enlargement_factor)
    191. )
    192. ElseIf Phi < 0.0 AndAlso Theta < 0.0 Then
    193. aktueller_Punkt2 = New PointF(
    194. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AB.X * x * enlargement_factor),
    195. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - (Math.Abs(AB.Z) * CDbl(x) + Math.Abs(AC.Z) * CDbl(y))) * AC.Y * y * enlargement_factor)
    196. )
    197. End If
    198. Grid_horizontal.Add(aktueller_Punkt2)
    199. Next
    200. Next
    201. End Sub
    202. Private Sub create_Normal()
    203. Dim Normal As Vector3D = Vector3D.CrossProduct(AB, AC) * 10.0 * enlargement_factor
    204. Dim Normal_without_z As New Vector3D(Normal.X, Normal.Y, 0.0)
    205. Dim Angle As Double = Vector3D.AngleBetween(Normal, Normal_without_z)
    206. Dim vertical_height As Double = Normal_without_z.Length * Math.Tan(Angle * Math.PI / 180.0)
    207. 'Debug.WriteLine(Math.Round((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - vertical_height) * Normal.X, 0).ToString())
    208. Normal_projected = New PointF(
    209. CSng((Kameraposition_z - Fensterhoehe) / Math.Abs(Kameraposition_z - vertical_height) * Normal.X),
    210. CSng((Kameraposition_z - Fensterhoehe) / Math.Abs(Kameraposition_z - vertical_height) * Normal.Y)
    211. )
    212. 'Debug.WriteLine(Math.Round(Normal_projected.X, 1).ToString() & " " & Math.Round(Normal_projected.Y, 1).ToString())
    213. End Sub
    214. Private Sub unitV_2D()
    215. Normal_projected = New PointF(CSng(Normal_projected.X / Math.Sqrt(Math.Pow(Normal_projected.X, 2.0) + Math.Pow(Normal_projected.Y, 2.0))),
    216. CSng(Normal_projected.Y / Math.Sqrt(Math.Pow(Normal_projected.X, 2.0) + Math.Pow(Normal_projected.Y, 2.0))))
    217. End Sub
    218. Public Sub Paint(ByVal g As Graphics)
    219. If g Is Nothing Then Return
    220. g.TranslateTransform(CSng(FormMain.PictureBox1.Size.Width / 2.0), CSng(FormMain.PictureBox1.Size.Height / 2.0))
    221. g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
    222. g.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
    223. g.PixelOffsetMode = Drawing2D.PixelOffsetMode.HighQuality
    224. g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBilinear
    225. Using GPath As New Drawing2D.GraphicsPath
    226. GPath.AddLine(p1, p2)
    227. GPath.AddLine(p2, p3)
    228. GPath.AddLine(p3, p4)
    229. GPath.AddLine(p4, p1)
    230. Using BrushLightBlue As New SolidBrush(Color.FromArgb(112, 200, 255))
    231. g.FillPath(BrushLightBlue, GPath)
    232. End Using
    233. End Using
    234. If Grid_vertical IsNot Nothing Then
    235. Using Pen_Gelb As New Pen(Color.FromArgb(217, 217, 0), 1.0F)
    236. For i As Integer = 0 To Grid_vertical.Count - 2 Step 1
    237. ' Diese If-Bedingung dient dazu, dass nicht Punkte von unten nach oben schräg durchverbunden werden. Es ist zwar ein Quick&Dirty-Workaround, aber es geht.
    238. ' Die einzelnen Punkte sind bereits richtig projiziert und sind in der List(of PointF) gespeichert. Es würde also wenig Sinn machen, ein gerades Gitternetz zu zeichnen und dieses dann zu verdrehen (engl.: skew).
    239. ' Ich mache es mir zu Nutze, dass y regelmäßig von einem negativsten Wert auf einen positivsten Wert springt (oder andersherum).
    240. If Not ((Grid_vertical(i).Y > 0.0F AndAlso Grid_vertical(i + 1).Y < 0.0F AndAlso Math.Abs(Grid_vertical(i).Y - Grid_vertical(i + 1).Y) > 10.0F) Xor
    241. (Grid_vertical(i).Y < 0.0F AndAlso Grid_vertical(i + 1).Y > 0.0F AndAlso Math.Abs(Grid_vertical(i).Y - Grid_vertical(i + 1).Y) > 10.0F)) Then
    242. g.DrawLine(Pen_Gelb, Grid_vertical(i), Grid_vertical(i + 1))
    243. End If
    244. Next
    245. End Using
    246. End If
    247. If Grid_horizontal IsNot Nothing Then
    248. Using Pen_Gelb As New Pen(Color.FromArgb(217, 217, 0), 1.0F)
    249. For i As Integer = 0 To Grid_horizontal.Count - 2 Step 1
    250. ' Diese If-Bedingung dient dazu, dass nicht Punkte von unten nach oben schräg durchverbunden werden. Es ist zwar ein Quick&Dirty-Workaround, aber es geht.
    251. ' Die einzelnen Punkte sind bereits richtig projiziert und sind in der List(of PointF) gespeichert. Es würde also wenig Sinn machen, ein gerades Gitternetz zu zeichnen und dieses dann zu verdrehen (engl.: skew).
    252. ' Ich mache es mir zu Nutze, dass y regelmäßig von einem negativsten Wert auf einen positivsten Wert springt (oder andersherum).
    253. If Not ((Grid_horizontal(i).X > 0.0F AndAlso Grid_horizontal(i + 1).X < 0.0F AndAlso Math.Abs(Grid_horizontal(i).X - Grid_horizontal(i + 1).X) > 10.0F) Xor
    254. (Grid_horizontal(i).X < 0.0F AndAlso Grid_horizontal(i + 1).X > 0.0F AndAlso Math.Abs(Grid_horizontal(i).X - Grid_horizontal(i + 1).X) > 10.0F)) Then
    255. g.DrawLine(Pen_Gelb, Grid_horizontal(i), Grid_horizontal(i + 1))
    256. End If
    257. Next
    258. End Using
    259. End If
    260. If Not Single.IsInfinity(Normal_projected.X) AndAlso
    261. Not Single.IsInfinity(Normal_projected.Y) AndAlso
    262. Normal_projected.X < 800.0F AndAlso
    263. Normal_projected.Y < 800.0F Then
    264. Using PenPink As New Pen(Color.FromArgb(255, 0, 144), 5.0F)
    265. Normal_projected.Y *= -1.0F
    266. g.DrawLine(PenPink, point_of_origin, Normal_projected)
    267. End Using
    268. End If
    269. End Sub
    270. Public Sub verschieben(ByVal MouseLocation As System.Drawing.Point)
    271. 'Hiermit wird die Ebene im Ganzen verschoben. Eigentlich wird nur MouseLocation.X - AB.X * enlargement_factor
    272. ' benutzt, aber weil in der Paint-Prozedur der Koordinatensystemursprung auf die Mitte der Picturebox gelegt
    273. ' wird, wird noch "- FormMain.PictureBox1.Size.Width / 2.0" benutzt.
    274. p4 = New PointF(CSng(MouseLocation.X - AB.X * enlargement_factor - FormMain.PictureBox1.Size.Width / 2.0),
    275. CSng(MouseLocation.Y + AC.Y * enlargement_factor - FormMain.PictureBox1.Size.Height / 2.0))
    276. p1 = New PointF(CSng(MouseLocation.X - AB.X * enlargement_factor - FormMain.PictureBox1.Size.Width / 2.0),
    277. CSng(MouseLocation.Y - AC.Y * enlargement_factor - FormMain.PictureBox1.Size.Height / 2.0))
    278. p2 = New PointF(CSng(MouseLocation.X + AB.X * enlargement_factor - FormMain.PictureBox1.Size.Width / 2.0),
    279. CSng(MouseLocation.Y - AC.Y * enlargement_factor - FormMain.PictureBox1.Size.Height / 2.0))
    280. p3 = New PointF(CSng(MouseLocation.X + AB.X * enlargement_factor - FormMain.PictureBox1.Size.Width / 2.0),
    281. CSng(MouseLocation.Y + AC.Y * enlargement_factor - FormMain.PictureBox1.Size.Height / 2.0))
    282. End Sub
    283. Public Sub change_Kamerahoehe(ByVal Hoehe As Double)
    284. Me.Kameraposition_z = Hoehe
    285. End Sub
    286. Public Sub change_Fensterhoehe(ByVal hoehe As Double)
    287. Me.Fensterhoehe = hoehe
    288. End Sub
    289. Private Sub nur_um_yAchse_drehen()
    290. 'Debug.WriteLine(Math.Round(AB.X, 3).ToString() & " " & Math.Round(AC.Y, 3).ToString() & " " & Math.Round(AB.Z, 3).ToString() & " " & Math.Round(AC.Z, 3).ToString())
    291. p1 = New PointF(
    292. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z + AB.Z * 10.0) * AB.X * 10.0 * enlargement_factor),
    293. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z + AB.Z * 10.0) * AC.Y * 10.0 * enlargement_factor))
    294. p2 = New PointF(
    295. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - AB.Z * 10.0) * AB.X * 10.0 * enlargement_factor),
    296. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z + (-AB.Z) * 10.0) * AC.Y * 10.0 * enlargement_factor))
    297. 'Debug.WriteLine("p2X = " & Math.Round(p2.X, 3).ToString() & "p2Y = " & Math.Round(p2.Y, 3).ToString())
    298. p3 = New PointF(
    299. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z - AB.Z * 10.0) * AB.X * 10.0 * enlargement_factor),
    300. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z + (-AB.Z) * 10.0) * AC.Y * 10.0 * enlargement_factor))
    301. p4 = New PointF(
    302. CSng(-(Kameraposition_z - Fensterhoehe) / (Kameraposition_z + AB.Z * 10.0) * AB.X * 10.0 * enlargement_factor),
    303. CSng((Kameraposition_z - Fensterhoehe) / (Kameraposition_z + AB.Z * 10.0) * AC.Y * 10.0 * enlargement_factor))
    304. End Sub
    305. Private Sub nur_um_xAchse_drehen()
    306. 'Debug.WriteLine(Math.Round(AB.X, 3).ToString() & " " & Math.Round(AC.Y, 3).ToString() & " " & Math.Round(AB.Z, 3).ToString() & " " & Math.Round(AC.Z, 3).ToString())
    307. p1 = New PointF(
    308. CSng(-(Kameraposition_z - Fensterhoehe) / (-(Kameraposition_z + AC.Z * 10.0)) * AB.X * 10.0 * enlargement_factor),
    309. CSng(-(Kameraposition_z - Fensterhoehe) / (-(Kameraposition_z + AC.Z * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    310. p2 = New PointF(
    311. CSng((Kameraposition_z - Fensterhoehe) / (-(Kameraposition_z + AC.Z * 10.0)) * AB.X * 10.0 * enlargement_factor),
    312. CSng(-(Kameraposition_z - Fensterhoehe) / (-(Kameraposition_z + AC.Z * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    313. 'Debug.WriteLine("p2X = " & Math.Round(p2.X, 3).ToString() & "p2Y = " & Math.Round(p2.Y, 3).ToString())
    314. p3 = New PointF(
    315. CSng((Kameraposition_z - Fensterhoehe) / (-(Kameraposition_z - AC.Z * 10.0)) * AB.X * 10.0 * enlargement_factor),
    316. CSng((Kameraposition_z - Fensterhoehe) / (-(Kameraposition_z - AC.Z * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    317. p4 = New PointF(
    318. CSng(-(Kameraposition_z - Fensterhoehe) / (-(Kameraposition_z - AC.Z * 10.0)) * AB.X * 10.0 * enlargement_factor),
    319. CSng((Kameraposition_z - Fensterhoehe) / (-(Kameraposition_z - AC.Z * 10.0)) * AC.Y * 10.0 * enlargement_factor))
    320. End Sub
    321. Private Sub erstell_Koordinatenform()
    322. Dim _N As Vector3D = Vector3D.CrossProduct(AB, AC)
    323. Dim _xMinusA0 As String
    324. Dim _yMinusA0 As String
    325. Dim _zMinusA0 As String
    326. If A0.X = 0.0 Then
    327. _xMinusA0 = "x"
    328. Else
    329. _xMinusA0 = "(x - " & A0.X.ToString(Deu) & ")"
    330. End If
    331. If A0.Y = 0.0 Then
    332. _yMinusA0 = "y"
    333. Else
    334. _yMinusA0 = "(y - " & A0.Y.ToString(Deu) & ")"
    335. End If
    336. If A0.Z = 0.0 Then
    337. _zMinusA0 = "z"
    338. Else
    339. _zMinusA0 = "(z - " & A0.Z.ToString(Deu) & ")"
    340. End If
    341. Koordinatenform = Math.Round(_N.X, 3).ToString(Deu) & " * " & _xMinusA0 & " + " & Math.Round(_N.Y, 3).ToString(Deu) & " * " & _yMinusA0 & " + " & Math.Round(_N.Z, 3).ToString(Deu) & " * " & _zMinusA0
    342. End Sub
    343. Public Sub neue_Ebene_erstellen()
    344. Using FNEE As New Form_neue_Ebene_erstellen
    345. If FNEE.ShowDialog() = DialogResult.OK Then
    346. A0 = New Vector3D(CDbl(FNEE.TextBox_A0_x.Text), CDbl(FNEE.TextBox_A0_y.Text), CDbl(FNEE.TextBox_A0_z.Text))
    347. AB = New Vector3D(CDbl(FNEE.TextBox_RV1_x.Text), CDbl(FNEE.TextBox_RV1_y.Text), CDbl(FNEE.TextBox_RV1_z.Text))
    348. AC = New Vector3D(CDbl(FNEE.TextBox_RV2_x.Text), CDbl(FNEE.TextBox_RV2_y.Text), CDbl(FNEE.TextBox_RV2_z.Text))
    349. enlargement_factor = CDbl(FNEE.TextBox_G.Text)
    350. End If
    351. End Using
    352. End Sub
    353. End Class
    354. #Enable Warning CA1707 ' Bezeichner dürfen keine Unterstriche enthalten



    und der Aufruf in Form1.vb

    Spoiler anzeigen

    VB.NET-Quellcode

    1. #Disable Warning CA1707 ' Bezeichner dürfen keine Unterstriche enthalten
    2. Public NotInheritable Class FormMain
    3. Private ReadOnly Deu As New System.Globalization.CultureInfo("de-DE")
    4. Private program_has_finished_loading As Boolean '= False
    5. Private Ebene As Class_Ebene_Mathematik2
    6. Private Sub FormMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    7. Me.Location = New System.Drawing.Point(0, 0)
    8. Label_Phi.Text = My.Resources.Phi_leer
    9. Label_Theta.Text = My.Resources.Theta_leer
    10. TextBox_Kamerahoehe.Text = My.Resources.vierzig
    11. TextBox_Fensterhoehe.Text = My.Resources.zwanzig
    12. End Sub
    13. Private Sub FormMain_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
    14. Ebene = New Class_Ebene_Mathematik2
    15. Ebene.neue_Ebene_erstellen()
    16. program_has_finished_loading = True
    17. End Sub
    18. Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
    19. If e.Button = MouseButtons.Left Then
    20. Ebene.verschieben(e.Location)
    21. PictureBox1.Invalidate()
    22. End If
    23. End Sub
    24. Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
    25. If e.Button = MouseButtons.Left Then
    26. Ebene.verschieben(e.Location)
    27. PictureBox1.Invalidate()
    28. End If
    29. End Sub
    30. Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
    31. If e.Button = MouseButtons.Left Then
    32. Ebene.verschieben(e.Location)
    33. PictureBox1.Invalidate()
    34. End If
    35. End Sub
    36. Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
    37. If Not program_has_finished_loading OrElse Ebene Is Nothing Then Return
    38. Ebene.Paint(e.Graphics)
    39. End Sub
    40. Private Async Sub FormMain_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
    41. Select Case e.KeyCode
    42. Case Keys.W
    43. Await Task.Run(Sub() Ebene.um_x_und_y_Achsen_drehen(-1.0, 0.0))
    44. TextBox_KF.Text = Ebene.Koordinatenform & " = 0"
    45. Label_Phi.Text = "ϕ = " & Math.Round(Ebene.Phi, 0).ToString(Deu).PadLeft(2, "0"c) & " °"
    46. Label_Theta.Text = "θ = " & Math.Round(Ebene.Theta, 0).ToString(Deu).PadLeft(2, "0"c) & " °"
    47. PictureBox1.Invalidate()
    48. Case Keys.S
    49. Await Task.Run(Sub() Ebene.um_x_und_y_Achsen_drehen(1.0, 0.0))
    50. TextBox_KF.Text = Ebene.Koordinatenform & " = 0"
    51. Label_Phi.Text = "ϕ = " & Math.Round(Ebene.Phi, 0).ToString(Deu).PadLeft(2, "0"c) & " °"
    52. Label_Theta.Text = "θ = " & Math.Round(Ebene.Theta, 0).ToString(Deu).PadLeft(2, "0"c) & " °"
    53. PictureBox1.Invalidate()
    54. Case Keys.A
    55. Await Task.Run(Sub() Ebene.um_x_und_y_Achsen_drehen(0.0, -1.0))
    56. TextBox_KF.Text = Ebene.Koordinatenform & " = 0"
    57. Label_Phi.Text = "ϕ = " & Math.Round(Ebene.Phi, 0).ToString(Deu).PadLeft(2, "0"c) & " °"
    58. Label_Theta.Text = "θ = " & Math.Round(Ebene.Theta, 0).ToString(Deu).PadLeft(2, "0"c) & " °"
    59. PictureBox1.Invalidate()
    60. Case Keys.D
    61. Await Task.Run(Sub() Ebene.um_x_und_y_Achsen_drehen(0.0, 1.0))
    62. TextBox_KF.Text = Ebene.Koordinatenform & " = 0"
    63. Label_Phi.Text = "ϕ = " & Math.Round(Ebene.Phi, 0).ToString(Deu).PadLeft(2, "0"c) & " °"
    64. Label_Theta.Text = "θ = " & Math.Round(Ebene.Theta, 0).ToString(Deu).PadLeft(2, "0"c) & " °"
    65. PictureBox1.Invalidate()
    66. Case Else
    67. Exit Select
    68. End Select
    69. End Sub
    70. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    71. Ebene.neue_Ebene_erstellen()
    72. End Sub
    73. Private Sub TextBox_Kamerahoehe_TextChanged(sender As Object, e As EventArgs) Handles TextBox_Kamerahoehe.TextChanged
    74. If Ebene IsNot Nothing Then
    75. Ebene.change_Kamerahoehe(CDbl(TextBox_Kamerahoehe.Text))
    76. End If
    77. End Sub
    78. Private Sub TextBox_Fensterhoehe_TextChanged(sender As Object, e As EventArgs) Handles TextBox_Fensterhoehe.TextChanged
    79. If Ebene IsNot Nothing Then
    80. If CDbl(TextBox_Fensterhoehe.Text) >= CDbl(TextBox_Kamerahoehe.Text) Then
    81. TextBox_Fensterhoehe.ForeColor = Color.Red
    82. Else
    83. TextBox_Fensterhoehe.ForeColor = Color.FromArgb(0, 138, 0) ' Mittelgrün
    84. Ebene.change_Fensterhoehe(CDbl(TextBox_Fensterhoehe.Text))
    85. End If
    86. End If
    87. End Sub
    88. End Class
    89. #Enable Warning CA1707 ' Bezeichner dürfen keine Unterstriche enthalten




    *sigh* ist also doch so eine Strahlensatzgeschichte... Im Grunde genommen hatte ich das fast mal so, aber ich habe nicht ein Fenster gehabt...
    $ z_{neu} = \frac{d}{x} \cdot z $

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „Bartosz“ ()