Linien in Tabellen darstellen

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

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von tron25.

    Linien in Tabellen darstellen

    Hallo,
    ich habe ein vermeintlich kleines Problem, welches mir Kopfschmerzen verursacht. Ich habe eine 2-dimmensionale Tabelle, beispielsweise 100x100. Dann habe ich Linienkoordinaten, beispielsweise Linie von 10,10 bis 60,50. Nun möchte ich herausfinden, welche Tabellenzellen von dieser Linie berührt werden.

    Hintergrund ist folgender:
    Ich habe eine .gcode-Datei, welche ich gerastert tastbar in Braille darstellen möchte. Bei .gcode-Dateien werden Linien durch die Anfangs- und Endkoordinaten dargestellt.

    Es gäbe natürlich die Möglichkeit, jede Ebene des 3D.-Objektes aus der .gcode-Datei zeichnen zu lassen und dann diese Grafik Zelle für Zelle auf beispielsweise "Schwarz" überprüfen zu lassen. Da aber grafische Darstellung viele Resoursen beanspruchen, suche ich nach einer Möglichkeit, die Tabelle ohne Grafik zu füllen.

    Hat jemand von euch eine Idee?
    Sind diese 100x100 die Anzahl der Zellen oder der Pixel? Ist die Zeilen und Spalten denn alle gleich breit bzw. gleich hoch? Oder werden die Zeilen-/Spaltendaten ebenfalls durch weitere gcode-Inhalte definiert?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Jo.
    Und ich würd bei sowas lieber von "Matrix" reden als von Tabelle.
    Eine Tabelle ist etwas mit einer festen Anzahl benannter Spalten und veränderlich viele Datensätze darin.

    Wiedemauchsei.
    Es gibt kein Matrix-Control out of the box. Ich hab mir daher gelegentlich eines gebastelt.
    Ich schliesse mich im wesentlichen den Fragen meines Vorposters an.
    Ich ziele darauf ab, ob es prinzipiell möglich ist, das Sammelsurium an .gcode - Linien in eine Matrix zu übersetzen - das wäre quasi ein "Paradigmen-Wechsel", und könnte eine starke Vereinfachung der weiteren Datenverarbeitung sein.
    Aber halt nur wenn dieser Paradigmen-Wechsel Sinn ergibt.
    Die Zellen der Tabelle sind gleich groß. Die Schichtdicke eines 3D-Druckes sind meistens kleiner, als die Linienbreite. Daher sind die Zellen quadratisch und so groß, wie die Schichtdicke.

    Je nach der Rechenleistung würde ich eventuell eine 3-dimmensionale Tabelle nutzen, um das ganze Objekt auf einmal darstellen zu können.

    Darf ich mal dumm fragen? Was ist der Unterschied zwischen einer Matrix und einer 2-dimmensionalen Tabelle?
    Häwaswiewower? 3D-Drucker? Geht es um ein 3D-Objekt oder eine Datentabelle? Sag mal bitte, was am Ende dabei rauskommen soll, damit wir Dir gedanklich folgen können. Ich dachte zuerst an: »Ich mal mir eine Tabelle (also ein 2-dimensionales Konstrukt bestehend aus 2D-Zellen), um dann später darin Daten einzutragen.« Dein Post klingt aber eher nach: »Ich druck mir ein Gitter aus nem 3D-Drucker.«
    Ne Tabelle ist für mich ein unphysikalisches x-dimensionales Konstrukt, um darin Daten zu platzieren. Eine Matrix kann für mich ein Tabelle sein. Aber genausogut auch ein x-dimensionales physikalisches Gitter, z.B. ein Trenngitter für Weinflaschen.
    Was hat es mit der Linie auf sich, die die Zellen durchkreuzt?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    tron25 schrieb:

    Was ist der Unterschied zwischen einer Matrix und einer 2-dimmensionalen Tabelle?
    Hab ich doch gesagt:

    ErfinderDesRades schrieb:

    Eine Tabelle ist etwas mit einer festen Anzahl benannter Spalten und veränderlich viele Datensätze darin.

    Eine Matrix ist zwar auch mit Zeilen und Spalten, aber Spaltenüberschriften (Namen) sind nicht vorgesehen, und Zeilen zufügen/löschen geht nicht.

    Ausserdem haben die Spalten einer Tabelle je einen eigenen Datentyp, also die erste Spalte kann Integer sein, die zweite String, Datum, Boolean - was du wolle.
    In einer Matrix haben alle Zellen denselben Datentyp.
    Also alles Double, alles String etc.

    tron25 schrieb:

    würde ich eventuell eine 3-dimmensionale Tabelle nutzen
    Ja, und das geht mit Tabellen garnet.
    Eine Matrix kann man auch 3D denken, eine Tabelle üblicherweise nicht.

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

    Also, es geht um Folgendes:

    Ich schreibe an einer Software, welche Grafiken umwandelt und über ein Brailledisplay dem blinden Benutzer zugänglich macht. Die Grafiken können natürlich auch über einen Brailledrucker ausgedruckt werden, sodass Blinde die Möglichkeit haben, Grafiken zu ertasten. Dies ist beispielsweise in einer Klausur mit Grafiken für Studenten nützlich. Ein Brailledisplay hat eine Lochplatte, aus der sich Pins erheben und somit eine Form tastbar machen. Unter dem folgenden Link gibt es ein Video dazu.



    Mein neues Projekt ist, das Blinde die Möglichkeit bekommen sollen, 3D-Objekte vor dem Druck abtasten zu können. Da sich meine Sehkraft immer weiter verschlechtert, werde ich wahrscheinlich irgend wann auch auf dieses Modul angewiesen sein.

    Der benutzer soll die Möglichkeit haben, das Objekt von jeder Seite aus zu betrachten, zu zoomen und Ebene für Ebene hinein- bzw. herauszugehen.

    Da in einer .gcode-Datei nicht jeder einzelne Punkt, sondern die Anfangs- und Endkoordinaten einer Linie gespeichert sind, benötige ich eine Möglichkeit, die Punkte dazwischen zu lokalisieren.
    Also da würde ich das Braille-Display oder den Braille-Drucker als Matrix verstehen, und es würde Sinn ergeben, Linien aus gcode-Files quasi in die "Braille-Matrix" einzutragen.
    Joa, da gibts Algorithmen für, oder es sind Tricks mit der Bitmap-Klasse denkbar.
    Aber erstmal beschliessen aus was deine Matrix bestehen soll:
    ein 2D-Array of Boolean?
    ein jagged 2D-Array of Boolean?
    einfach eine SchwarzWeiss-Bitmap?
    noch was anderes?

    Dann muss was erfunden werden, um so eine Matrix am Bildschirm anzuzeigen
    DatagridView?
    ownerdrawn Grid?
    SchwarzWeiss-Bitmap in Picturebox?
    noch was anderes?
    Eine 2dimmensionale Matrix klingt gut. Funktionen zum Anzeigen sind schon vorhanden. Ich habe mir gestern Abend folgendes überlegt:

    Es gibt beispielsweise eine Linie von X1-Y1 bis X2-Y2 (5,5 bis 20,10).

    VB.NET-Quellcode

    1. for X3 = X1 to X2
    2. Y3 = (Y2 / Y1) / (y1 / X1)
    3. next

    Diese Funktion müßte man noch verallgemeinern, damit auch 0-Koordinaten abgefangen werden. Außerdem muß man sich entscheiden ob Y3 auf- oder abgerundet werden soll. Was haltet ihr von dieser Idee?
    Was ist Y3?
    Wenn es Dir darum geht, die Y-Werte der Linie für einen gegebenen X-Wert zu berechnen, dann kannst Du das so machen:
    Y = (Y(max)-Y(min)) : (X(max)-X(min)) * x
    Das ist eine einfache lineare Gleichung. Y-Differenz : X-Differenz = Anstieg der Geraden. Anstieg mal x-Wert ergibt y-Wert für jenen x-Wert.
    Nur wenn X(max) und X(min) gleich sind, kann man keinen Anstieg berechnen, da das eine Division durch Null ergäbe. Dafür müsstest Du einen Sonderfall einbauen.
    Aber wahrscheinlich ist es das, was Du gemint hattest.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    jo, ich denke, du kannst nun erstmal eine Function schreiben, die zwei Punkte (quasi eine Linie) entgegennimmt, und die eine Liste von Punkten returnt - nämlich alle Punkte auf dieser Linie.

    Diese Linie kannst du in einem weiteren Schritt in deine Braille-Matrix eintragen.

    Zu letzterem kann ich noch nichts sagen, weil du post#8 noch nicht entshieden hast.
    So, jetzt habe ich eine Funktion gebastelt:

    VB.NET-Quellcode

    1. Private Sub GCODEObjektImportierenMenue_Click(sender As Object, e As EventArgs) Handles GCODEObjektImportierenMenue.Click
    2. If DateiOeffnenDialog.ShowDialog = DialogResult.OK Then
    3. 'Als Erstes wird die Datei geöffnet und in eine Liste übertragen.
    4. 'Dabei werden alle nicht relevanten Zeilen herausgefiltert.
    5. 'Gleichzeitig wird die Größe des Objektes ermittelt. Hierfür wird
    6. 'die Schichtdicke als Minimalgröße der einzelnen Tabellenzellen
    7. 'festgelegt. Dahinter werden jeweils die Anfangs- und
    8. 'Endkoordinaten jeder Linie geschrieben.
    9. Dateiinhalt = New StreamReader(DateiOeffnenDialog.FileName)
    10. 'Die Schichtdicke wird ermittelt.
    11. AktuelleZeile = ""
    12. Do Until InStr(UCase(AktuelleZeile), "LAYER HEIGHT: ") Or Dateiinhalt.EndOfStream
    13. AktuelleZeile = Dateiinhalt.ReadLine
    14. Loop
    15. '...
    16. Schichtdicke = Val(Mid(AktuelleZeile, X1, Y1 - X1))
    17. 'Nun wird eine Liste erstellt, die mit den
    18. 'Anfangs- und Endkoordinaten der einzelnen Linien gefüllt wird.
    19. Dim Koordinaten As New List(Of String)
    20. Koordinaten.Add("")
    21. 'Jede Zeile, die mit G0 beginnt, beinhaltet die
    22. 'Anfangskoordinaten. Jede Zeile, die mit G1 beginnt, enthält
    23. 'die Endkoordinaten. Die dazugehörigen Anfangskoordinaten sind
    24. 'die Endkoordinaten der letzten Zeile.
    25. AktuelleSchicht = 0
    26. AktuelleZeile = Dateiinhalt.ReadLine
    27. Do Until Dateiinhalt.EndOfStream Or InStr(UCase(AktuelleZeile), ";END GCODE")
    28. 'Die Koordinaten werden anhand der Schichtdicke auf ganze
    29. 'Zahlen gerundet.
    30. If InStr(UCase(AktuelleZeile), "LAYER:") > 0 Then
    31. '...
    32. AktuelleSchicht = Val(Mid(AktuelleZeile, X1, Y1 - X1))
    33. End If
    34. If Mid(UCase(AktuelleZeile), 1, 3) = "G0 " And InStr(UCase(AktuelleZeile), "X") And InStr(UCase(AktuelleZeile), "Y") Then
    35. X1 = InStr(UCase(AktuelleZeile), "X") + 1
    36. Y1 = X1
    37. Do Until Mid(AktuelleZeile, Y1, 1) = " " Or Y1 > Len(AktuelleZeile)
    38. Y1 += 1
    39. Loop
    40. X2 = InStr(UCase(AktuelleZeile), "Y") + 1
    41. Y2 = X2
    42. Do Until Mid(AktuelleZeile, Y2, 1) = " " Or Y2 > Len(AktuelleZeile)
    43. Y2 += 1
    44. Loop
    45. X1 = Math.Round(Val(Mid(AktuelleZeile, X1, Y1 - X1)) / Schichtdicke, 0)
    46. Y1 = Math.Round(Val(Mid(AktuelleZeile, X2, Y2 - X2)) / Schichtdicke, 0)
    47. Koordinaten.Item(Koordinaten.Count - 1) = AktuelleSchicht & "," & X1 & "," & Y1 & ","
    48. End If
    49. If Mid(UCase(AktuelleZeile), 1, 3) = "G1 " And InStr(UCase(AktuelleZeile), "X") And InStr(UCase(AktuelleZeile), "Y") Then
    50. X1 = InStr(UCase(AktuelleZeile), "X") + 1
    51. Y1 = X1
    52. Do Until Mid(AktuelleZeile, Y1, 1) = " " Or Y1 > Len(AktuelleZeile)
    53. Y1 += 1
    54. Loop
    55. X2 = InStr(UCase(AktuelleZeile), "Y") + 1
    56. Y2 = X2
    57. Do Until Mid(AktuelleZeile, Y2, 1) = " " Or Y2 > Len(AktuelleZeile)
    58. Y2 += 1
    59. Loop
    60. X1 = Math.Round(Val(Mid(AktuelleZeile, X1, Y1 - X1)) / Schichtdicke, 0)
    61. Y1 = Math.Round(Val(Mid(AktuelleZeile, X2, Y2 - X2)) / Schichtdicke, 0)
    62. Koordinaten.Item(Koordinaten.Count - 1) &= X1 & "," & Y1
    63. Koordinaten.Add(AktuelleSchicht & "," & X1 & "," & Y1 & ",")
    64. End If
    65. AktuelleZeile = Dateiinhalt.ReadLine
    66. Loop
    67. Dateiinhalt.Close()
    68. 'Hier werden die Linienkoordinaten um die Punkte ergänzt, die
    69. 'jeweils dazwischen liegen. Diese werden auf ganze Zahlen gerundet.
    70. For X As Integer = 0 To Koordinaten.Count - 1
    71. AktuelleZeile = Koordinaten.Item(X)
    72. X1 = 1
    73. Do Until Mid(AktuelleZeile, X1, 1) = ","
    74. X1 += 1
    75. Loop
    76. X1 += 1
    77. Y1 = X1
    78. Do Until Mid(AktuelleZeile, Y1, 1) = ","
    79. Y1 += 1
    80. Loop
    81. Y1 += 1
    82. X2 = Y1
    83. Do Until Mid(AktuelleZeile, X2, 1) = ","
    84. X2 += 1
    85. Loop
    86. X2 += 1
    87. Y2 = X2
    88. Do Until Mid(AktuelleZeile, Y2, 1) = ","
    89. Y2 += 1
    90. Loop
    91. Y2 += 1
    92. Zwischenspeicher = Mid(AktuelleZeile, 1, X2 - 1)
    93. X1 = Val(Mid(AktuelleZeile, X1, Y1 - X1 - 1))
    94. Y1 = Val(Mid(AktuelleZeile, Y1, X2 - Y1 - 1))
    95. X2 = Val(Mid(AktuelleZeile, X2, Y2 - X2 - 1))
    96. Y2 = Val(Mid(AktuelleZeile, Y2, Len(AktuelleZeile) - Y2 + 1))
    97. AktuelleZeile = Mid(AktuelleZeile, Len(Zwischenspeicher) + 1, Len(AktuelleZeile) - Len(Zwischenspeicher))
    98. X3 = X1
    99. Do Until X3 = X2
    100. If X2 > X1 Then
    101. X3 += 1
    102. Else
    103. X3 -= 1
    104. End If
    105. Y3 = Math.Round(Y1 + (((Y2 - Y1) / (X2 - X1)) * (X3 - X1)), 0)
    106. Zwischenspeicher &= X3 & "," & Y3 & ","
    107. Loop
    108. Y3 = Y1
    109. Do Until Y3 = Y2
    110. If Y2 > Y1 Then
    111. Y3 += 1
    112. Else
    113. Y3 -= 1
    114. End If
    115. X3 = Math.Round(X1 + (((X2 - X1) / (Y2 - Y1)) * (Y3 - Y1)), 0)
    116. Zwischenspeicher &= X3 & "," & Y3 & ","
    117. Loop
    118. Zwischenspeicher &= AktuelleZeile
    119. Koordinaten.Item(X) = Zwischenspeicher
    120. Next
    121. End If
    122. End Sub

    Am Ende habe ich einen virtuellen Würfel, der das 3D-Objekt enthält. In weiteren Funktionen kann der Würfel gedreht, verschoben oder gekippt werden. Diese Funktionen sind auch schon fertig.

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

    Bei der Codeauslagerung von Code in Methoden geht es schon lange nicht mehr nur um Wiederverwendung, sondern auch um Verständnis. Portionsblöcke auslagern und einen passenden Methodennamen vergeben. Damit man nicht bei jedem Mal Code durchschauen erstmal durchblicken muss.
    Du hast hier einen 120-Zeilen-Brocken, der problemlos in kleinere Häppchen aufgeteilt werden kann. Den Anfang macht eine If-Umkehrung, um die Übersicht zu verbessern bzw. den Code etwas zu vereinfachen. Danach kann man den Rest weiter aufteilen. Das ist zumindest (m)eine Empfehlung. Wenn Du es bei dem Ungetüm lassen willst - es ist Dein Code.

    Ach ja, Du könntest Dich natürlich auch aller VB6-Anachronismen entledigen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Was meinst du denn mit "VB6-Anachronismen"? Kannst du mir da ein Beispiel geben? Das ganze Programm, dessen Teil diese Funktion ist, ist mittlerweile sehr groß geworden. Ich versuche ab und zu, wenn es die Zeit zuläßt, den Code und die Oberfläche zu vereinfachen.

    Mittlerweile habe ich den Code zum berechnen eines gcode-Objektes fertiggestellt. Auch die Steuerung, das Objekt aus jeder Perspektive und jeder 90-Grad-Rotation anzeigen zu lassen funktioniert. Der Benutzer kann auch durch die Ebenen gehen, das Objekt drehen und zoomen. Nun kann eine blinde Person 3D programmieren und sein Objekt auch mit einem Brailledisplay ansehen. Sorry für die eigene Schulterklopferei, aber 3D war bis jetzt für Blinde ein Ding der fast Unmöglichkeit.

    Für die, die es interessiert, werte ich nur die Koordinaten der äußeren Wände aus und fülle die Koordinaten dazwischen mit einer Funktion. Dadurch wird ein Würfel mit Ausspahrungen und eingefügten Textelementen mit einer Kantenlänge von 100 mm und einer Auflösung von 0.2 mm in ca. 4 Sek. berechnet und angezeigt. Nachdem ich aber einen Fortschrittsbalken hinzugefügt habe, kamen leider noch 2 Sek. dazu. Das ist aber in Anbetracht dessen, das das Objekt aus 500x500x500 Einheiten besteht noch OK.
    Respekt für das Programm. Ich kann zwar den Vollumfang und die Erfolge nicht einschätzen, klingt alles aber nach einer großen Sache. Hut ab!
    Deine VB6-Punkte kommen zustande, weil Du noch den Microsoft.VisualBasic-Namespace drinhast und so alte Funktionen nutzen kannst wie: InStr, UCase, Mid, Val. Dafür gibt es VB.NET-Pendants. Allerdings ticken diese für InStr und Mid etwas anders. InStr und Mid beginnen ihre Zählungen bei 1, ihre Pendants IndexOf und Substring bei 0.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Irgendwann, wenn ich genügend Zeit habe, werde ich MID und INSTR auch ersetzen, allerdings brauche ich da viel Zeit. Während INSTR nur 28 mal vorkommt, habe ich MID 851 mal verwendet. Das dauert ein wenig, die Parameter anzupassen. Trotzdem Danke für den Hinweis.

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