わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

円の半径を求めよう

いきなりですが問題です.

HTML5 Canvasで円を描くには,「context.arc(x, y, r, 0, Math.PI * 2, false);」とします.contextはあらかじめセットされた変数です.
マウスのドラッグ操作の始点と終点をそれぞれ,円の中心と円周上の点とし,円を描くための半径rを計算してください.平方根はMath.sqrtで求められます.

昨日の記事のある意味続きです.tmlib.jsではstrokeCircle(x, y, r)を使えば円を描けますが,この記事では,tmlib.jsを使わないこととします.プログラミング言語は,今回もJavaScriptです.
答えを得るには,もう少し,情報が必要となります.ドラッグ操作の「始点と終点の座標」です.
始点は,onmousedownイベント*1のコールバック関数で,座標を取得し,グローバル変数xおよびyに格納しておきます.終点は,onmouseupイベントのコールバック関数で取得ができ,この関数の中で,半径rも計算することとします.
座標取得の方法には,clientXとclientY,pageXとpageY,offsetXとoffsetY,screenXとscreenYがあり,jQuery(JavaScript)でマウス座標やウィンドウサイズを取得して確認するツール | EasyRambleで違いが確認できます.今回は,ページ全体での位置座標を取得する,pageXとpageYを採用します.
コールバック関数の引数は,eventとしておきます.そうすると,event.pageXとevent.pageYが,座標を表すJavaScriptの式となります.
コーディングの前に,rを求める手順を,GIFアニメーションで表現してみました.

手順は次のとおりです.

  1. 図や数式を書ける領域(紙など)を用意する
  2. 適当に線分を引く
  3. 求めたい長さをrとする
  4. 始点の座標を(x, y)とする
  5. 終点の座標を(event.pageX, event.pageY)とする
  6. 直角三角形を作り,水平成分と鉛直成分に分ける
  7. 幅をxとする(x=|event.pageX−x|)
  8. 高さをyとする(y=|event.pageY−y|)
  9. xyrの関係を三平方の定理で表す(x^2+y^2=r^2
  10. rについて解く(r=\sqrt{x^2+y^2}

「半径r」としましたが,実際には始点と終点,2点間の距離を求めています.それと幅と高さに,絶対値記号が入りますが,2乗するので,計算にあたっては不要となります.
ではプログラムに…と行きたいのですが,もう一つだけ,解決しておきたいことがあります.始点の座標の(x, y)と,幅・高さのxyとの区別です.座標のxとyは,円を描く処理を追加する前のプログラムで,すでに使用されているものとします.そしてxyに,プログラム内で適切な変数を用意しましょう.
「差」なので,diffやdeltaといった語が思い浮かびます.字数を減らしたいので,xには変数dxを,yには変数dyを,それぞれ割り当てることにします.
半径rを算出し,円を描くためのコードは,次のようになります.

var dx = event.pageX - x;
var dy = event.pageY - y;
var r = Math.sqrt(dx * dx + dy * dy);
context.arc(x, y, r, 0, Math.PI * 2, false);

「2乗」について,「dx ^ 2」や「dx ** 2」といった書き方は,認められていません*2.べき乗関数を見つけてきて,「Math.pow(dx, 2)」と書くよりも,「dx * dx」のほうがスマートです.


プログラミングの授業で,学生に「rを計算しましょう」と問うと,おそらく一番気づきにくいのが,箇条書きの最初に挙げた「紙を用意する」だと思います.
次は,「適当に線分を引く」でしょうか.ここは,図示にあたっての「見通し」が必要なところです.直角三角形の斜辺の長さがrとなり,残りの辺の長さは,水平成分(X座標)と鉛直成分(Y座標)に分けて,rより先に計算できることを,認識しておくわけです*3
高校の物理で,このように分ける訓練をしていれば,プログラミングもスムーズ…といきたいのですが,そう言い切っていいか分かりませんし,当学部では高校で物理を履修していない学生も入学してきます.
今回の図示や解法を,「新しい経験」としてもらってかまいません.コンピュータグラフィックスなどで,新たな表現技法を学ぶ際の土台になってくれればと願います.

*1:例えば,http://hakuhin.jp/js/mouse.html

*2:http://js-next.hatenablog.com/entry/2016/03/22/221353https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operatorsに,べき乗演算子「**」が書かれていますが,ECMAScript 2016のプロポーザルの段階らしく,手元のFirefox(バージョン50.1.0)で,開発ツールよりコンソールを出し,「3**2」を実行したものの,「SyntaxError: expected expression, got '*'」と返ってきました.

*3:ドラッグ操作の始点と終点の位置によっては,X座標やY座標の差が0となる場合も起こり得ますが,それでも,ゼロ割や負数の平方根に陥らず,上記の手順で円の半径(2点間の距離)が計算できるのも,別途確認しておきたいところです.