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

# はじめに
イラストレータなどでは、円や円弧を描くときにベジェ曲線による近似が行われている。
※CADなどでは、NURBSによる正確な円や円弧が使われる。

Processing標準の円弧描画命令を使っても描けるのだが、タートルグラフィックスのように使いたかったので、やってみた次第です。

# 環境
Processing 4

# ベジェ曲線による円弧近似の一般公式
ベジェ曲線の制御点を
```math
P_0, P_1, P_2, P_3
```
とし、
```math
P_0を始点、P_3を終点
```
とするとき、
```math
P_1=P_0+\alpha t_0
```
```math
P_2=P_3-\alpha t_1
```
```math
t_0,t_1は、それぞれ始点・終点での円弧の接線方向を正規化したベクトルで、
```
```math
t_0=(0,1)
```
は、明らか。
例えば、45度のとき
```math
t_1=(-\frac{\sqrt2}{2},\frac{\sqrt2}{2})
```
となる。αは
```math
\alpha=\frac{4}{3}\tan(\frac{\theta}{4})
```
で、定義され、
例えば、45度のとき
```math
\alpha=\frac{4}{3}\tan(\frac{\pi}{16})
```
となる。

この公式は、60度以下なら非常に精度が高く、90度でも実用的な精度がある。
90度を超えると、使い物にならない。

# 90度の円弧
```math
\alpha=\frac{4}{3}\tan(\frac{\theta}{4})=\frac{4}{3}\tan(\frac{\pi}{8})\approx 0.55228474983
```
```math
P_1=P_0+\alpha t_0=(1,0.55228474983)
```
```math
P_2=P_3-\alpha t_1=(0.55228474983,1)
```

```java
size(110,110);
noFill();
scale(100);
strokeWeight(0.01);

bezier(1, 0,
       1, 0.5523,
  0.5523, 1,
       0, 1);
stroke(255,0,0);
circle(0,0,2);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/3f677a77-f74f-48ba-a411-3b291c594588.png)

# 60度の円弧
```math
\alpha=\frac{4}{3}\tan(\frac{\theta}{4})=\frac{4}{3}\tan(\frac{\pi}{12})\approx 0.3572655899
```
```math
P_1=P_0+\alpha t_0=(1,0.3572655899)
```
```math
P_2=P_3-\alpha t_1=(0.5,\frac{\sqrt3}{2})-\alpha(-\frac{\sqrt3}{2},0.5)
```
```math
=(0.80940107675, 0.68739260883)
```

```java
size(110,110);
noFill();
scale(100);
strokeWeight(0.01);

bezier(1, 0,
       1, 0.3573,
  0.8094, 0.6874,
     0.5, 0.866);
stroke(255,0,0);
circle(0,0,2);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/4ea09afe-748f-4471-ab36-25d8b77699c8.png)


# 45度の円弧
```math
\alpha=\frac{4}{3}\tan(\frac{\theta}{4})=\frac{4}{3}\tan(\frac{\pi}{16})\approx 0.26521648984
```

```math
P_1=P_0+\alpha t_0=(1,0.26521648984)
```
```math
P_2=P_3-\alpha t_1=(\frac{\sqrt2}{2},\frac{\sqrt2}{2})-\alpha(-\frac{\sqrt2}{2},\frac{\sqrt2}{2})
```
```math
=(0.89464315963,0.51957040273)
```

```java
size(110,110);
noFill();
scale(100);
strokeWeight(0.01);

bezier(1, 0,
       1, 0.2652,
  0.8946, 0.5196,
  0.7071, 0.7071);
stroke(255,0,0);
circle(0,0,2);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/76829b9f-92c8-43f0-9cfd-d79a87b0a391.png)


# 30度の円弧

```math
\alpha=\frac{4}{3}\tan(\frac{\theta}{4})=\frac{4}{3}\tan(\frac{\pi}{24})\approx 0.17553666345
```
```math
P_1=P_0+\alpha t_0=(1,0.17553666345)
```
```math
P_2=P_3-\alpha t_1=(\frac{\sqrt3}{2}, 0.5)-\alpha(-0.5, \frac{\sqrt3}{2})
```
```math
=(0.9537937355, 0.34798079015)
```


```java
size(110,110);
noFill();
scale(100);
strokeWeight(0.01);

bezier(1, 0,
       1, 0.1755,
  0.9538, 0.3480,
  0.8660, 0.5);
stroke(255,0,0);
circle(0,0,2);
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/4f028d3c-d944-4a90-92f6-7828f37c3e59.png)


# SVGによる90度円弧の誤差比較
SVGフォーマットでテキストエディタでベタ書き。
100mm四方の領域を用意。（単位をミリにする）
1行目：赤：ベジェ曲線による近似円弧
2行目：緑：ベジェハンドルを半径*0.5で代用
3行目：青：円命令
4行目：黃：円弧命令
```xml
<svg width="100mm" height="100mm" viewBox="0 0 100 100">
  <path d="M 0,5 C 0,2.238575 2.238575,0 5,0" fill="none" stroke-width="0.02" stroke="red" />
  <path d="M 0,5 C 0,2.5      2.5,0      5,0" fill="none" stroke-width="0.02" stroke="lime" />
  <circle r="5" cx="5" cy="5"                 fill="none" stroke-width="0.02" stroke="blue" />
  <path d="M 0,5 A 5,5        0 0 1     5,0"  fill="none" stroke-width="0.02" stroke="yellow" />
</svg>
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510257/6e174b08-9894-4c83-b176-32286a4af772.png)



# メモ
見つけたのでメモ。
イラレの曲線で使われているらしい。
フリーハンド曲線のやつかな？まだ読み込めてない。
Siggraph2017で発表。

https://qiita.com/Rijicho_nl/items/05ee4c8d77e99e29daa5

著者のページに論文データと、発表スライドがある。

https://people.engr.tamu.edu/schaefer/research/index.html

論文への直リンク

https://people.engr.tamu.edu/schaefer/research/kcurves.pdf