月別アーカイブ: 2023年12月

三葉曲線を描く

バラ曲線の描画

HTML言語のSvg(Scalable Vector Graphics)を用いて、正葉曲線(バラ曲線)の中で代表的な三葉曲線を描いてみました。そのサンプルを示します。

プログラミングにおいてはタイマー関数を利用して導火線が燃え移るような時間差描写を実現し、ここにおける三葉曲線は半径と描画色を変えて4重の重ね書きが完了後に全体が回転します。

三葉曲線はsinとcosの三角関数を準備すれば描画ポイントを算出できます。それらは浮動小数点演算され、誤差を加味したテクニックが要求されます。また、回転操作はHTMLのアニメーション関数を使いました。

調査不足かも知れませんがアニメーションの起動において、animation-play-stateによる制御は期待した動作にならず苦労しました。

cssのstye属性:animationに直接、働きかけたサンプルの処理は主要ブラウザで思ったとおりの動作を確認しました。 回転中心座標を指定するtransform-originは対象要素がdiv, svgによって回転中心座標が異なります。サンプルコードを注意深く見てください。

Result

再実行はブラウザのリロードボタンを押します。

©TacM 2023

HTMLサンプルコード

<html>							<!-- svg35C.html: svg, animation, setInterval, clearInterval のサンプル, ©TacM 2023 -->
<head>
<meta charset="utf-8">
<style type="text/css">
@keyframes rotate1 {					/* 回転に使う */
    0% { transform: rotate(  0deg); }
   50% { transform: rotate(180deg); }
  100% { transform: rotate(360deg); }
}
</style>
</head>
<body onload="gameLoop=setInterval(draw35,T3);" style="overflow:hidden;">
<div id="turn" style="margin:0 auto; width:400px; height:400px; border:1px solid blue; border-radius:50%;">
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 550 550">
  <line id="xaxis" x1="0"   y1="275" x2="550" y2="275" stroke-width="1" stroke="skyblue"/>
  <line id="yaxis" x1="275" y1="0"   x2="275" y2="550" stroke-width="1" stroke="skyblue"/>
  <text x="490" y="272" font-size="16">&copy;TacM 2023</text>
  <polyline id="curv0" style="fill:none; stroke:deeppink; stroke-width:1.0" points=""/>
  <polyline id="curv1" style="fill:none; stroke:olive;    stroke-width:1.0" points=""/>
  <polyline id="curv2" style="fill:none; stroke:sienna;   stroke-width:1.0" points=""/>
  <polyline id="curv3" style="fill:none; stroke:blue;     stroke-width:1.0" points=""/>
</svg>
</div>
<script type="text/javascript">
const ZX=ZY=275;				//主要画像の位置
const T3=8;						//サイクロイド曲線を更新する間隔 ms
const ST=0.01;					//step 刻み値
//==============================//svgとは、Scalable Vector Graphics(スケーラブル・ベクター・グラフィックス)
var a=1;						//para-1, 1/1 1/1
var b=0.33333333333333;			//para-2, 1/3 1/5
var c=0.5;						//para-3, 1/2 1/7
var gameLoop=count=th=0;		//th:0~2.0  count:半径と色を変えて複数回繰り返す
var cmd35="";					//スタティックな変数であること
var SIZE=235;					//半径

function draw35(){				//<<<<<***** function draw35(), blue サイクロイド曲線 θ:0~360°まで繰り返す *****>>>>>
    var t = th * Math.PI;							//theta
    var ab = a - b;									//パラメータ
    var bb = ab / b * t;							//パラメータ
    var wy = 550 - ZY - SIZE * (ab * Math.cos(t) + c * Math.cos(bb));		//y方向の見た目が安定するよう上下を逆にした
    var wx = ZX - SIZE * (ab * Math.sin(t) - c * Math.sin(bb));				//見た目が左右対称になるようにxyを逆にした
    cmd35=cmd35+" "+wx+","+wy;						//polylineのpointsコマンドを作る
    //console.log("t=", t, wx, wy);
	document.getElementById('curv'+count).setAttribute("points", cmd35);	//三葉曲線を描画
	th += ST;										//次のポイント
	if(th > 2.0000000000000013){					//2.0000000000000013は 360°2πの浮動小数点演算誤差を勘案
	  if(++count>=4){clearInterval(gameLoop);setTimeout(revolution,500);return;}//三葉曲線を描画終了500ms後、回転 returnを忘れてはならない!
	  th=0;											//関数の外で定義したスタティックな制御変数をリセット
	  cmd35="";										//スタティックな変数を空に
	  SIZE = 235 - count*16;						//0 1 2 3  10~20 230 235  半径と色はcountに依存
	  console.log("半径と色を変える", count, SIZE, 'curv'+count, document.getElementById('curv'+count).style.stroke);
	}
}
function revolution(){								//全体を回転させる
	document.getElementById("turn").style.animation="rotate1 5s linear 2";	//回転起動
	document.getElementById("turn").style.transformOrigin="200px 200px";	//回転中心座標 svg要素でなくdiv要素の中心点
}
</script>
</body>
</html>

さいごに

三葉曲線は何度も取り上げてきましたが今回は演算誤差やアニメーションの起動に焦点を合わせました。Svgの使い方の例として参考になれば幸いです。