Optimiertes Zeichnen - wie?

Status
Nicht offen für weitere Antworten.

Antimon

Mitglied
Hallo zusammen,

folgende Problematik besteht bei mir: Ich zeichne verschiedene Objekte auf ein Panel über die paintComponent()-Methode. Dabei kann das Panel ziemlich groß werden, deswegen wird es in einer JScrollPane untergebracht. Das Ganze ist übrigens ähnlich der Zeichenfläche in einem Grafikprogramm, durch die Scrollpane kann man einen anderen Auschnitt einer Zeichnung betrachten.

Nun ist es so, dass bei einer Änderung (Verschieben von Grafikelementen, Verschieben des Bildausschnitts) das Panel neu gezeichnet werden müsste. Wenn aber beim Verschieben eines Elements mit ein paar Pixeln Größe jedes Mal das komplette Panel neu gezeichnet wird, sinkt die Performance ziemlich in den Keller.

Gut, nun kann man der repaint-Methode Koordinaten mitgeben, die neu gezeichnet werden sollen.
Allerdings: Bezieht sich das auf die Koordinaten des Panels, auf dem gezeichnet wird, oder auf die Koordinaten des sichtbaren Bildausschnitts der Scrollpane?

Das weitere Problem ist, dass mein Koordinatensystem nicht links oben mit (0,0) beginnt, sondern links unten. Um das zu erreichen, wird das Graphics-Objekt in der paintComponent-Methode mit

Code:
AffineTransform trafo = new AffineTransform();
trafo.scale(1.0, -1.0);
trafo.translate(-scrollpane.getViewport().getViewPosition().getX(), -panel.getHeight() + scrollpane.getViewport().getViewPosition().getY());
g2d.setTransform(trafo);

gespiegelt.

Beziehen sich jetzt die Koordinaten für repaint() auf die Bildschirmkoordinaten, oder werden die durch die Transformation auch gleich mit umgerechnet? Ich habe zwar versucht, mir den repaint-Bereich einzeichnen zu lassen, aber da kam nur Müll dabei raus...

Und zu guter Letzt: Wird nur ein Bereich per repaint neu gezeichnet, muss ich den in der paintComponent()-Methode abfragen und dann nur die Elemente neu zeichnen, die in diesen Bereich hineinragen, sehe ich das richtig?

Und wenn der Ausschnitt der Scrollpane verschoben wird, muss ich dann auch dafür sorgen, dass der neue sichtbare Ausschnitt neu gezeichnet wird? Oder wird da ein bereits erzeugtes Graphics-Objekt von Swing intern verwendet und nur der neue Ausschnitt angezeigt? Irgendwas mache ich da wohl noch falsch, denn beim Verschieben entstehen einige Grafikfehler...

Mit den ganzen Paint-Geschichten blicke ich leider noch nicht so durch, ich habe mir zwar die Paint-Tutorials von Sun durchgelesen, aber die beantworten leider noch nicht alle Fragen - wenn Ihr Tips für mich habt, bin ich Euch sehr dankbar!
 

Ebenius

Top Contributor
So ziemlich alle Koordinaten und Größen in Component und deren Ableitungen beziehen sich mit 0×0 auf die linke obere Ecke der Komponente, nach rechts und unten ansteigend. Das trifft zum Beispiel auf getSize(), getLocation(), repaint(Rectangle), repaint(int, int, int, int), und getVisibleRect() zu. Letztere Methode sagt Dir, welches Rechteck der Komponente sichtbar ist, zum Beispiel in einer JScrollPane.

Wenn Du zeichnest, kannst Du alle anderen Bereiche außen vor lassen und nur innerhalb des VisibleRects zeichnen. Dieses musst Du natürlich ebenfalls durch die selbe Transformation schicken, um es in Deinem View-Koordinatensystem nutzen zu können.

Hilft das soweit?

Ebenius
 

Antimon

Mitglied
Hm okay das hilft mir schon mal weiter - ich muss also die Koordinaten selbst umrechnen.

Was mir allerdings noch nicht ganz klar ist, ist wie genau ich zeichnen muss/soll. Vielleicht verdeutlicht das ein Beispiel: Angenommen das Panel auf dem ich zeichne hat ein Raster mit Gitternetzlinien von 10 Pixeln Abstand und ist 800x600 Pixel groß. Die sichtbare Fläche ist 400x300 Pixel groß. Das bedeutet nun dass ich beim Zeichnen erst berechnen muss wo sich der Ausschnitt befindet und dort dann nur das sichtbare Gitter zeichne und nicht die kompletten 800x600 Pixel?

Oder würde es da vielleicht sogar Sinn machen, das komplette Gitter zu zeichnen, bevor erst ewig berechnet wird wo es denn nun beginnen muss - und vielleicht sogar Grafikfehler durch falsche Berechnungen entstehen?

Und Elemente die aus der Arbeitsfläche rausragen werden vermutlich besser gleich komplett gezeichnet anstatt großartig zu berechnen welche Ecken davon berechnet werden müssen und welche nicht, sehe ich das richtig?

Dass ich das komplette Bild einmal zeichne und dann nur noch wenn sich am Bildinhalt etwas ändert neu aufbaue, funktioniert nicht? Denn theoretisch könnte die komplette Grafik ja fertig gezeichnet im Speicher liegen und nur der sichtbare Ausschnitt angezeigt werden, solange sich an dem Inhalt der Grafik nichts ändert, müsste diese ja nicht neu gezeichnet werden?
 

Wildcard

Top Contributor
Ein pragmatischer Ansatz ist ein Bounding Box Test. Berührt die Bounding Box eines Objekt den Clip des Graphics Objects, dann zeichnest du es, ansonsten nicht. Damit fällt dir schon einiges weg.
Ob es Sinn macht diese Objekte dann evtl. nur partiell zu Zeichnen, hängt von der Komplexität deiner Objekte ab.
 

0x7F800000

Top Contributor
1) zu jedem der zu zeichnenden Objekte eine bounding box berechnen (das ist schonmal eine sehr gute idee)
2) je nach dem wie speicherintensiv das ist: entweder alles in ein großes regelmäßiges Gitter packen (wobei in jedes Kästchen... kA... 20-30-50-100? Objekte reinpassen)
Oder ein Quadtree über das ganze bild legen, und alle Objekte anhand der bounding box dareinpacken (hat den vorteil, dass die Feinheit der aufteilung variabel ist)
3) beim zeichnen schaust du, welcher bildausschnitt neugezeichnet werden muss, und zeichnest einfach alle sichtbare leafs (dank des Quadtrees musst du da nicht jedes objekt prüfen, ob es sich mit dem sichtbaren bereich schneidet, sondern kannst direkt gigantische äste des Quadtrees komplett ignorieren)
Dann brauchst du nicht O(n), sondern nur noch O(ln(n)), was bei vielen objekten ziemliche ersparnis ist (wenn die Objekte dumm verteilt sind, und du dennoch alle siehst, dann bringt es nichts, im worst case ist das immer noch O(n))

Wenn der zuletzt angesprochene fall eintreten kann, kannst du mit demselben Quadtree noch eine weitere optimierung anstellen:
-Beim ändern (verschieben, skalieren der Objekte) markierst du alle "betroffene" leafs des Quadtrees, d.h diejenigen, in den die Bounding box vorher gewesen war (dort wurden evtl bereiche offengelegt) sowohl alle diejenigen leafs, die von der bounding box nach der transformation betroffen sind (dort wurde evtl etwas verdeckt)
NUR DIESE leafs musst du jetzt neuzeichnen, alles andere kann unberührt bleiben, was wieder eine große ersparnis sein kann.

Noch eine weitere optimierungsstufe wäre es natürlich, große objekte (etwa Bilder) in kleinere rechtecke zu zersägen, damit man da auch nicht alles neuzeichnen muss...

Also, da sind der phantasie keine grenzen gesetzt.
 
Zuletzt bearbeitet:

Antimon

Mitglied
Okay, super - danke für die Tips schon mal, die werd ich jetzt mal Stück für Stück umsetzen.

Jetzt ist mir nur noch was aufgefallen, was mir nicht so gefällt:

Durch das Spiegeln des Koordinatensystems werden Texte, die ich per drawString() zeichne, auf den Kopf gestellt gezeichnet. Das ist natürlich eher suboptimal... muss ich nun für jeden Text den ich zeichnen möchte eine neue Spiegelung per scale(1.0, -1.0) plus benötigter Verschiebung ausführen oder geht das Ganze einfacher?

Also mein Ziel ist es, ein Koordinatensystem zu haben, das nach rechts positive x-Koordinaten hat und nach oben positive y-Koordinaten. Der Ursprung soll (verschiebbar) links unten im Fenster dargestellt werden. Gibt es einen sinnvolleren Ansatz als den von mir oben verwendeten?
 

0x7F800000

Top Contributor
Durch das Spiegeln des Koordinatensystems werden Texte, die ich per drawString() zeichne, auf den Kopf gestellt gezeichnet. Das ist natürlich eher suboptimal... muss ich nun für jeden Text den ich zeichnen möchte eine neue Spiegelung per scale(1.0, -1.0) plus benötigter Verschiebung ausführen oder geht das Ganze einfacher?
Hmm, willst du denn das wirklich zulassen? Ich kenne kein 2D-Bildbearbeitungs Programm o.ä. , wo man das Koordinatensystem Spiegeln kann. Normalerweise beschränken sich alle diese Programme auf Verschieben und Zoomen. Mehr ist imho auch nicht nötig, weil der Benutzer ansonsten ganz schnell nicht mehr weiß, wo oben und unten ist...

[edit]
Achso, jetzt raff ich das, du willst einfach nur das Koordinatensystem "klassisch herum" zeichnen, und ärgerst dich, dass sich die Achsenbeschriftungen auch umdrehen... Nja, das ist ärgerlich. Ich denke nicht, dass du es dir wesentlich einfacher machen kannst, als den Punkt, wo der text sein soll, vorher mit der aktuell gesetzten AffinenTransformation in Bildschirmkoordinaten zu transformieren, und anschließend mit der Identitäts-Transformation normal den text an dieser Stelle hinzeichnen.
 

Antimon

Mitglied
Ähm jo genau, sorry wenn das ein wenig diffus erklärt war von mir ;)

Okay... das gefällt mir irgendwie gar nicht, denn die Problematik wird dadurch nicht einfacher.

Aber gut, was wäre dann die angenehmere Variante - ein Image im Speicher zu zeichen, dessen Höhe und Breite ich kenn und das ich dann einfach spiegle und an die Stelle zeichne wo es hinkommen soll? Oder den ursprünglichen Graphics-Kontext zu "Identitäts-transformieren"?

Die letztere Variante, also mit den ursprünglichen Bildschirm-Koordinaten zu arbeiten gefällt mir aus mehreren Gründen nicht:
- Alle anderen Zeichenoperationen geschehen auf dem neuen, internen Koordinatensystem (Zoom, Verschiebung und so läuft dann alles nur über die Trafo)
- Wenn ich den Text zeichnen möchte, muss ich die Texthöhe kennen bzw. vorher umständlich berechnen, damit der Text an die richtige Position kommt
- Wenn ich auf Bildschirmkoordinaten umrechnen möchte, muss ich immer die Höhe des Panels, Position des Ursprungs etc. kennen und umrechnen

Ich weiss schon, ich habe mir keinen Gefallen getan indem ich gesagt habe, ich verwende das übliche Koordinatensystem-Schema - aber im Nachhinein ist man immer schlauer und für den Benutzer ist die Geschichte doch intuitiver...
 

0x7F800000

Top Contributor
- Alle anderen Zeichenoperationen geschehen auf dem neuen, internen Koordinatensystem (Zoom, Verschiebung und so läuft dann alles nur über die Trafo)
Da soll aber eben nicht alles durch diese zoom-verschiebungs-trafo (ich nenn die mal T. T transformiert also die "wahren Koordinaten" in "Bildschirmkoordinaten".)
Der Text soll ja immer eine Konstante Größe behalten und nicht mitskaliert werden, richtig? Also musst du die Form des Textes an der Transformation T vorbeischmuggeln, während seine Position aber stets transformiert wird, sodass er im endgültigen Bild an der richtigen Stelle landet.

Dieses "teilweise Vorbeischmuggeln" realisierst du eben wie folgt:
[highlight=Java]
String text="blahblahblah";
Point2D.Double realTextPosition=new Point2D.Double(x,y);

AffineTransform T=g.getTransform(); // T wird rausgenommen
g.setTransform(new AffineTransform()); // stattdessen wird Trafo eingesetzt, die gar nichts tut
Point2D.Double screenTextPosition;
T.transform(realTextPosition,screenTextPosition); //position des Textes wird transformiert, seine Form aber nicht!
g.drawString(text, screenTextPosition.x , screenTextPosition.x); //zeichnen
g.setTransform(T); //transform zurücksetzen
[/highlight]
Klarer geworden, was ich meine? [der code oben ist natürlich als "pseudocode" zu verstehen, da sollten wenigstens ein paar float-casts noch hin]
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
E relevanter bereich einer isometrischen karte zeichnen (AffineTransform) Spiele- und Multimedia-Programmierung 0
SaftigMelo Kreissegment zeichnen Spiele- und Multimedia-Programmierung 2
E Buttons neu zeichnen im GridLayout Spiele- und Multimedia-Programmierung 2
A Zeichnen außerhalb der paint-Methode Spiele- und Multimedia-Programmierung 6
E Isometrische Tiles mit unterschiedlicher Größe an korrekter Position zeichnen Spiele- und Multimedia-Programmierung 1
Androbin Mein Spiel will sich nicht zeichnen lassen !!! Spiele- und Multimedia-Programmierung 7
J Int Wert auf JFrame zeichnen Spiele- und Multimedia-Programmierung 3
H [ANIMATION] Hintergrundbild nur einmal zeichnen Spiele- und Multimedia-Programmierung 3
R [lwjgl] Cursor -> versetzt Zeichnen / Bild ist umgedreht Spiele- und Multimedia-Programmierung 2
M Methoden eine Map zu zeichnen Spiele- und Multimedia-Programmierung 5
aze Nicht rechteckiges Bild zeichnen Spiele- und Multimedia-Programmierung 5
F nur Ausschnitt eines Image zeichnen Spiele- und Multimedia-Programmierung 9
T 3D Graphen Zeichnen Spiele- und Multimedia-Programmierung 19
F Kurven zeichnen Spiele- und Multimedia-Programmierung 2
E Keine Werte zum Zeichnen werden Übergeben Spiele- und Multimedia-Programmierung 3
A Halbkreise zeichnen lassen? Spiele- und Multimedia-Programmierung 2
F Lineal mit Zahlen zeichnen Spiele- und Multimedia-Programmierung 7
N Linie mit Rand zeichnen Spiele- und Multimedia-Programmierung 10
A Mehrere geometrische Objekte in JPanel zeichnen Spiele- und Multimedia-Programmierung 4
data89 Koordinaten in Koordinatensystem zeichnen Spiele- und Multimedia-Programmierung 11
M Binärbaum ohne Überlappung zeichnen Spiele- und Multimedia-Programmierung 3
H Decke zeichnen mit Hilfe eines Polygons Spiele- und Multimedia-Programmierung 2
B 1)JButtons zeichnen 2)Kolisionsabfrage von zwei Objekten Spiele- und Multimedia-Programmierung 9
G Linie im Applet zeichnen Spiele- und Multimedia-Programmierung 5
G Schüsse zeichnen, Fehler? Spiele- und Multimedia-Programmierung 3
S Dreieck zeichnen Spiele- und Multimedia-Programmierung 9
G Überlagern von Strings beim zeichnen verhindern Spiele- und Multimedia-Programmierung 3
C Objekt bei Buttonklick zeichnen Spiele- und Multimedia-Programmierung 16
G Geschwungene Klammer zeichnen Spiele- und Multimedia-Programmierung 5
F Neu zeichnen verhindern Spiele- und Multimedia-Programmierung 25
J Zeichnen in BufferedImage und dieses in Datei speichern Spiele- und Multimedia-Programmierung 2
O Funktion zeichnen Spiele- und Multimedia-Programmierung 11
A Lissajous Figuren zeichnen Spiele- und Multimedia-Programmierung 1
G Maus springt --> Free-Hand-Zeichnen Spiele- und Multimedia-Programmierung 2
L Schüsse zeichnen Spiele- und Multimedia-Programmierung 13
M Eigene Strings zeichnen Spiele- und Multimedia-Programmierung 4
T Blitz berechnen und zeichnen Spiele- und Multimedia-Programmierung 13
M auswahlkreis zeichnen (schräg) Spiele- und Multimedia-Programmierung 4
N Logik: Grenz-/Frontlinie zeichnen Spiele- und Multimedia-Programmierung 4
M Grafikprogramm, zeichnen mit Maus Spiele- und Multimedia-Programmierung 7
G Problem beim Zeichnen von LineArrays Spiele- und Multimedia-Programmierung 9
P linie in bild zeichnen Spiele- und Multimedia-Programmierung 2
G Auf 3D Box zeichnen Spiele- und Multimedia-Programmierung 4
K mit Canvas übereinander zeichnen Spiele- und Multimedia-Programmierung 4
G 3D Raum zeichnen Spiele- und Multimedia-Programmierung 7
H Kreis zeichnen mittels Schleife & drawLine Spiele- und Multimedia-Programmierung 4
B Probleme beim zeichnen Spiele- und Multimedia-Programmierung 15
N Bild zu zeichnen (drawImage) klappt nur manchmal?? Spiele- und Multimedia-Programmierung 8
T Effizient zeichnen Spiele- und Multimedia-Programmierung 12
H mit Java2D Markierung über JTable zeichnen und diese bewegen Spiele- und Multimedia-Programmierung 2
C Graphische Benutzerschnittstelle, Problem beim Zeichnen Spiele- und Multimedia-Programmierung 4
J schnellste alternative um in java zu "zeichnen" Spiele- und Multimedia-Programmierung 17
conan2 Objekte in richtiger Z-Reihenfolge zeichnen Spiele- und Multimedia-Programmierung 2
G Punkte in Java3D zeichnen Spiele- und Multimedia-Programmierung 2
S Pixel zeichnen Spiele- und Multimedia-Programmierung 3
S Bild in Speicherbild zeichnen = Nichts? Spiele- und Multimedia-Programmierung 3
G Farbig zeichnen ohne java.awt.Color? Spiele- und Multimedia-Programmierung 5
S Wie kann ich das Zeichnen der Grafik feiner machen? Spiele- und Multimedia-Programmierung 9
M Wie kann man Kreisringe zeichnen ? Spiele- und Multimedia-Programmierung 12
C Graphics 2D Zeichnen Spiele- und Multimedia-Programmierung 4
R Kreuz lässt sich nicht zeichnen Spiele- und Multimedia-Programmierung 11
F einzelne Polygone(Graphics) schneller als and. Fig. zeichnen Spiele- und Multimedia-Programmierung 3
K Kugeln und Zylinder zeichnen Spiele- und Multimedia-Programmierung 4
L ein Rechteck zeichnen Spiele- und Multimedia-Programmierung 6

Ähnliche Java Themen

Neue Themen


Oben