2D-Grafik Linie hat Löcher

jappel

Mitglied
Hi das ist mein erster Post hier.. ich arbeite seit 2 Tagen daran und komme nicht weiter.

Ich bin dabei ein 2-dim lineares dgl system grafisch darzustellen. Das dgl system wird numerisch / inkrementweise berechnet und als 2 linien dargestellt. Bei einer sehr grossen steigung werden nicht alle Punkte dargestellt bzw einige ausgelassen.. Die Linie wird mit "Line2D.Double" dargestellt und das Applet ist runnable d.h. bei jedem durchlauf wird ein inkrement berechnet und als fortlaufende linie dargstellt. gesteuert wird das mit thread.sleep..

ich freue mich über jeden Hinweis.

gute nacht
 
Hi, versuch mal Antialiasing zu aktivieren


Java:
public void paintComponent(Graphics gr) {
    Graphics2D gr2d = (Graphics2D)gr;
    //...

    gr2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
      RenderingHints.VALUE_ANTIALIAS_ON);
}
 
Zuletzt bearbeitet:
Beschreib' mal genauer. Wie wird der Inkrement zur Linie hinzugefügt, und wie wird die Linie gezeichnet? Das 'sleep' steht hoffentlich nicht in der paint-Methode... und... wenn du irgendwo ein "getGraphics" stehen hast, liegt's im Zeifelsfall DAran 😉
 
Danke für die "Renderinghints" - hat es vielleicht etwas besser gemacht aber das Problem bleibt..

Hier ist der Codeaufbau:

Java:
public class Test extends JApplet implements Runnable, ChangeListener{
	

.....
     
// Hier werden dem drawing_panel werte übergeben   
   
     public void run() {
         while (true){
        	 eulers=euler(lasteulers,n);
        	 drawing_panel.setValues(n*h,n*(+1)*h,lasteulers,eulers); 
        	 lasteulers=eulers;
        	 n=n+1;
             try {
                 Thread.sleep((long)1/100);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
     }

}

//und hier ist das JPanel

public class DrawingPanel extends JPanel {

	boolean clrPanel=true;

	double xend, xstart;
	
	double[] lastEuler=new double[2];
	double[] newEuler=new double[2];
	


   DrawingPanel () {

       setBackground (Color.WHITE);
  
   } 
   
   public void update(Graphics g){
	   
	   paintComponent(g);
	   
   }
   
   

   public void setValues(double x0, double x1, double[] lastE, double[] newE ){
	   xstart=x0;
	   xend=x1;
	   lastEuler=lastE;
	   newEuler=newE;
	   
	   repaint();

   
   }
  
   

   public void paintComponent(Graphics g)   {
    // Paint background
    

   // Set current drawing color
  
    Graphics2D g2 = (Graphics2D) g;
    
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
    	      RenderingHints.VALUE_ANTIALIAS_ON);

    g2.setStroke(new BasicStroke(2));
    

   
   
   





    g2.setColor(Color.blue);
    g2.draw(new Line2D.Double(xstart, Math.atan(-lastEuler[0])*getHeight()/4,xend,  Math.atan(-newEuler[0])*getHeight()/4));       
    g2.setColor(Color.red);
    g2.draw(new Line2D.Double(xstart, Math.atan(-lastEuler[1])*getHeight()/4,xend,  Math.atan(-newEuler[1])*getHeight()/4));
    

   
   	}
   }
 
Ja, der Zeichenablauf stimmt so nicht ganz. (BTW: (long)1/100 ist 0, ganzzahlige division und so...)

Eigentlich müßte es
Code:
public void paintComponent(Graphics g)   {
    [b]super.paintComponent(g);[/b]
heißen, und dann würde er immer nur das letzte Stück anzeigen. In der paintComponent muss IMMER ALLES gezeichnet werden. Dass es im Moment "teilweise" funktioniert ist eher ein zufälliges Artefakt.

Aber sooo viel muß man da vermutlich gar nicht ändern. Wenn in dem DrawingPanel ein Linienzug gezeichnet werden soll, könnte man dort einen
private Path2D.Double path = new Path2D.Double();
reinlegen. Den kann man mit path.moveTo(x,y) an eine Bestimmte Starposition setzen, und mit path.lineTo(x,y) dann Liniensegmente anhängen, vom letzten Endpunkt ausgehend (die lineTo würdest du dann in deiner "setValues"-Methode aufrufen).

In der paintComponent würde dann nur stehen
g.draw(path);

Natürlich sollte man das ganze verallgemeinern: Man sollte dort eine List<Path2D.Double> reinlegen (die bei dir im Moment 2 Elemente enthalten würde), und die setValues würde dann eher
public void appendPointToPath(int pathIndex, double x, double y)
oder so heißen, damit man "beliebig viele" Paths damit zeichnen kann (die Zahl '2' existiert nicht). Aber das liegt dann ganz bei dir.
 
Danke - das hört sich vernünftig an. Ich werde das mal so versuchen. Allerdings bin ich nicht sehr zuversichtlich, da ich in einem vorigen Anlauf statt des DrawingPanels einen Canvas benutzt hatte und da hatte ich die paint() methode benutzt und das gleiche problem gehabt (bei der paint(g) methode stellt sich das problem mit "super.paint.." garnicht oder?). Trotzdem setze ich deinen vorschlag mal um.. danke und vg
 
Doch, sicher, auch bei Canvas sollte man in paint erst super.paint aufrufen (auch wenn sie AFAIK nichts macht). Aber Canvas ist AWT, das sollte man in Swing nicht verwenden. Unabhängig davon: Das hat auf das Problem an sich keinen direkten Einfluß...
 
Hi ich habe deinen vorschlag so umgesetzt wie ich ihn verstanden habe und kriege jetzt einen outofbounds error..

was ich gemacht ist: in Test.java die run() methode leicht angepasst:

Java:
public void run() {
         while (true){
             drawing_panel.setValues((n+1)*h,euler(lasteulers,n));
             lasteulers=eulers;
             n=n+1;
             try {
                 Thread.sleep((long)1/100);
             } catch (InterruptedException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
         }
     }

und die drawing_panel klasse sieht jetzt so aus:

Java:
public class DrawingPanel extends JPanel {

    double xend, xstart;
   
    double[] lastEuler=new double[2];
    double[] newEuler=new double[2];
    private Path2D.Double path = new Path2D.Double(Path2D.WIND_EVEN_ODD,5000);
   


   DrawingPanel () {

       setBackground (Color.WHITE);
       path.moveTo(1,1);
   }
  
  
   public void setValues(double x1, double[] newE ){
    
       path.lineTo(x1,newE[0]);
       repaint();

   }
 
  

   public void paintComponent(Graphics g)   {

	super.paintComponent(g);
 
    Graphics2D g2 = (Graphics2D) g;

      g2.draw(path);

       }
   }

und kriege den folgenden Fehler:


Exception in thread "AWT-EventQueue-1" java.lang.ArrayIndexOutOfBoundsException: 10000
at java.awt.geom.Path2D$Double$CopyIterator.currentSegment(Path2D.java:1653)
at sun.java2d.pisces.PiscesRenderingEngine$NormalizingPathIterator.currentSegment(PiscesRenderingEngine.java:393)
at sun.java2d.pipe.RenderingEngine.feedConsumer(RenderingEngine.java:282)
at sun.java2d.pisces.PiscesRenderingEngine.pathTo(PiscesRenderingEngine.java:474)
at sun.java2d.pisces.PiscesRenderingEngine.strokeTo(PiscesRenderingEngine.java:353)
at sun.java2d.pisces.PiscesRenderingEngine.strokeTo(PiscesRenderingEngine.java:164)
at sun.java2d.pisces.PiscesRenderingEngine.getAATileGenerator(PiscesRenderingEngine.java:552)
at sun.java2d.pipe.AAShapePipe.renderPath(AAShapePipe.java:93)
at sun.java2d.pipe.AAShapePipe.draw(AAShapePipe.java:61)
at sun.java2d.pipe.ValidatePipe.draw(ValidatePipe.java:154)
at sun.java2d.SunGraphics2D.draw(SunGraphics2D.java:2392)
at DrawingPanel.paintComponent(DrawingPanel.java:65)

wobei at DrawingPanel.paintComponent(DrawingPanel.java:65) gerade der g2.draw(path) Befehl ist..

woran liegt das?? danke und vg
 
Ah, ja, sorry: Das hinzufügen macht ja ein eigener thread. Damit kann es passieren, dass ein Punkt hinzugefügt wird während der Pfad gezeichnet wird. Das muss man vermeiden. Da gibt's zwei einfache Möglichkeiten (und vermutlich noch einige "geschicktere" aber vielleicht auch kompliziertere) : Entweder, man legt das addValue immer mit SwingUtilities auf den EDT, oder man synchronisiert auf den Path. Letzteres ist schon sehr pragmatisch, könnte hier aber OK sein:
Code:
synchronized (path)
{
   path.lineTo(x1,newE[0]);
}

und

synchronized (path)
{
   g2.draw(path);
}
 
Vielen Dank Marco!!! Eine Linie wird schon mal fehlerfrei - lückenlos - dargestellt! Jetzt muss ich nur noch die zweite Linie mit der Liste hinbekommen..
 

Zurück
Oben