Last active
December 17, 2015 05:38
-
-
Save ikekou/5559137 to your computer and use it in GitHub Desktop.
[Math][JavaScript][CoffeeScript] 3次ベジェ曲線を2次ベジェ曲線に変換する(近似するだけ、間違ってたり無駄のある可能性は十分にあり) 参考:http://www.noids.tv/2007/02/bspline_10fd.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
window.onlaod=()-> | |
a1x=100 | |
a1y=100 | |
c1x=200 | |
c1y=200 | |
c2x=300 | |
c2y=200 | |
a2x=400 | |
a2y=100 | |
result=[] | |
Vector2DUtil.cubicBezierToQuadraticBezier(a1x,a1y,c1x,c1y,c2x,c2y,a2x,a2y,10,result) | |
console.log(result) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Vector2DUtil | |
#3次ベジェ曲線を2次ベジェ曲線に変換する | |
#精度は中間点の距離で測る、precisionで設定 | |
#resultに結果が入るので空の配列渡す | |
#a1はアンカーポイント1 | |
#c1はアンカーポイント1から出るコントロールポイント | |
#c2はアンカーポイント2から出るコントロールポイント | |
#a2はアンカーポイント2 | |
@cubicBezierToQuadraticBezier:(a1x,a1y,c1x,c1y,c2x,c2y,a2x,a2y,precision,result)-> | |
#元の3次ベジェの中間点を求める | |
#http://nutsu.com/blog/2007/120500_as_cbezier_cut1.html | |
[p1x,p1y]=@getCubicBezierPoint(a1x,a1y,c1x,c1y,c2x,c2y,a2x,a2y,0.5) | |
#3次ベジェの2つのコントロールポイントの交点を求める | |
[p2x,p2y]=@getCorssPoint(a1x,a1y,c1x,c1y,c2x,c2y,a2x,a2y) | |
#2次ベジェの中間点を求める | |
#http://geom.web.fc2.com/geometry/bezier/quadratic.html | |
[p3x,p3y]=@getQuadraticBezierPoint(a1x,a1y,p2x,p2y,a2x,a2y,0.5) | |
#3次ベジェと2次ベジェの中間点の距離を求める | |
distance=@getDistance(p1x,p1y,p3x,p3y) | |
#中間点の距離が指定された値以下なら精度を満たしているので完了 | |
if distance<=precision | |
result.push [a1x,a1y,p2x,p2y,a2x,a2y] | |
#それ以外だと分割して再帰 | |
else | |
#3次ベジェを分割する | |
splited=@split(a1x,a1y,c1x,c1y,c2x,c2y,a2x,a2y,0.5) | |
#2つの3次ベジェを再帰的に計算 | |
@cubicBezierToQuadraticBezier(splited[0],splited[1],splited[2],splited[3],splited[4],splited[5],splited[6],splited[7],precision,result) | |
@cubicBezierToQuadraticBezier(splited[8],splited[9],splited[10],splited[11],splited[12],splited[13],splited[14],splited[15],precision,result) | |
#2次ベジェの中間点の座標を求める | |
#a1はアンカーポイント1 | |
#c1はアンカーポイント1から出るコントロールポイント | |
#c2はアンカーポイント2から出るコントロールポイント | |
#a2はアンカーポイント2 | |
#tは分割する割合、0~1の範囲 | |
@getQuadraticBezierPoint:(a1x,a1y,cx,cy,a2x,a2y,t)-> | |
tp = 1 - t | |
x = t*t*a2x + 2*t*tp*cx + tp*tp*a1x | |
y = t*t*a2y + 2*t*tp*cy + tp*tp*a1y | |
return [x,y] | |
#座標(p1x,p2y)と座標(p2x,p2y)を結ぶ線分をt:1-tで分割した座標を求める | |
@interpolate:(p1x,p1y,p2x,p2y,t)-> | |
return [ | |
p1x+(p2x-p1x)*t, | |
p1y+(p2y-p1y)*t | |
] | |
#3次ベジェをt:1-tで分割した点の座標を求める | |
#a1はアンカーポイント1 | |
#c1はアンカーポイント1から出るコントロールポイント | |
#c2はアンカーポイント2から出るコントロールポイント | |
#a2はアンカーポイント2 | |
#tは分割する割合、0~1の範囲 | |
@getCubicBezierPoint:(a1x,a1y,c1x,c1y,c2x,c2y,a2x,a2y,t)-> | |
tp = 1.0 - t; | |
return [ | |
a1x*tp*tp*tp + 3*c1x*t*tp*tp + 3*c2x*t*t*tp + a2x*t*t*t, | |
a1y*tp*tp*tp + 3*c1y*t*tp*tp + 3*c2y*t*t*tp + a2y*t*t*t | |
] | |
#(x1,y1),(x2,y2)を通る直線と(x3,y3),(x4,y4)を通る直線の交点の座標を求める | |
#http://mf-atelier.sakura.ne.jp/mf-atelier/modules/tips/index.php/program/algorithm/a1.html | |
@getCorssPoint:(x1,y1,x2,y2,x3,y3,x4,y4)-> | |
ksi = (y4 - y3) * (x4 - x1) - (x4 - x3) * (y4 - y1) | |
delta = (x2 - x1) * (y4 - y3) - (y2 - y1) * (x4 - x3) | |
ramda = ksi / delta | |
x = x1 + ramda * (x2 - x1) | |
y = y1 + ramda * (y2 - y1) | |
return [x,y] | |
#座標(p1x,p1y)と(p2x,p2y)の距離を求める | |
@getDistance:(p1x,p1y,p2x,p2y)-> | |
dx=p1x-p2x | |
dy=p1y-p2y | |
Math.sqrt(dx*dx+dy*dy) | |
#3次ベジェをt:1-tで分割した点の座標とコントロールポイントを得る | |
#a1はアンカーポイント1 | |
#c1はアンカーポイント1から出るコントロールポイント | |
#c2はアンカーポイント2から出るコントロールポイント | |
#a2はアンカーポイント2 | |
@split:(a1x,a1y,c1x,c1y,c2x,c2y,a2x,a2y,t)-> | |
[tpx,tpy] = @getCubicBezierPoint(a1x,a1y,c1x,c1y,c2x,c2y,a2x,a2y,t); | |
[mx,my] = @interpolate( c2x,c2y, c1x,c1y, t); | |
#コントロールポイント | |
[ac0x,ac0y] = @interpolate( c1x,c1y, a1x,a1y, t); | |
[ac1x,ac1y] = @interpolate( mx,my, ac0x,ac0y, t); | |
#コントロールポイント | |
[bc1x,bc1y] = @interpolate( a2x,a2y, c2x,c2y, t); | |
[bc0x,bc0y] = @interpolate( bc1x,bc1y, mx,my, t); | |
return [ | |
a1x,a1y,ac0x,ac0y,ac1x,ac1y,tpx,tpy | |
tpx,tpy,bc0x,bc0y,bc1x,bc1y,a2x,a2y | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment