Mathematisch fehlendes Verständnis (3D-Denken)

Hag2bard

Bekanntes Mitglied
Hallo,

ich habe folgende Ausgangssituation:

Ich habe einen Code geschrieben, der mir ein Feld z.b. bei der Koordinate 0,0 (x,y) zeichnet
nun möchte ich mit Hilfe einer Schleife, dass er je nach Eingabe der Länge der zu zeichnenden Felder (also 1 steht dann für 1x1 Feld, 2 steht für 2x2 Felder) vollständig zeichnet.
Bei meinem derzeitigem Code sieht das ganze bei 4x4 Feldern so hier aus:
1648629891584.png
Ihr erkennt das Problem sicher direkt.
Ab hier fehlt mir einfach das mathematische Verständnis, wie ich sowas in eine Schleife einbaue bzw. definiere.

Könnt ihr mir auf die Sprünge helfen?

Danke im Voraus
 

httpdigest

Top Contributor
Naja, im Prinzip kannst du zwei Schleifen (ineinander verschachtelt) verwenden. Jeweils eine für die X-Dimension und eine für die Y-Dimension. Beide mit derselben Länge/Anzahl an Iterationen.
Wie du es aber konkret machen musst, um da was zu zeichnen, hängt davon ab, welche API genau du verwendest, um zu zeichnen.
 

Hag2bard

Bekanntes Mitglied
Danke für die Antwort,
ich überschreibe die PaintComponent Methode in einem Panel.
Das Zeichnen bekomme ich hin aber mir fehlt das Verständnis mathematischer Natur.
Ich versuche es mal so wie du gesagt hast.
 

httpdigest

Top Contributor
Was genau meinst du denn mit "mathematisch"? Mit "Mathematik" hat das Problem eigentlich nichts zu tun. Das Problem hat ja auch nichts mit "3D" zu tun. Du hast ja nur zwei Dimensionen, also 2D.
 

Hag2bard

Bekanntes Mitglied
Ich habe es jetzt hinbekommen dank deiner Hilfe.

Java:
        for (int x = 0; x < tilePanel.getAmountOfSelectedBlocks(); x++) {
            for (int y = 0; y < tilePanel.getAmountOfSelectedBlocks(); y++) {
                g.drawRect((mousePositionX * TILESIZE * ZOOM) + (x * TILESIZE * ZOOM), (mousePositionY * TILESIZE * ZOOM), TILESIZE * ZOOM, TILESIZE * ZOOM);//sollte eigentlich fertig sein an dieser Stelle
                g.drawRect((mousePositionX * TILESIZE * ZOOM) + (y * TILESIZE * ZOOM), (mousePositionY * TILESIZE * ZOOM), TILESIZE * ZOOM, TILESIZE * ZOOM);//sollte eigentlich fertig sein an dieser Stelle
             
                g.drawRect((mousePositionX * TILESIZE * ZOOM), (mousePositionY * TILESIZE * ZOOM) + (x * TILESIZE * ZOOM), TILESIZE * ZOOM, TILESIZE * ZOOM);//sollte eigentlich fertig sein an dieser Stelle
                g.drawRect((mousePositionX * TILESIZE * ZOOM), (mousePositionY * TILESIZE * ZOOM) + (y * TILESIZE * ZOOM), TILESIZE * ZOOM, TILESIZE * ZOOM);//sollte eigentlich fertig sein an dieser Stelle
             
                g.drawRect((mousePositionX * TILESIZE * ZOOM) + (x * TILESIZE * ZOOM), (mousePositionY * TILESIZE * ZOOM) + (x * TILESIZE * ZOOM), TILESIZE * ZOOM, TILESIZE * ZOOM);//sollte eigentlich fertig sein an dieser Stelle
                g.drawRect((mousePositionX * TILESIZE * ZOOM) + (x * TILESIZE * ZOOM), (mousePositionY * TILESIZE * ZOOM) + (y * TILESIZE * ZOOM), TILESIZE * ZOOM, TILESIZE * ZOOM);//sollte eigentlich fertig sein an dieser Stelle
             
                g.drawRect((mousePositionX * TILESIZE * ZOOM) + (y * TILESIZE * ZOOM), (mousePositionY * TILESIZE * ZOOM) + (y * TILESIZE * ZOOM), TILESIZE * ZOOM, TILESIZE * ZOOM);//sollte eigentlich fertig sein an dieser Stelle
                g.drawRect((mousePositionX * TILESIZE * ZOOM) + (y * TILESIZE * ZOOM), (mousePositionY * TILESIZE * ZOOM) + (x * TILESIZE * ZOOM), TILESIZE * ZOOM, TILESIZE * ZOOM);//sollte eigentlich fertig sein an dieser Stelle
            }
        }

Endergebnis:

1648630726444.png

Jetzt muss ich nur noch schauen, ob ich den Code vereinfachen kann.

Danke dir vielmals

P.S.: Dann halt eben 2D. :D Ich habe ein schlechtes räumliches Vorstellungsvermögen und das zählte da auch schon dazu für mich.

edit: Ich dachte echt, dass ihr mir hier jetzt mit Vektoren und sowas kommt :D
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Jetzt muss ich nur noch schauen, ob ich den Code vereinfachen kann.
Da möchte ich mich mal wieder mit dem melden, mit dem ich mich immer wieder einmische:

Bei der Programmierung (speziell der objektorientierten) ist es immer gut, sich alles genau vorzustellen. Der große Vorteil ist, dass man so eben eine sehr gute Vorstellung bekommt - auch Du!
Ich habe ein schlechtes räumliches Vorstellungsvermögen und das zählte da auch schon dazu für mich
Du musst Dir da ja nichts vorstellen. Du kannst es real anpacken. Nmm Dir Stift und Papier. Und nun machst Du es.

Wie malst Du die Rechtecke auf? Wie bekommst Du das Endergebnis aufs Papier?

Einen möglichen Algorithmus hast Du schon: Du fängst an einer Ecke an um da ein erstes Quadrat zu zeichen. Und dan zeichnest Du ein Quadrat nach dem anderen.

Ist das wirklich dein Vorgehen? Oder findest Du ein anderes Vorgehen? Ein Vorgehen, das evtl. schneller geht?

Oder wenn Du Probleme hast, da in abstrakten Quadraten zu denken: Das sieht doch z.B. aus wie ein Regal. Wie ist denn so ein Regal aufgebaut? Sind das einfach nur Kisten, die aneinander gereiht werden? (Wird es bestimmt auch geben.) Oder hast Du da evtl. schon anderes regal gesehen? Also z.B. mit Brettern irgendwas?

Hilft Dir evtl. so eine konkrete Vorstellung? Das ist etwas, das ich nur empfehlen kann. In den Anfängen der objektorientierten Entwicklung, z.B. bei der Sprache Smalltalk wurde das auch immer gut visualisiert: Instanzen waren dann Objekte, die sich Nachrichten geschickt haben. Das ging (aus meiner Sicht) dann auch in die Richtung, das abstrakte zu reduzieren.
 

Hag2bard

Bekanntes Mitglied
Die Lösung funktioniert, aber ich würde dennoch gerne auf deine Antwort eingehen.
Ich habe vorhin angefangen mir aufzuschreiben, welche Kästchen gezeichnet werden müssen, erfolglos.

Ich habe z.b. 4x4 Kästchen, also muss ich
in Y0 die Kästchen 0,1,2,3 zeichnen.
In Y1 die Kästchen 0,1,2,3
In Y2 die Kästchen 0,1,2,3
In Y3 die Kästchen 0,1,2,3
Das sind 4x4=16 Kästchen

Ich bräuchte also eine Schleife(Y) die erst bei Y0 anfängt, da von X0-X3 geht und sich dann erhöht. Also ist die Idee mit den verschachtelten Schleifen meiner Meinung nach eigentlich die beste.
Also im Grundprinzip baue ich damit Reihe für Reihe auf.
Ich weiß nicht wieso ich nicht selber drauf kam...
Gibt es eine bessere Vorgehensweise oder einen anderen Denkansatz?
 

httpdigest

Top Contributor
Du kannst es natürlich auch mit nur einer Schleife machen, indem du dir z.B. aus einem linearen 1D Index einen 2D Index berechnest:
Java:
for (int i = 0; i < w * w; i++) {
  int x = i % w;
  int y = i / w;
  // mach was mit (x, y):
  // ...
}
 

KonradN

Super-Moderator
Mitarbeiter
Worauf ich hinaus wollte ist einfach etwas anderes:

Anstatt Kästchen zu malen, malst Du nur Linien.

Um dieses Bild von 4x4 Kästchen zu malen, würde ich halt einfach erst 5 horizontale Linien malen mit Länge 4*Breite, jeweils im Anstand der gewünschten Höhe (Bei Dir sollen es Quadrate sein, also Höhe = Breite). Im Anschluss würde ich die 5 vertikalen Linien malen im Abstand der Breite und ich wäre fertig.

Das Vorgehen kann man dann also etwas verallgemeinern. Was ist notwendig für n*n Kästchen?

Um 1 Kästchen zu haben, brauchst Du zwei horizontale und zwei vertikale Linien.
Um 2x2 Kästchen zu haben, brauchst Du drei horizontale und drei vertikale Linien.
...
um n*n Kästchen zu haben, brauchst Du n+1 horizontale und n+1 vertikale Linien.

Die Länge jeder Linie ist n mal gewünschte Breite (oder Länge)
Der Abstand zwischen zwei Linien ist die gewünschte Breite (oder Länge)

Daher noch einmal mein Vorschlag: Statt es Dir abstrakt vorzustellen: Spiel es durch! Stift und Papier ist Dein Freund! Mal es einfach ein paar Mal auf und schau, wie Du es möglichst einfach aufmalen kannst. Den Weg versuchst Du dann so zu beschreiben, dass es jeder nachvollziehen kann, selbst wenn er die Aufgabe nicht kennt (Meine Beschreibung ist noch nicht ausreichend. Die Anfangspunkte jeder Linie sind noch nicht gegeben. Die horizontalen Linien müssen natürlich genau übereinnder sein - nur in der Höhe versetzt.)

Gerade wenn Du Probleme hast, die alles im Kopf vorzustellen ist das notwendig! Übe es also direkt von Anfang an! Spätestens bei den Abstrakten Datentypen wirst Du es brauchen. Bei verketteten Listen und Bäumen und so geht nichts über ein Aufmalen der jeweiligen Situation und dem Drchspielen der notwendigen Schritte mit Stift und Papier!

Es ist also schlicht normal, dass Du da gewisse Probleme hast. Das hat jeder (natürlich in unterschiedlicher Ausprägung)! Daher diese (eindringliche) Empfehlung. Stift und Papier oder im Büro im Team ein Whiteboard sind das beste Hilfsmittel! Oder bei fachlichen Dingen teilweise eine visualisierte Darstellung der Zusammenhänge die dann zur offiziellen Doku gehören und die dann eigentlich immer offen ist, wenn man da etwas macht.
 

Hag2bard

Bekanntes Mitglied
Das mit den 5 Linien pro Richtung ist verständlich. Als nächstes müsste ich aber die Koordinaten der Linien festlegen.

Kästchenbreite: 32 Pixel

Horizontale Linien:
Linie0 = 0,0(x,y) i=0
Linie1 = 0,32 i=1
Linie2 = 0,64 i=2
Linie3 = 0,96 i=3
Linie4 = 0,128 i=4

Linie(i) = 0,32*i

Vertikale Linien:

Linie(i) = 32*i,0

Das finde ich aber deutlich komplizierter, auch wenn der Code kürzer ist.

Wie soll ich das angehen?
Mein Code bisher:

Java:
int blockX = mousePositionX * TILESIZE * ZOOM;
int blockY = mousePositionY * TILESIZE * ZOOM;
final int BLOCKSIZE = TILESIZE * ZOOM;
for (int x = blockX; x < ((tilePanel.getAmountOfSelectedBlocks() + 1) * BLOCKSIZE); x += BLOCKSIZE) {                   //+1 nur bei zweiter Methode
    for (int y = blockY; y < ((tilePanel.getAmountOfSelectedBlocks() + 1) * BLOCKSIZE); y += BLOCKSIZE) {
        g.drawLine(x, y, x + BLOCKSIZE, y);
        g.drawLine(x, y, x, y + BLOCKSIZE);
}}

Dieser verhält sich absolut merkwürdig.
Ich kann es noch nichtmal erklären, was er macht.

Wäre es nicht besser den Code eher simpel zu halten, als unverständlich?
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Die Idee ist dabei natürlich weiterhin, dass der Code übersichtlich ist und bleibt. Dazu muss man aber natürlich den Algorthmus als erstes verständlich formulieren. Das ist und bleibt immer der erste Schritt und am Anfang solltest Du den auch genau so durchführen, z.B. als Kommentar im Editor.
So ist Dein angepasster Code ist auch nicht das, was ich an möglicher Lösung skizziert habe. Wenn Du das mit den Horizontalen und Vertikalen Linien aufgreifen willst, dann
a) Mach das einmal manuell mit Stift und Papier für z.B. n = 5. Hast Du das hin bekommen?
b) Wie hast Du es hin bekommen? Kannst Du die Schritte genau bechreiben? Und zwar so genau, dass Du diese Anleitung an jemand anderes geben kannst und der kann es dann auch.
c) Wie sind die Schritte anzupassen, wenn Du statt n = 5 ein n=6 oder n=7 hast? Kannst Du die Schritte verallgemeinern?

Und dann kommt am Ende etwas gut lesbarer bei raus - dazu kann man dann auch Methoden verwenden. Deine Paint Methode könnte dann z.B. beinhalten:
Java:
drawVerticalLines(g);
drawHorizontalLines(g);

==> Damit ist der Code klar verständlich: Erst werden die vertikalen und dann die horizontalen Linien gezeichnet.
 

Hag2bard

Bekanntes Mitglied
Ich hab das jetzt so hier gelöst:

Java:
  private void drawVerticalLines(Graphics g) {
        int blockX = mousePositionX * TILESIZE * ZOOM;
        int blockY = mousePositionY * TILESIZE * ZOOM;
        final int BLOCKSIZE = TILESIZE * ZOOM;

        for (int x = blockX; x < ((tilePanel.getAmountOfSelectedBlocks() + 1) * BLOCKSIZE); x += BLOCKSIZE) {
            g.drawLine(x, blockY, x, blockY + (BLOCKSIZE * tilePanel.getAmountOfSelectedBlocks()));
        }
    }

    private void drawHorizontalLines(Graphics g) {
        int blockX = mousePositionX * TILESIZE * ZOOM;
        int blockY = mousePositionY * TILESIZE * ZOOM;
        final int BLOCKSIZE = TILESIZE * ZOOM;

        for (int y = blockY; y < ((tilePanel.getAmountOfSelectedBlocks() + 1) * BLOCKSIZE); y += BLOCKSIZE) {
            g.drawLine(blockX, y, blockX + (BLOCKSIZE * tilePanel.getAmountOfSelectedBlocks()), y);
        }

Aber da bringt er auch sehr merkwürdige Ergebnisse hervor

(Maus ist hier in dem Fall wo ihr den roten Punkt seht (hab ich selber grad reingezeichnet)

1648645155582.png1648645195659.png
Was ist da denn los?



EDIT:

Das war eine sehr schwere Geburt, ich habe es gelöst:

Java:
 private void drawVerticalLines(Graphics g) {
        int blockX = mousePositionX * TILESIZE * ZOOM;
        int blockY = mousePositionY * TILESIZE * ZOOM;
        final int BLOCKSIZE = TILESIZE * ZOOM;

        for (int x = blockX; x < (blockX+(tilePanel.getAmountOfSelectedBlocks() + 1) * BLOCKSIZE); x += BLOCKSIZE) {
            g.drawLine(x, blockY, x, blockY + (BLOCKSIZE * tilePanel.getAmountOfSelectedBlocks()));
        }
    }

    private void drawHorizontalLines(Graphics g) {
        int blockX = mousePositionX * TILESIZE * ZOOM;
        int blockY = mousePositionY * TILESIZE * ZOOM;
        final int BLOCKSIZE = TILESIZE * ZOOM;

        for (int y = blockY; y < (blockY+(tilePanel.getAmountOfSelectedBlocks() + 1) * BLOCKSIZE); y += BLOCKSIZE) {
            g.drawLine(blockX, y, blockX + (BLOCKSIZE * tilePanel.getAmountOfSelectedBlocks()), y);
        }


Endergebnis:

1648645757512.png
 
Zuletzt bearbeitet:

KonradN

Super-Moderator
Mitarbeiter
Ja genau. So in der Art dachte ich es mir. Super!

Ich hoffe, dass das mit dem möglichen Vorgehen auch soweit gut verständlich war, denn ich bin davon überzeugt, dass man so meist am einfachsten zum Ziel kommt.

Ich wünsche Dir auf jeden Fall weiter viel Spaß und Erfolg mit Deiner weiteren Entwicklung!
 

Hag2bard

Bekanntes Mitglied
Vielen Dank!
Mein Projekt wird immer größer und momentan bin ich dran den Code zu säubern und Bugs zu beheben.
Wenn ich rausgefunden habe, wie ich intelliJ mit Github synchronisieren kann, kann ich gerne mal die Repo teilen.
 

X5-599

Top Contributor
Schön, dass du Erfolg hattest. Ich möchte allerdings auch mal meinen Senf dazu geben und sagen, dass meiner Meinung nach dieser Algorithmus schon eher schwer zu verstehen ist. Für außenstehende und ich denke auch für dich selbst (nach ein paar Wochen).

Mein alternativer Vorschlag: Bleib bei der drawRect Methode von Graphics. Denn, das ist ja das was du eigentlich tun willst; Rechtecke zeichnen.
Textuelle Beschreibung eines Algorithmus kann schon ziemlich komplex werden, aber ich versuche es einmal:

Um Verwirrung zu vermeiden sollten wir zwischen den Koordinaten der Rechtecke (im Grid) und der eigentlichen x/y Koordinaten der drawRect Methode unterscheiden. Rechtecke sprechen wir daher per "Zeile,Spalte" an. Die drawRect Methode behält das "x,y".

Stell dir das Grid so vor wie es hinterher aussehen soll (wie in deinem Beitrag #5). Wie würden wir also anfangen das erste Rechteck oben links zu zeichnen? (mittels drawRect). wir brauchen dafür: die x/y Koordinate, die Breite, die Höhe. Breite und Höhe sind Konstant; also kein Problem.
x/y von drawRect geht von der linken oberen Ecke aus. d.h. Um unser erstes Rechteck zu zeichnen brauchen wir x=0; y=0;
Okay, das war leicht. Das nächste Rechteck soll rechts davon gezeichnet werden. Jetzt kommen wir zur eigentlichen Berechnung der x/y drawRect Koordinaten. y ist weiterhin 0. x muss jetzt genau da sein wo das vorherige Rechteck aufhört. Das wissen wir weil wir die Breite des Rechtecks kennen. Also x=Breite.

Soweit ist noch nicht unbedingt eine Gesetzmäßigkeit erkennbar. Die wird im nächsten Schritt klar. Denn welchen Wert muss x haben wenn das dritte Rechteck gezeichnet werden soll? Es befinden sich zwei Rechtecke vor ihm. Also ist x = 2 * Breite.
Das vierte Rechteck müsste x = 3 * Breite bekommen. Ein fünftes x = 4 * Breite usw. Das ist die Gesetzmäßigkeit.
Für die y Koordinate gilt nebenbei genau dasselbe. Es muss nur jeweils x mit y und Breite mit Höhe getauscht werden.

Wir werden nur eine einzige drawRect Methode haben, die uns alle Rechtecke zeichnen soll. d.h die Konstanten (2 *, 3 *, 4 *) etc für die x/y Berechnung müssen dynamisch errechnet werden können. Wie kriegen wir das hin? Schauen wir nochmal darauf wie wir auf diese Multiplikatoren gekommen sind. Bei der (2 *) hatten wir das dritte Rechteck gezeichnet. Bei der (3 *) das vierte. Die Multiplikatoren stehen also im Zusammenhang mit dem jeweiligen Rechteck (immer Rechteck -1). Die Rechteck Koordinaten haben wir, weil wir wissen in welcher Zeile,Spalte sich das Rechteck befindet, welches wir gerade zeichnen wollen.


Das war im Grunde alles was den Algorithmus ausmacht. Jetzt geht es mehr in Richtung Code. Die Zeile, Spalte Koordinaten werden die Grenzen der beiden verschachtelten for-Schleifen sein. Und wenn wir das ganze '0' basiert aufbauen brauchen wir nichtmal das "-1" zu machen um den Multiplikator zu erhalten.
Somit haben wir alles was wir brauchen um einen funktionierenden Code zu schreiben. Beim editieren hat sich durchaus das bewahrheitet was ich befürchtet habe; Algorithmen textuell zu beschreiben ist Wortreich und wird sehr schnell unverständlich.
Ich denk aber wenn man sich den Code dazu ansieht sollte es klarer werden.


Code:
@Override
protected void paintComponent(Graphics g)
{
    super.paintComponent(g);
    
    int amountSelectedBlocks = 4;
    int tileSize = 100;
    
    drawGrid(amountSelectedBlocks, amountSelectedBlocks, tileSize, tileSize, g);
}

private void drawGrid(int nRows, int nColumns, int boxHeight, int boxWidth, Graphics g)
{
    for(int row = 0; row < nRows; row++)
    {
        for(int col = 0; col < nColumns; col++)
        {
            int width  = boxWidth;
            int height = boxHeight;
            
            int x = col*boxWidth;
            int y = row*boxHeight;
            
            g.drawRect(x, y, width, height);
        }
    }
}

Wir können die innere for-Schleife auch auf eine Zeile reduzieren. Ich habe halt extra mal aufgeführt wie die Parameter der drawRect Methode zustande kommen. Mal von der Textwand der Erklärung abgesehen finde ich diese Variante wesentlich einfacher zu verstehen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
N Betrag (mathematisch) Allgemeine Java-Themen 2
J CSVWriter und fehlendes CRLF Allgemeine Java-Themen 1
meez Bug, fehlendes Feature oder Ok? Allgemeine Java-Themen 3
berserkerdq2 Threads, wie genau läuft das in Java ab? (Ich kann Threads erstellen und nutzen, nur das Verständnis) Allgemeine Java-Themen 6
A Hilfe beim Verständnis Allgemeine Java-Themen 16
Kirby.exe Verständnis Problem bei Rucksack Problem Allgemeine Java-Themen 6
parrot Verständnis des Codes Allgemeine Java-Themen 3
L Vererbung Verständnis Probleme Vererbung Allgemeine Java-Themen 2
M True or false Verständnis Allgemeine Java-Themen 5
D (Verständnis-)Problem mit Unterklasse Allgemeine Java-Themen 4
J Josephus Verständnis Allgemeine Java-Themen 1
J Verständnis Frage zur Instanz, Objekte, Instanzierung, Referenz Allgemeine Java-Themen 14
H Erste Schritte Beispiele zum Verständnis Allgemeine Java-Themen 3
T Input/Output Verständnis: Wo wird das File auf die Festplatte gepackt? Allgemeine Java-Themen 4
B Hilfe beim Verständnis von Mergesort Allgemeine Java-Themen 5
C int zu byte cast - verständnis Allgemeine Java-Themen 3
M Verständnis enum - switch Allgemeine Java-Themen 2
M Verständnis "synchronized" Allgemeine Java-Themen 4
C Verständnis zur Strukturierung von Java-Projekten/Interfaces Allgemeine Java-Themen 2
C Autoboxing Verständnis Allgemeine Java-Themen 4
S Probleme mit dem allgemeinen Verständnis zuverrebung usw. Allgemeine Java-Themen 6
S Verständnis Problem - Classpath Allgemeine Java-Themen 5

Ähnliche Java Themen

Neue Themen


Oben