how to use clip to reduce paint time?

走远了吗. 提交于 2020-01-03 21:02:58

问题


i am trying to use clip to reduce the cpu load.

but the clip leaves some garbage on the screen that i can not seem to get rid of. also, turning clipping on and off seems to have no effect on the cpu load.

in either case. most of the time seems to be spent in the repaint manager and paint buffered image.

import static java.lang.Math.*;
import static java.awt.Color.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
import javax.swing.*;
class Piece {
    protected Piece(int piece,int pieces,int radius) {
        this.piece=piece;
        this.start=piece*2*PI/pieces;
        this.end=(piece+1)*2*PI/pieces;
        points=new ArrayList<Point>((int)ceil(4*PI*radius*radius/pieces));
    }
    public double start() {
        return start;
    }
    public double end() {
        return end;
    }
    public int piece() {
        return piece;
    }
    public static double angleToPiece(int piece,int pieces) {
        return piece*2*PI/pieces;
    }
    public String toString() {
        return piece+" "+start+" "+end+" "+start*180/PI;
    }
    protected final double start;
    protected final double end;
    final int piece;
    public final ArrayList<Point> points;
}
class P extends Piece {
    P(int piece,int pieces,int radius) {
        super(piece,pieces,radius);
        shape=new Arc2D.Double(0,0,2*radius,2*radius,toDegrees(start),toDegrees(end-start),Arc2D.PIE);
        shapeAndPrevious=new Arc2D.Double(0-extra,0-extra,2*radius+extra,2*radius+extra,toDegrees(start-2*PI/pieces)-extrad,toDegrees(2*(end-start))+2*extrad,Arc2D.PIE);
    }
    final Shape shape,shapeAndPrevious;
    static final int extra=0;
    static final int extrad=0;
}
class Y extends JPanel {
    Y(int radius,int nPieces,long period) {
        this.radius=radius;
        this.nPieces=nPieces;
        this.period=period;
        d=new Dimension(2*radius,2*radius);
        lhsOrigin=new Point(radius,radius);
        // setOpaque(false);
    }
    private void init() {
        pieces=new P[nPieces];
        for(int i=0;i<nPieces;i++)
            pieces[i]=new P(i,nPieces,radius);
        while(gc==null)
            Thread.yield(); // wait for gui to be constructed
        bi=gc.createCompatibleImage(d.width,d.height);
        stpe.scheduleAtFixedRate(new Runnable() {
            @Override public void run() {
                dtrt();
            }
        },0,1,TimeUnit.MILLISECONDS);
    }
    private int dt() {
        return (int)(System.currentTimeMillis()-t0);
    }
    private long dtNanos() {
        return System.nanoTime()-t0Nanos;
    }
    private double dtMillis() {
        return dtNanos()/1000000.;
    }
    private void paintRadialLine(Graphics2D g) {
        g.setColor(green);
        if(line2d!=null)
            if(paintRadialLine)
                g.draw(line2d);
    }
    private void paintPieceShape(Graphics g,int index) {
        g.setColor(red);
        if(paintPieceShape) {
            ((Graphics2D)g).draw(pieces[index].shape);
            g.setColor(yellow);
            //((Graphics2D)g).fill(pieces[index].shape);
        }
    }
    @Override public void paintComponent(Graphics g) {
        // super.paintComponent(g);
        Shape s=g.getClip();
        if(clip!=null) {
            AlphaComposite ac=AlphaComposite.getInstance(AlphaComposite.SRC_OVER,.75f);
            ((Graphics2D)g).setComposite(ac);
            ((Graphics2D)g).clip(clip);
        }
        paintBufferedImage(g);
        Color old=g.getColor();
        paintPieceShape(g,piece);
        paintRadialLine(((Graphics2D)g));
        g.setColor(old);
        g.setColor(Color.white);
        g.drawLine(radius,0,radius,2*radius);
        g.drawLine(0,radius,2*radius,radius);
        if(clip!=null)
            ((Graphics2D)g).setClip(s);
    }
    private void paintBufferedImage(Graphics g) {
        if(bi!=null)
            g.drawImage(bi,0,0,null);
    }
    @Override public Dimension getPreferredSize() {
        return new Dimension(d);
    }
    private void dtrt() {
        piece=(int)(dtNanos()%period*nPieces/period);
        if(!(0<=piece&&piece<nPieces)) {
            System.out.println("!(0<=piece&&piece<nPieces)");
            throw new RuntimeException("!(0<=piece&&piece<nPieces)");
        }
        long dtNanos=dtNanos();
        if(piece!=previous) {
            if(dtNanos()<=period)
                log.info("piece="+piece);
            log.fine("piece "+piece+" "+dtMillis()+" "+round(dtMillis())+" "+(dt()-dtMillis())+" "+dtNanos()%(period/nPieces)+" "+period/nPieces);
            if(useClip)
                clip=piece==0?null:pieces[piece].shapeAndPrevious;
            // repaint();
            previous=piece;
        }
        double angle=2*PI*((dtNanos()%period)/(double)period);
        Point2D.Double pd=new Point2D.Double((double)radius*cos(angle),radius*sin(angle));
        int x=(int)rint(pd.x);
        int y=(int)rint(pd.y);
        Point p=new Point(x+radius,radius-y);
        line2d=new Line2D.Double(lhsOrigin,p);
        if(false&&useClip&&round(dtNanos()%(period/nPieces))!=0)
            clip=angle==0?null:line2d;
        if(paintImmediately)
            paintImmediately(0,0,2*radius,2*radius);
        else repaint();
    }
    private void createAndShowGUI() {
        System.out.println("start constructing gui");
        setSize(d);
        setPreferredSize(d);
        Frame f=new Frame("X");
        f.setUndecorated(true);
        f.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
        f.add("Center",this);
        gc=getGraphicsConfiguration();
        f.pack();
        if(System.getProperty("user.name").equals("ray")) {
            Rectangle rectangle=f.getBounds();
            rectangle.x+=-700;
            rectangle.y+=1080;
            f.setBounds(rectangle);
        }
        f.setVisible(true);
        System.out.println("end constructing gui");
    }
    public static void main(String[] args) throws InvocationTargetException,InterruptedException {
        RepaintManager rm;
        Y x0;
        if(false)
            x0=new Y(512,400,2000*1000000l); // real app
        else x0=new Y(512,16,10000*1000000l); // easier to see
        final Y x=x0;
        x.log=Logger.getLogger("");
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                x.createAndShowGUI();
            }
        });
        x.init();
    }
    private GraphicsConfiguration gc;
    private BufferedImage bi;
    private P[] pieces;
    private int previous,piece,n;
    private final long t0=System.currentTimeMillis(),t0Nanos=System.nanoTime();
    private final int radius,nPieces;
    private final long period;
    private final Dimension d;
    private final Point lhsOrigin;
    private Shape clip;
    private boolean useClip=true;
    private boolean paintRadialLine=true;
    private boolean paintPieceShape=true;
    private boolean paintImmediately=false; 
    private final ScheduledThreadPoolExecutor stpe=new ScheduledThreadPoolExecutor(2);
    private Line2D line2d;
    private Logger log;
}

thanks


回答1:


The problem would appear to be the P.shapeAndPrevious which doesn't extend far enough. Adding to it's size seems to make the extra stuff disappear.

class P extends Piece
{
    P(int piece, int pieces, int radius)
    {
        super(piece, pieces, radius);
        shape = new Arc2D.Double(0, 0, 2 * radius, 2 * radius,
            toDegrees(start), toDegrees(end - start), Arc2D.PIE);       
        shapeAndPrevious = new Arc2D.Double(0 - extra,
            0 - extra,
            2 * radius + extra,
            2 * radius + extra,
            toDegrees((start - 2 * PI / pieces)) - extrad,
            toDegrees((2 * (end - start))) + 2 * extrad,
            Arc2D.PIE);
}

    ...

to

class P extends Piece
{
    P(int piece, int pieces, int radius)
    {
        super(piece, pieces, radius);
        shape = new Arc2D.Double(0, 0, 2 * radius, 2 * radius,
            toDegrees(start), toDegrees(end - start), Arc2D.PIE);           
        shapeAndPrevious = new Arc2D.Double(0 - extra,
            0 - extra,
            2 * radius + extra + 10, // add some extra
            2 * radius + extra + 10, // add some extra
            toDegrees((start - 2 * PI / pieces) - 1) - extrad,  // add some extra
            toDegrees((2 * (end - start)) + 1) + 2 * extrad,  // add some extra
            Arc2D.PIE);
}

UPDATE

Actually you seem to have already realised this problem as you've got variables in there to do what I hardcoded. So the whole P class becomes

class P extends Piece
{
    P(int piece, int pieces, int radius)
    {
        super(piece, pieces, radius);
        shape = new Arc2D.Double(0, 0, 2 * radius, 2 * radius,
                toDegrees(start), toDegrees(end - start), Arc2D.PIE);
        shapeAndPrevious = new Arc2D.Double(0 - extra,
                0 - extra,
                2 * radius + extra,
                2 * radius + extra,
                toDegrees((start - 2 * PI / pieces)) - extrad,
                toDegrees((2 * (end - start))) + 2 * extrad,
                Arc2D.PIE);
    }

    final Shape shape, shapeAndPrevious;
    static final int extra = 15; // add some extra
    static final int extrad = 25; // add some extra
}

this still seems to leave a problem on the lower right hand side quantile where the arc bit isn't being drawn, but that is certainly something to do with the clip.




回答2:


I'm having a dig around your code, but in the mean time...

First, I'd take a look at Painting in AWT and Swing

You'll find the the clipping rectangle is already set to the height/width of the component.

Graphics2D.clip(Shape) "Intersects the current Clip with the interior of the specified Shape and sets the Clip to the resulting intersection" - So I don't think it's doing what you want.

UPDATE

Sorry, I know this is not answering question, but my highlight some other areas of inefficiency

From "Paintng in AWT Swing"

Programs should not invoke this method (painImmediately) directly unless there is a valid need for real-time painting. This is because the asynchronous repaint() will cause multiple overlapping requests to be collapsed efficiently, whereas direct calls to paintImmediately() will not

Further, having spent time reading through the "Painting in AWT & Swing" doc, again, I think your misunderstanding the potentional benefits if the clip.

Basically, you seem to assume that using the clip will reduce the paint time because the areas outside the clip won't be rendered. While partially true (they won't appear on the screen), they are still be rendered to the Graphics context (& taking up time been rendered)

Instead, what you should be trying to do, is determining what you shouldn't paint based on the intersects of the clip shape, thus only painting those elements which fall within the clipping area of effect.

Components which render complex output should make smart use of the clip rectangle to narrow the drawing operations to those which intersect with the clip area.



来源:https://stackoverflow.com/questions/12139461/how-to-use-clip-to-reduce-paint-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!