(function (){document.getElementById('r').onkeydown=function(){ draw(); };document.getElementById('g').onkeydown=function(){ draw(); };document.getElementById('b').onkeydown=function(){ draw(); };document.getElementById('y').onkeydown=function(){ draw(); };document.getElementById('r').onkeyup=function(){ draw(); };document.getElementById('g').onkeyup=function(){ draw(); };document.getElementById('b').onkeyup=function(){ draw(); };document.getElementById('y').onkeyup=function(){ draw(); };document.getElementById('r').onchange=function(){ draw(); };document.getElementById('g').onchange=function(){ draw(); };document.getElementById('b').onchange=function(){ draw(); };document.getElementById('y').onchange=function(){ draw(); };document.getElementById('br').onclick=function(){ document.getElementById('r').selectedIndex = document.getElementById('r').selectedIndex+1; draw(); };document.getElementById('bg').onclick=function(){ var n = document.getElementById('g').selectedIndex; var m = document.getElementById('bg').value*1; if ( n==0 ) m = +1; if ( n==180) m = -1; document.getElementById('g').selectedIndex = document.getElementById('g').selectedIndex+m; document.getElementById('bg').value = m+''; draw();};document.getElementById('bb').onclick=function(){ var n = document.getElementById('b').selectedIndex; var m = document.getElementById('bb').value*1; if ( n==0 ) m = +1; if ( n==180) m = -1; document.getElementById('b').selectedIndex = document.getElementById('b').selectedIndex+m; document.getElementById('bb').value = m+''; draw();};document.getElementById('by').onclick=function(){ var n = document.getElementById('y').selectedIndex; var m = document.getElementById('by').value*1; if ( n==0 ) m = +1; if ( n==180) m = -1; document.getElementById('y').selectedIndex = document.getElementById('y').selectedIndex+m; document.getElementById('by').value = m+''; draw();};var n;for (n=0; n!=181; n++) { document.getElementById('r').options[n] = new Option(n+'°',n+''); document.getElementById('g').options[n] = new Option(n+'°',n+''); document.getElementById('b').options[n] = new Option(n+'°',n+''); document.getElementById('y').options[n] = new Option(-n+'°',n+'');}for (; n!=721; n++) { document.getElementById('r').options[n] = new Option(n%360+'°',n%360+'');}function draw(){ var cvs = document.getElementById('cvs'); var ctx = cvs.getContext('2d'); var i = document.getElementById('r').selectedIndex; var j = document.getElementById('g').selectedIndex; var k = document.getElementById('b').selectedIndex; var l = document.getElementById('y').selectedIndex; if (i==0 || i==720) document.getElementById('r').selectedIndex=360; i = document.getElementById('r').options[i].value*1; j = document.getElementById('g').options[j].value*1; k = document.getElementById('b').options[k].value*1; l = document.getElementById('y').options[l].value*1; ctx.beginPath(); ctx.clearRect(0,0,400,400); ctx.closePath(); var p = (1.0+Math.sqrt(-3.0+Math.sqrt(48.0)))/2.0; var q = Math.sqrt(Math.sqrt(3.0)); var r = Math.acos((p*p+q*q-1.0)/(2.0*p*q)); var s = 100.0; var al=new Array(3); var ar=new Array(3); var ax=new Array(3); var ay=new Array(3); var bl=new Array(4); var br=new Array(4); var bx=new Array(4); var by=new Array(4); var cl=new Array(4); var cr=new Array(4); var cx=new Array(4); var cy=new Array(4); var dl=new Array(4); var dr=new Array(4); var dx=new Array(4); var dy=new Array(4); var centerx, centery, weightx, weighty; ctx.lineWidth = 3.5; ctx.lineJoin = 'round'; ctx.strokeStyle = 'rgba(128,128,128,0.7)'; ax[0] = 0.0; ay[0] = 0.0; al[0] = s*Math.cos(r); ar[0] = i*Math.PI/180.0+Math.PI/2.0-r; ax[1] = ax[0] + al[0]*Math.sin(-ar[0]); ay[1] = ay[0] + al[0]*Math.cos(+ar[0]); al[1] = s; ar[1] = ar[0] + (Math.PI+r); ax[2] = ax[1] + al[1]*Math.sin(-ar[1]); ay[2] = ay[1] + al[1]*Math.cos(+ar[1]); al[2] = 0; ar[2] = 0; bx[0] = ax[2]; by[0] = ay[2]; bl[0] = s*(p-1.0); br[0] = ar[1] + j*Math.PI/180.0; bx[1] = bx[0] + bl[0]*Math.sin(-br[0]); by[1] = by[0] + bl[0]*Math.cos(+br[0]); bl[1] = s; br[1] = br[0] + 4.0*Math.PI/3.0; bx[2] = bx[1] + bl[1]*Math.sin(-br[1]); by[2] = by[1] + bl[1]*Math.cos(+br[1]); bl[2] = s*(q-Math.cos(r)); br[2] = br[1] + Math.PI+2.0*Math.PI/3.0-r; bx[3] = bx[2] + bl[2]*Math.sin(-br[2]); by[3] = by[2] + bl[2]*Math.cos(+br[2]); bl[3] = 0; br[3] = 0; cx[0] = bx[2]; cy[0] = by[2]; cl[0] = s; cr[0] = br[1] + k*Math.PI/180.0; cx[1] = cx[0] + cl[0]*Math.sin(-cr[0]); cy[1] = cy[0] + cl[0]*Math.cos(+cr[0]); cl[1] = s; cr[1] = cr[0] + 4.0*Math.PI/3.0; cx[2] = cx[1] + cl[1]*Math.sin(-cr[1]); cy[2] = cy[1] + cl[1]*Math.cos(+cr[1]); cl[2] = s*Math.sin(r); cr[2] = cr[1] + 11.0*Math.PI/6.0-r; cx[3] = cx[2] + cl[2]*Math.sin(-cr[2]); cy[3] = cy[2] + cl[2]*Math.cos(+cr[2]); cl[3] = 0; cr[3] = 0; dx[0] = ax[1]; dy[0] = ay[1]; dl[0] = s*(2.0-p); dr[0] = ar[1] + Math.PI-l*Math.PI/180.0; dx[1] = dx[0] + dl[0]*Math.sin(-dr[0]); dy[1] = dy[0] + dl[0]*Math.cos(+dr[0]); dl[1] = s; dr[1] = dr[0] + 2.0*Math.PI/3.0; dx[2] = dx[1] + dl[1]*Math.sin(-dr[1]); dy[2] = dy[1] + dl[1]*Math.cos(+dr[1]); dl[2] = s*Math.sin(r); dr[2] = dr[1] - 7.0*Math.PI/6.0-r; dx[3] = dx[2] + dl[2]*Math.sin(-dr[2]); dy[3] = dy[2] + dl[2]*Math.cos(+dr[2]); dl[3] = 0; dr[3] = 0; weightx = ( ax[0]+ax[1]+ax[2]+ bx[0]+bx[1]+bx[2]+bx[3]+ cx[0]+cx[1]+cx[2]+cx[3]+ dx[0]+dx[1]+dx[2]+dx[3]); weighty = ( ay[0]+ay[1]+ay[2]+ by[0]+by[1]+by[2]+by[3]+ cy[0]+cy[1]+cy[2]+cy[3]+ dy[0]+dy[1]+dy[2]+dy[3]); centerx = 200.0 - weightx/15.0; centery = 200.0 - weighty/15.0; ctx.beginPath(); ctx.fillStyle = 'rgba(255,0,0,1.0)'; ctx.moveTo(ax[0]+centerx,ay[0]+centery); ctx.lineTo(ax[1]+centerx,ay[1]+centery); ctx.lineTo(ax[2]+centerx,ay[2]+centery); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = 'rgba(0,255,0,1.0)'; ctx.moveTo(bx[0]+centerx,by[0]+centery); ctx.lineTo(bx[1]+centerx,by[1]+centery); ctx.lineTo(bx[2]+centerx,by[2]+centery); ctx.lineTo(bx[3]+centerx,by[3]+centery); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = 'rgba(0,0,255,1.0)'; ctx.moveTo(cx[0]+centerx,cy[0]+centery); ctx.lineTo(cx[1]+centerx,cy[1]+centery); ctx.lineTo(cx[2]+centerx,cy[2]+centery); ctx.lineTo(cx[3]+centerx,cy[3]+centery); ctx.closePath(); ctx.fill(); ctx.stroke(); ctx.beginPath(); ctx.fillStyle = 'rgba(255,255,0,1.0)'; ctx.moveTo(dx[0]+centerx,dy[0]+centery); ctx.lineTo(dx[1]+centerx,dy[1]+centery); ctx.lineTo(dx[2]+centerx,dy[2]+centery); ctx.lineTo(dx[3]+centerx,dy[3]+centery); ctx.closePath(); ctx.fill(); ctx.stroke();}draw();})();
デュードニーの正三角形という数学的なパズルです。
正三角形を4パーツに切り分け、そのパーツを残らず使い正方形に組み替える。
さて、どうするか。
仮に、1辺が2の正三角形とすると、面積は3^(1/2)となる。
等積変換なので、変換後の正方形の面積も3^(1/2)であるから、正方形の1辺の長さは3^(1/4)となる。
コンパスと直定規のみを使って、正三角形から作図し、そこから切断する直線を作図する。
1) 直線を引き、長さ1をコンパスで決め、直線上に中心にして、長さ2を作る。
2) 長さ2をコンパスで取り、先の直線と円弧の2交点をそれぞれ中心として、それぞれの円弧の交点とを結び、正三角形を描く。
頂点をAとし、右上辺の中点をB、右下頂点をC、左下頂点をD、左上辺の中点をEとする。
3) DBを通る直線を引き、Bから長さ1を外側へ取った点をFとする。
DF=1+3^(1/2)
4) 線分EFの中点をGとする。a)参照
GD=GF=(1+3^(1/2))/2
GB=(-1+3^(1/2))/2
5) 点Gを中心に、DとFを通る円を描き、線分ACを延伸し、弧との交点をHとする。
BH=(((1+3^(1/2))/2)^2-((-1+3^(1/2))/2)^2)^(1/2)=3^(1/4)
6) 点Bを中心に線分BHを半径として円を描き、線分CDとの交点をIとし、BIを直線で結ぶ。
7) 点IからB方向へ長さ1の点をJとする。
8) 点Jと点Eからそれぞれ、線分BIに垂線の足を下ろし、それぞれの点をK、Lとする。b)参照
a) 中点を作図するには、それぞれの端点を中心とする2円が2点で交わるような同じ半径の円を描き、2交点を直線で結び、元の線分との交点が中点。
b) 垂線の足を作図するには、点を中心として、線分と2交点が出来る半径で円を描き、2交点を底辺とする正三角形を描き、正三角形の頂点と点を通る直線と線分との交点が垂線の足。
作図ができましたね。
次に、それぞれの図形の辺の長さや角を求めてみましょう。
まず、ICの長さを求めます。
BC=1、BI=3^(1/4)、∠C=60˚より、余弦定理を使い、
IC=(1+(-3+(48^(1/2)))^(1/2))/2
次に、∠BICを求めます。
∠BIC=acos((IB^2+IC^2-BC^2)/(2*IB*IC))
=acos(((3^(1/2))+(((1+(-3+(48^(1/2)))^(1/2))/2)^2)-(1^2))/(2*(3^(1/4))*(1+(-3+(48^(1/2)))^(1/2))/2)
m=IB
n=IC
∠α[rad]=∠BIC
として、話を進めます。
三角形KJI
辺 | 式 | 値 |
KJ | =sin(α) | 0.6580370065 |
JI | =1 | 1.0000000000 |
IK | =cos(α) | 0.7529855896 |
角 | 式 | 値[rad] | 値[deg] |
∠IKJ | =(π/2) | 1.5707963268 | 90.0000000000 |
∠KJI | =(π/2)-α | 0.8525874923 | 48.8496649732 |
∠JIK | =α | 0.7182088345 | 41.1503350268 |
四角形KBCJ
辺 | 式 | 値 |
KB | =m-cos(α) | 0.5630884234 |
BC | =1 | 1.0000000000 |
CJ | =n-1 | 0.4909847666 |
JK | =sin(α) | 0.6580370065 |
角 | 式 | 値[rad] | 値[deg] |
∠JKB | =(3π/6) | 1.5707963268 | 90.0000000000 |
∠KBC | =(4π/6)-α | 1.3761862679 | 78.8496649732 |
∠BCJ | =(2π/6) | 1.0471975512 | 60.0000000000 |
∠CJK | =(3π/6)+α | 2.2890051613 | 131.1503350268 |
四角形LEAB
辺 | 式 | 値 |
LE | =sin(α) | 0.6580370065 |
EA | =1 | 1.0000000000 |
AB | =1 | 1.0000000000 |
BL | =cos(α) | 0.7529855896 |
角 | 式 | 値[rad] | 値[deg] |
∠BLE | =(3π/6) | 1.5707963268 | 90.0000000000 |
∠LEA | =(5π/6)-α | 1.8997850435 | 108.8496649732 |
∠EAB | =(2π/6) | 1.0471975512 | 60.0000000000 |
∠ABL | =(2π/6)+α | 1.7654063857 | 101.1503350268 |
四角形LIDE
辺 | 式 | 値 |
LI | =m-cos(α) | 0.5630884234 |
ID | =2-n | 0.5090152334 |
DE | =1 | 1.0000000000 |
EL | =sin(α) | 0.6580370065 |
角 | 式 | 値[rad] | 値[deg] |
∠ELI | =(3π/6) | 1.5707963268 | 90.0000000000 |
∠LID | =(6π/6)-α | 2.4233838191 | 138.8496649732 |
∠IDE | =(2π/6) | 1.0471975512 | 60.0000000000 |
∠DEL | =(1π/6)+α | 1.2418076101 | 71.1503350268 |
プログラミング言語にもよるが、三角関数の引数はラジアンであり、逆三角関数の返り値もラジアンである。
角の式に置いてもラジアンを求め、πの係数の分母を揃えた方が分かりやすいので、あえて約分していません。
さて、パソコンでこのページを閲覧していて、JavaScriptが有効になっていて、html5のcanvasをサポートしている環境であれば、トップに正三角形が図示されていることだろう。
正三角形の外周上にある各パーツの接点のどこを切り離しても良いのだが、このプログラムでは青と黄を接続していないものにしました。
また、唯一ある三角形である赤を固定して、他のパーツを接点で回転させられるようにしてあります。
操作方法
プルダウンメニューは、直接角度を指定してもよし、フォーカスを当て、カーソルキーの上下左右を使ってダイナミックに動かすこともできます。
色名ボタンは、赤は時計回りに回転し続け、他の連結パーツは可動範囲を往復するようにしてあります。
とは言っても、当たり判定をしているわけではないので、場合によっては青と黄が重なることもあります。
クリックで連打しても良いのですが、フォーカスを当て、Enterキーを押しっぱなしにすることでダイナミックに動かすこともできます。
三角形を固定してとは書いたが、図形の重心を取って、canvasの中心に据えているので、変形するにつれ、場所が移動します。
こうすることで、正三角形や正方形のときなどに赤で回転をしても、ブレなくてよい。