Как использовать клип, чтобы уменьшить время рисования?
Я пытаюсь использовать клип, чтобы уменьшить нагрузку на процессор.
но клип оставляет на экране мусор, от которого я не могу избавиться. Кроме того, включение и выключение отсечения не влияет на загрузку процессора.
в любом случае. кажется, что большую часть времени тратит в менеджере перерисовок и рисует буферизованное изображение.
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;
}
Спасибо
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
}
кажется, что это все еще оставляет проблему в нижнем правом углу, где дуга не рисуется, но это, безусловно, связано с клипом.
Я копаюсь вокруг твоего кода, но пока...
Сначала я бы взглянул на Живопись в AWT и Swing.
Вы обнаружите, что прямоугольник отсечения уже установлен на высоту / ширину компонента.
Graphics2D.clip(Shape)
"Пересекает текущий клип с внутренней частью указанной фигуры и устанавливает клип на результирующее пересечение" - так что я не думаю, что он делает то, что вы хотите.
ОБНОВИТЬ
Извините, я знаю, что это не ответ на вопрос, но я выделю некоторые другие области неэффективности
Из "Paintng in AWT Swing"
Программы не должны напрямую вызывать этот метод (painImmediately), если только нет реальной необходимости рисовать в реальном времени. Это связано с тем, что асинхронный repaint() приведет к эффективному сворачиванию нескольких перекрывающихся запросов, тогда как прямые вызовы paintImmediately() не будут
Кроме того, потратив время на чтение документа "Живопись в AWT & Swing", я снова думаю, что вы неправильно понимаете потенциальные преимущества клипа.
По сути, вы, кажется, предполагаете, что использование клипа сократит время рисования, поскольку области вне клипа не будут отображаться. Хотя частично верно (они не будут отображаться на экране), они все равно будут отображаться в Graphics
контекст (и отняв время)
Вместо этого, то, что вы должны пытаться сделать, это определить, что вы не должны рисовать, основываясь на пересечениях формы клипа, таким образом, рисуя только те элементы, которые попадают в область обрезки эффекта.
Компоненты, которые представляют сложный вывод, должны использовать прямоугольник клипа, чтобы сузить операции рисования до тех, которые пересекаются с областью клипа.