Wednesday, July 13, 2005

Bézier curves

อ่านเจอเรื่องนี้ Bézier curves
It is attributed and named after a French engineer, Pierre Bézier, who used them for the body design of the Renault car in the 1970's. They have since obtained dominance in the typesetting industry and in particular with the Adobe Postscript and font products.


ก็เลยลอง implement ด้วย java ดู
/*
* DrawPanel.java
*
* Created on July 9, 2005, 9:12 AM
*
*/

package curve;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;

/**
*
* @author pphetra
*/
public class DrawPanel extends JPanel {
private static int LOOP_COUNT = 60;

protected void paintComponent(Graphics g) {
super.paintComponent(g);
ArrayList points = new ArrayList();
points.add(new Point2D.Double(0.0, 200.0));
points.add(new Point2D.Double(50.0, 50.0));
points.add(new Point2D.Double(100.0, 150.0));
points.add(new Point2D.Double(200.0, 0.0));

paintBazier(g, points, LOOP_COUNT);

paintControlPoints(g, points);

}

private void paintControlPoints(Graphics g, List points) {
g.setColor(Color.MAGENTA);
Point2D.Double oldp = null;
for (int i = 0; i < points.size(); i++) {
Point2D.Double p = (Point2D.Double) points.get(i);
if (oldp != null) {
g.drawLine((int) oldp.x, (int) oldp.y, (int) p.x, (int) p.y);
}
oldp = p;
}


}

private void paintBazier(Graphics g, List points, int loopCount) {
Point2D.Double oldp = null;

for (int i = 0; i < loopCount; i++) {
Point2D.Double p = bazier(points, points.size()-1, (double) i/ (doub
le) loopCount);
if (oldp == null) {
oldp = p;
}
g.drawLine((int) p.x, (int) p.y, (int) oldp.x, (int) oldp.y);
oldp = p;
}
Point2D.Double p = (Point2D.Double) points.get(points.size()-1);

g.drawLine((int) oldp.x, (int) oldp.y, (int) p.x, (int) p.y);
}

private Point2D.Double bazier(List points, int n, double mu) {

int k, kn, nn, nkn;
double blend, muk, munk;
Point2D.Double b = new Point2D.Double(0.0, 0.0);

muk = 1;
munk = java.lang.Math.pow(1-mu, n);

for (k = 0; k <= n; k++) {
nn = n;
kn = k;
nkn = n-k;
blend = muk * munk;
muk *= mu;
munk /= (1-mu);
while (nn >= 1) {
blend *= nn;
nn--;
if (kn > 1) {
blend /= (double) kn;
kn--;
}
if (nkn > 1) {
blend /= (double) nkn;
nkn--;
}

}
Point2D.Double p = (Point2D.Double) points.get(k);
b.x += (p.x * blend);
b.y += (p.y * blend);
}

return b;
}
}


ได้ผลลัพท์ดังนี้


ในโปรแกรม จะเห็นว่ามีค่า LOOP_COUNT อยู่ตัวหนึ่ง
ค่านี้ก็คือจำนวน line segment ที่ใช้ draw curve
ปัญหาก็คือ ควรใช้ค่าเท่าไรดี
น้อยไป ก็ไม่โค้ง
มากไป ก็เปลือง
ก็เลยมีบทความ Adaptive Subdivision of Bezier Curves

Related link from Roti

1 comment:

PPhetra said...

Bact' เขาแนะนำ site ที่ชื่อ Z.u.L.
ข้างในมี Bezier curves geometrydemo
ทำให้เข้าใจขึ้นเยอะเลย