3

我正在尝试使用剪辑来减少 CPU 负载。

但剪辑在屏幕上留下了一些我似乎无法摆脱的垃圾。此外,打开和关闭剪辑似乎对 cpu 负载没有影响。

在任一情况下。大部分时间似乎都花在了重绘管理器和绘制缓冲图像上。

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;
}

谢谢

4

2 回答 2

2

问题似乎是P.shapeAndPrevious延伸得不够远。增加它的大小似乎会使多余的东西消失。

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);
}

    ...

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);
}

更新

实际上你似乎已经意识到了这个问题,因为你有变量来做我硬编码的事情。所以整个P班级变成了

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
}

这似乎仍然在未绘制弧位的右下角分位数上留下问题,但这肯定与剪辑有关。

于 2012-08-27T10:00:47.900 回答
1

我正在研究您的代码,但与此同时...

首先,我会看一下在 AWT 和 Swing 中的绘画

您会发现剪切矩形已设置为组件的高度/宽度。

Graphics2D.clip(Shape)“将当前剪辑与指定形状的内部相交并将剪辑设置为结果交集” - 所以我认为它没有做你想要的。

更新

抱歉,我知道这不是在回答问题,但我强调了其他一些效率低下的领域

来自“AWT Swing 中的绘画”

程序不应直接调用此方法(painImmediately),除非对实时绘画有有效的需求。这是因为异步 repaint() 会导致多个重叠请求被有效折叠,而直接调用 paintImmediately() 不会

此外,再次阅读“Painting in AWT & Swing”文档后,我认为您误解了剪辑的潜在好处。

基本上,您似乎认为使用剪辑会减少绘制时间,因为剪辑之外的区域不会被渲染。虽然部分正确(它们不会出现在屏幕上),但它们仍会被渲染到Graphics上下文中(并占用时间被渲染)

相反,您应该尝试做的是根据剪辑形状的相交确定不应该绘制的内容,因此只绘制那些落在效果剪辑区域内的元素。

渲染复杂输出的组件应该巧妙地使用剪辑矩形将绘图操作缩小到与剪辑区域相交的那些。

于 2012-08-27T09:59:11.423 回答