「一次変換」命令

前節で扱った「回転」変換は、一次変換と呼ばれるものです。他にも、(原点を通る)直線に対する対称変換や、縮小・拡大変換なども一次変換になります。

点(x,y)を一次変換によって移した点(X,Y)は、次のように表されます。

X=ax+by, Y=cx+dy

a, b, c, d は一次変換を特徴づける定数(パラメータ)です。

# 「X,Yを1,0,0,-1で一次変換」のように使う
●一次変換({参照渡し}X,{参照渡し}Yをa,b,c,dで)
 xとは数値=X
 yとは数値=Y
 X = a*x + b*y
 Y = c*x + d*y

回転変換(再定義)

前節で扱った回転変換の場合は、それぞれ a = cos(θ), b = -sin(θ), c = sin(θ), d = cos(θ) でした。そこで、前節の「回転」命令を、「一次変換」命令を使って定義し直してみましょう[*1]

●回転({参照渡し}X,{参照渡し}Yをθだけ)
 cosとは数値=COS(θ)
 sinとは数値=SIN(θ)
 X,Yをcos,-sin,sin,cosで一次変換

前の定義と見比べてみると、少しすっきりしました。

対称変換

同じように、直線についての対称変換も定義してみます。x 軸となす角が α[rad] で原点を通る直線 x*sinα-y*cosα=0 に対して点(x,y)を折り返(対称変換)した点(X,Y)は、次のように求まります:

X=xcos2θ+bsin2θ, Y=xsin2θ-ycos2θ

●対称変換({参照渡し}X,{参照渡し}Yをθで)
 cosとは数値=COS(2*θ)
 sinとは数値=SIN(2*θ)
 X,Yをcos,sin,sin,-cosで一次変換

対称変換」よりも「折り返し」とか「反転」という名前の方がいい!という人もいるかもしれません。その場合は、「AとはB」を使って別名で同じ処理をする命令を作ることができます:

折り返しとは対称変換。
反転とは対称変換。

グループを利用した一次変換

一般の一次変換と、それを具体的な用途に特化した形で「回転変換」「対称変換」を見てきました。しかし、この定義だと何回(1000回、10000回…!)も同じ角度で回転したりするときに何度も三角関数を計算しなければならず、少し無駄が多いです。

なでしこには「グループ構文」という機能があるので、それを使うことでこの問題を解消することができます[*2]。グループ構文は難しいので、ここでは紹介程度に留めておきます。

■一次変換
 ・{数値}a
 ・{数値}b
 ・{数値}c
 ・{数値}d
 ・変換({参照渡し}X,{参照渡し}Yを)〜
  xとは数値=X。yとは数値=Y。
  X = a*x + b*y
  Y = c*x + d*y

■回転 +一次変換
 ・角度 ←角度設定
 ・角度設定(θに)〜
  θ=DEG2RAD(θ)
  a = COS(θ)
  c = SIN(θ)
  b = -c
  d = a

■折り返し +一次変換
 ・角度 ←角度設定
 ・角度設定(θに)〜
  θ=DEG2RAD(θ)
  a = COS(2*θ)
  c = SIN(2*θ)
  b = c
  d = -a

使い方の例:

三十度回転とは回転
その角度は30。# この時点で三角関数の計算が一度行われる

L対称とは折り返し
その角度は30。# この時点で三角関数の計算が一度行われる

X=100
Y=200

100回
 X,YをL対称で変換。# ここでは一度計算した値が使われるだけ
 「{X},{Y}」と表示
 X,Yを三十度回転で変換。# ここでは一度計算した値が使われるだけ
 「{X},{Y}」と表示

表示ログをメモ記入

注釈

*1
なでしこでは関数のオーバーライド(同名関数の上書き)に対応していますが、同じプログラム(ネームスペース)中に同じ関数名を二度出現させることはできません。何度も同じ名前で関数を定義したりしていますが、実際に使う場合は一種類だけ利用してください。
*2
関数式とクロージャ(変数環境)が実装されている言語では、このようにわざわざグループ(クラス)を定義しなくても同じプログラムをもっと簡単に表現できます。例えばこのグループの例では、回転角度などの「情報」をグループのメンバの形で保持していますが、クロージャは関数式自体に直接パラメータ(外環境のローカル変数)を持たせることができるので、非常に強力な表現手段となります。なでしこから実行できる言語「LUA」もクロージャを実装しているので、LUAを使うのもいいかもしれませんね。