实现布雷森汉姆的圆绘图算法
我写了一个Bresenham的圆画算法的实现。此算法利用圆的高度对称属性(它仅计算第一个八分位数的点,并利用对称性来绘制其他点)。因此,我期望它非常快。图形编程黑皮书,第35章的标题是“Bresenham是快的,快是好的”,虽然它是关于线条绘制算法的,但我可以合理地期望圆画算法也很快(因为原理是一样的)。
这是我的java,swing实现
public static void drawBresenhamsCircle(int r, double width, double height, Graphics g) {
int x,y,d;
y = r;
x = 0;
drawPoint(x, y, width, height,g);
d = (3-2*(int)r);
while (x <= y) {
if (d <= 0) {
d = d + (4*x + 6);
} else {
d = d + 4*(x-y) + 10;
y--;
}
x++;
drawPoint(x, y, width, height,g);
drawPoint(-x, y, width, height,g);
drawPoint(x, -y, width, height,g);
drawPoint(-x, -y, width, height,g);
drawPoint(y, x, width, height,g);
drawPoint(-y, x, width, height,g);
drawPoint(y, -x, width, height,g);
drawPoint(-y, -x, width, height,g);
}
}
此方法使用以下方法:drawPoint
public static void drawPoint(double x, double y,double width,double height, Graphics g) {
double nativeX = getNativeX(x, width);
double nativeY = getNativeY(y, height);
g.fillRect((int)nativeX, (int)nativeY, 1, 1);
}
getNativeX 和 getNativeY 这两种方法用于将坐标从源自屏幕左上角的系统切换到具有更经典轴方向的面板中心的系统。
public static double getNativeX(double newX, double width) {
return newX + (width/2);
}
public static double getNativeY(double newY, double height) {
return (height/2) - newY;
}
我还创建了一个基于三角公式(和)的圆图绘制算法的实现,以及使用对标准drawArc方法(在图形对象上可用)的调用的第三个实现。这些额外的实现的唯一目的是将Bresenham的算法与它们进行比较。x=R*Math.cos(angle)
y= R*Math.sin(angle)
然后,我创建了绘制一堆圆圈的方法,以便能够很好地衡量所花费的时间。这是我用布雷森汉姆算法绘制一堆圆圈的方法
public static void drawABunchOfBresenhamsCircles(int numOfCircles, double width, double height, Graphics g) {
double r = 5;
double step = (300.0-5.0)/numOfCircles;
for (int i = 1; i <= numOfCircles; i++) {
drawBresenhamsCircle((int)r, width, height, g);
r += step;
}
}
最后,我覆盖了我正在使用的JPanel的绘画方法,绘制一堆圆圈并测量每种类型绘制所需的时间。以下是绘画方法:
public void paint(Graphics g) {
Graphics2D g2D = (Graphics2D)g;
g2D.setColor(Color.RED);
long trigoStartTime = System.currentTimeMillis();
drawABunchOfTrigonometricalCircles(1000, this.getWidth(), this.getHeight(), g);
long trigoEndTime = System.currentTimeMillis();
long trigoDelta = trigoEndTime - trigoStartTime;
g2D.setColor(Color.BLUE);
long bresenHamsStartTime = System.currentTimeMillis();
drawABunchOfBresenhamsCircles(1000, this.getWidth(), this.getHeight(), g);
long bresenHamsEndTime = System.currentTimeMillis();
long bresenDelta = bresenHamsEndTime - bresenHamsStartTime;
g2D.setColor(Color.GREEN);
long standardStarTime = System.currentTimeMillis();
drawABunchOfStandardCircles(1000, this.getWidth(), this.getHeight(),g);
long standardEndTime = System.currentTimeMillis();
long standardDelta = standardEndTime - standardStarTime;
System.out.println("Trigo : " + trigoDelta + " milliseconds");
System.out.println("Bresenham :" + bresenDelta + " milliseconds");
System.out.println("Standard :" + standardDelta + " milliseconds");
}
这是它将生成的渲染类型(每种类型的绘制1000个圆圈)
不幸的是,我的布雷森汉姆的实施非常缓慢。我采取了许多比较措施,布雷森汉姆的实施不仅比三角函数方法慢,而且比三角函数方法慢。请看以下针对绘制的各种圆圈数的度量值。Graphics.drawArc
实施的哪个部分更耗时?我可以使用任何解决方法来改进它吗?感谢您的帮助。
[EDITION]:根据@higuaro的要求,这是我绘制圆的三角函数算法
public static void drawTrigonometricalCircle (double r, double width, double height, Graphics g) {
double x0 = 0;
double y0 = 0;
boolean isStart = true;
for (double angle = 0; angle <= 2*Math.PI; angle = angle + Math.PI/36) {
double x = r * Math.cos(angle);
double y = r * Math.sin(angle);
drawPoint((double)x, y, width, height, g);
if (!isStart) {
drawLine(x0, y0, x, y, width, height, g);
}
isStart = false;
x0 = x;
y0 = y;
}
}
以及用于绘制一堆三角圆的方法
public static void drawABunchOfTrigonometricalCircles(int numOfCircles, double width, double height, Graphics g) {
double r = 5;
double step = (300.0-5.0)/numOfCircles;
for (int i = 1; i <= numOfCircles; i++) {
drawTrigonometricalCircle(r, width, height, g);
r += step;
}
}