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 に答える