Darstellung einer Kurve im Koordinatensystem

  • Themenstarter Themenstarter HolGore
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
H

HolGore

Gast
Hi Leute,

Ich muss ein kleines Darstellungsprogramm für erfasste Messwerte schreiben. Die Messwerte stammen aus Aufnahmen mit mehreren Kanälen. Die einzelnen Dateien mit den Messwerten können aber recht groß(mehrere MB) sein, sodaß meine bisherige Implementierung da einfach zu lahm ist, sobald man etwas darin rumscrollen und zoomen will. Hier mal meine Klasse für das Panel, das das ganze darstellt und meine Bitte um Tips, wie ich die Performance verbessern könnte (ich schätze mal, man kann vielleicht die paintComponent-Methode etwas modifizieren?).

Code:
import java.awt.Dimension;
import java.awt.Graphics;

import javax.swing.JPanel;


public class DarstellungsPanel extends JPanel {
	
	private short[] Daten;
	private int MaxAuspraegung;
	private int StartXwertXachse;
	private int EndeXwertXachse;
	private int YwertXachse;
	private int XwertYachse;
	private int StartYwertYachse;
	private int EndeYwertYachse;
	private int XwertRandbereich;
	private int YwertRandbereich;
	private double ZoomFaktorX;
	private double ZoomFaktorY;
	private RandPanel randPanel;
	private ZeilenPanel zeilenPanel;
	private int Breite;
	private int Hoehe;
	
	public DarstellungsPanel(ZeilenPanel zp, short[] daten, int min, int max, RandPanel randpanel, int breite, int hoehe)
	{
		this.Daten = daten;
		this.setXwertRandbereich();
		this.setYwertRandbereich();
		this.setMaxAuspraegung(min, max);
		this.randPanel = randpanel;
		this.setZoomFaktorX((double)(breite-40)/(double)daten.length);
		this.setZoomFaktorY((double)(hoehe-40)/(double)this.MaxAuspraegung);
		this.randPanel.setZoomfaktorY(this.ZoomFaktorY);
		this.zeilenPanel = zp;
		init();
	}
		
	public void init ()
	{
		this.setZoomFaktorY(this.randPanel.getZoomfaktorY());
		this.Breite = (int)(this.ZoomFaktorX * this.Daten.length) + 45;
		this.Hoehe = (int)(this.MaxAuspraegung*2*this.ZoomFaktorY) + 45;
		this.setPreferredSize(new Dimension(this.Breite, this.Hoehe));
		this.setStartXwertXachse();
		this.setEndeXwertXachse();
		this.setYwertXachse();
		this.setXwertYachse();
		this.setStartYwertYachse();
		this.setEndeYwertYachse();
		this.repaint();
	}
	
	public void paintComponent (Graphics gra)
	{
		gra.clearRect(0, 0, this.getWidth(), this.getHeight());
		
		int sxx = this.StartXwertXachse;
		int exx = this.EndeXwertXachse;
		int yx = this.YwertXachse;
		int xy = this.XwertYachse;
		int syy = this.StartYwertYachse;
		int eyy = this.EndeYwertYachse;
		double zx = this.ZoomFaktorX;
		double zy = this.ZoomFaktorY;
		
		gra.setColor(java.awt.Color.BLACK);
		gra.drawLine(sxx, yx, exx, yx);
		gra.drawLine(xy, syy, xy, eyy);
		
		gra.setColor(java.awt.Color.RED);
 
		for(int i = 0; i < this.Daten.length - 1; i++){
			gra.setColor(java.awt.Color.RED);
			gra.drawLine((int)(sxx+i*zx), (int)(yx-this.Daten[i]*zy), (int)(sxx+(i+1)*zx), (int)(yx-this.Daten[i+1]*zy));
		}
	}
	
	private void setMaxAuspraegung(int min, int max)
	  {
		  if (min < 0)
		  {
			  min = min * (-1); 
		  }
		  if (max < 0)
		  {
			  max = max * (-1); 
		  }
		  if (min > max)
		  {
			  this.MaxAuspraegung = min;
		  }
		  else
		  {
			  this.MaxAuspraegung = max;
		  }
	  }
	
	private void setXwertRandbereich()
	{
		this.XwertRandbereich = 20;
	}
	
	private void setYwertRandbereich()
	{
		this.YwertRandbereich = 20;
	}
	
	private void setStartXwertXachse()
	  {
		  this.StartXwertXachse = this.XwertRandbereich;
	  }
	  
	  private void setEndeXwertXachse()
	  {
		  this.EndeXwertXachse = this.Breite - this.XwertRandbereich;
	  }
	  
	  private void setYwertXachse()
	  {
		  this.YwertXachse = this.Hoehe/2;
	  }
	  
	  private void setXwertYachse()
	  {
		  this.XwertYachse = this.StartXwertXachse;
	  }
	  
	  private void setStartYwertYachse()
	  {
		  this.StartYwertYachse = this.YwertRandbereich;
	  }
	  
	  private void setEndeYwertYachse()
	  {
		  this.EndeYwertYachse = this.Hoehe - this.YwertRandbereich;
	  }

	public double getZoomFaktorX() {
		return this.ZoomFaktorX;
	}

	public void setZoomFaktorX(double zoomFaktorX) {
		this.ZoomFaktorX = zoomFaktorX;
	}

	public double getZoomFaktorY() {
		return this.ZoomFaktorY;
	}

	public void setZoomFaktorY(double zoomFaktorY) {
		this.ZoomFaktorY = zoomFaktorY;
	}

	public int getMaxAuspraegung() {
		return this.MaxAuspraegung;
	}

	public void setMaxAuspraegung(int maxAuspraegung) {
		this.MaxAuspraegung = maxAuspraegung;
	}

	public void setBreite(int breite) {
		this.Breite = breite;
	}

	public void setHoehe(int hoehe) {
		this.Hoehe = hoehe;
	}

	public short[] getDaten() {
		return this.Daten;
	}

	public void setZeilenPanel(ZeilenPanel zeilenPanel) {
		this.zeilenPanel = zeilenPanel;
	}

	public ZeilenPanel getZeilenPanel() {
		return this.zeilenPanel;
	}
	
}
 
Hast du vorher den Profiler bemüht und bestätigt das die paintComponent das Problem verursacht?
Sind die Daten statisch, oder dynamisch?
Hast du eine Möglichkeit festzustellen welche Daten für den Bildschirmausschnitt relevant sind?
 
Wildcard hat gesagt.:
Hast du vorher den Profiler bemüht und bestätigt das die paintComponent das Problem verursacht?
Sind die Daten statisch, oder dynamisch?
Hast du eine Möglichkeit festzustellen welche Daten für den Bildschirmausschnitt relevant sind?

Sorry, aber was ist ein Profiler? Naja jedenfalls bin ich mir sicher, daß es an paintComponent liegt, da der Rest flüssig läuft, wenn ich paintComponent und repaint auskommentiere. Und die das Dateneinlesen und -verarbeiten geht immer recht fix, bzw. schnell genug. Außerdem tritt das Problem erst bei größeren Dateien auf. Die Daten sind statisch. Es handelt sich um fertige Dateien, die von einem Messgerät erzeugt wurden, in denen alle Daten für alle Kanäle stehen. Ein DartstellungsPanel stellt genau einen Kanal dar. Welche Daten für den Bildschirmausschnitt relevant sind, lässt sich feststellen.
 
Bei statischen Daten bietet es sich an in ein Bild zu zeichnen.
Das Bild dann auf den Screen zu rendern geht wesentlich schneller als die Linien einzeln zu zeichnen.
Am besten ein Compatible Image verwenden um die Hardwarebeschleunigung zu verwenden.
Sollte das nicht möglich sein, versuch deinem Graphics Objekt eine passende Clipping Area zuzuweisen und nur die benötigten Teile zu zeichnen. Hier muss getestet werden, ob der relevante Ausschnitt so viel kleiner ist, das sich die zusätzliche Überprüfung überhaupt lohnt.
 
Wildcard hat gesagt.:
Bei statischen Daten bietet es sich an in ein Bild zu zeichnen.
Das Bild dann auf den Screen zu rendern geht wesentlich schneller als die Linien einzeln zu zeichnen.
Am besten ein Compatible Image verwenden um die Hardwarebeschleunigung zu verwenden.
Sollte das nicht möglich sein, versuch deinem Graphics Objekt eine passende Clipping Area zuzuweisen und nur die benötigten Teile zu zeichnen. Hier muss getestet werden, ob der relevante Ausschnitt so viel kleiner ist, das sich die zusätzliche Überprüfung überhaupt lohnt.

Danke für die schnelle Hilfe. Ich habe zwar keine Ahnung, wie das funktioniert, aber ich werde mich mal schlau machen und durchkämpfen.
 
Wenn du nicht im voraus bestimmen kannst oder willst, welche Linien gezeichnet werden müssen, könntest du die Linien in einen GeneralPath legen, und DEN dann zeichnen. Da wird das clipping automatisch gemacht.
Code:
       GeneralPath generalPath = new GeneralPath(GeneralPath.WIND_NON_ZERO, anzahlLinien*2);
        for (alle linien [x0,y0]-[x1,y1])
        {
            generalPath.moveTo(x0, y0);
            generalPath.lineTo(x1, y1);
        }
        g.draw(generalPath);
Das ist von der Umsetzung her ziemlich trivial, kann aber schon einen deutlichen Vorteil bringen!
 
Hey Jungs Danke nochmal für die Hilfe. Hab aber inzwischen eine viel einfachere Lösung gefunden. Ich habe einfach drawPolyline anstatt drawLine verwendet. Hier mal meine neue paintComponent-Methode:

Code:
public void paintComponent (Graphics gra)
	{
		gra.clearRect(0, 0, this.getWidth(), this.getHeight());
		
		int sxx = this.StartXwertXachse;
		int exx = this.EndeXwertXachse;
		int yx = this.YwertXachse;
		int xy = this.XwertYachse;
		int syy = this.StartYwertYachse;
		int eyy = this.EndeYwertYachse;
		double zx = this.ZoomFaktorX;
		double zy = this.ZoomFaktorY;
		
		gra.setColor(java.awt.Color.BLACK);
		gra.drawLine(sxx, yx, exx, yx);
		gra.drawLine(xy, syy, xy, eyy);
		
		gra.setColor(java.awt.Color.RED);
		
		int[] xpoints = new int[this.Daten.length];
		int[] ypoints = new int[this.Daten.length];
		
		for(int i = 0; i < this.Daten.length - 1; i++)
		{
			xpoints[i] = (int)(sxx+i*zx);
			ypoints[i] = (int)(yx-this.Daten[i]*zy);
		}
		gra.drawPolyline(xpoints, ypoints, this.Daten.length-1);
	}
 
Wildcard hat gesagt.:
Können wir ja schlecht wissen das es eine Polyline ist :wink:

Ich dachte das wäre daraus ersichtlich gewesen, daß ich in der Schleife immer 2 Punkte durch eine Linie verbunden habe. Hätte ich wohl besser kommentieren sollen... 😳
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben