二次ベジェ曲線による円の近似

Top »

原点を中心とし半径 r の円を二次ベジェ曲線で近似してみる。

始点を分割点上に置き、隣接始点における接線の交点を制御点とするとよい。

円周分割数をnとする。

ActionScript

function drawCircle(cx, cy, r) {
	var n = 8;
	var r2 = r/Math.cos(Math.PI/n);
	this.clear();
	this.lineStyle(2, 0x000000);
	this.moveTo(r+cx, cy);
	for (var i = 2; i<=n*2; i += 2) {
		this.curveTo(
			Math.cos((i-1)*Math.PI/n)*r2+cx, Math.sin((i-1)*Math.PI/n)*r2+cy, 
			Math.cos(i*Math.PI/n)*r+cx, Math.sin(i*Math.PI/n)*r+cy
		);
	}
}

8分割くらいで真円とほとんど区別が付かなくなる。

n最大半径誤差面積誤差
3+25.000%+24.049%
4+6.0660%+6.1033%
5+2.2542%+2.3161%
6+1.0363%+1.0770%
7+0.5443%+0.5695%
8+0.3136%+0.3296%
9+0.1935%+0.2040%
10+0.1259%+0.1330%
11+0.0855%+0.0905%
12+0.0601%+0.0636%
13+0.0435%+0.0461%
14+0.0322%+0.0342%
15+0.0244%+0.0259%
16+0.0188%+0.0200%
17+0.0147%+0.0156%
18+0.0117%+0.0124%
19+0.0094%+0.0100%
20+0.0077%+0.0081%
21+0.0063%+0.0067%
22+0.0052%+0.0055%
23+0.0044%+0.0046%
24+0.0037%+0.0039%

楕円

楕円はx軸・y軸を定数倍する。傾きが欲しければ回転行列をかける。

//楕円
function drawEllipse(cx, cy, rx, ry) {
	var n = 8;
	var r2 = 1/Math.cos(Math.PI/n);
	this.clear();
	this.lineStyle(2, 0x000000);
	this.moveTo(r+cx, cy);
	for (var i = 2; i<=n*2; i += 2) {
		this.curveTo(
			Math.cos((i-1)*Math.PI/n)*r2*rx+cx, Math.sin((i-1)*Math.PI/n)*r2*ry+cy, 
			Math.cos(i*Math.PI/n)*rx+cx, Math.sin(i*Math.PI/n)*ry+cy
		);
	}
}

円弧

中心角が最大(=円)のとき何分割するか決める(8分割)。すると分割1辺あたり中心角は最大 2π/n まで許されるから、中心角がaのときの分割数は ceil(a/(2π/n)) 。

function drawArc(cx, cy, r, a0, a1) {
	var fullArcang = ((a1-a0)/2+Math.PI)%Math.PI;
	if (isNaN(fullArcang)) return;
	var n = 8
	var n2 = Math.ceil(fullArcang/(Math.PI/n));
	var r2 = r/Math.cos(fullArcang/n2);
	this.clear();
	this.lineStyle(2, 0x000000);
	this.moveTo(Math.cos(a0)*r+cx, Math.sin(a0)*r+cy);
	for (var i = 2; i<=n2*2; i += 2) {
		this.curveTo(
			Math.cos((i-1)*fullArcang/n2+a0)*r2+cx, Math.sin((i-1)*fullArcang/n2+a0)*r2+cy, 
			Math.cos(i*fullArcang/n2+a0)*r+cx, Math.sin(i*fullArcang/n2+a0)*r+cy
		);
	}
}
inserted by FC2 system