LINQ をリスト内包記法として使う例
リストの内包表記(list comprehensions) - ++C++; // 管理人の日記で書いたリスト内包の利用例として、ふと思いついたことをやってみる。
3次元上の格子点を平面に投影するっての。
3次元の格子点って言うと、
で、とある平面への投影関数を Pr とでも置いて、
がどういう点を描くかという話。↑のPは、例えば、投影したい平面の正規直交基底ベクトルをとすると、
と書けるような点の集合になる。
まず、3次元の格子点は C# 3.0 的に書くと、
var points3d = from x in Enumerable.Range(-M, 2 * M) from y in Enumerable.Range(-M, 2 * M) from z in Enumerable.Range(-M, 2 * M) select new Vector3D(x, y, z);
てな感じ。M は適当な整数の定数。探索範囲を絞るために。Vector3D は、WPF の System.Windows.Media.Media3D.Vector3D クラス。
これに対して、ある法線ベクトル normal と、それに直交する基底2つ i1, i2 を与えて、
var projectedPoints = from p in points3d let x = Vector3D.DotProduct(p, i1) let y = Vector3D.DotProduct(p, i2) select new Point(x, y);
で投影完了。結構、数学のイメージどおりのコードになってるんじゃないかと。
法線ベクトル normal から、適当な残り2つの直交基底を求めるには以下のような関数を書けばOK。
static void GetOrthogonalBase(Vector3D i1, out Vector3D i2, out Vector3D i3) { Vector3D temp; if (i1.X > i1.Y) if (i1.X > i1.Z) temp = new Vector3D(0, 1, 0); else temp = new Vector3D(1, 0, 0); else if (i1.Y > i1.Z) temp = new Vector3D(0, 0, 1); else temp = new Vector3D(1, 0, 0); i2 = Vector3D.CrossProduct(i1, temp); i2.Normalize(); i3 = Vector3D.CrossProduct(i1, i2); i3.Normalize(); }
探索範囲とかを絞って(指定した平面から遠い点は除外&結果として表示されない範囲も除外)効率化するために、↓みたいな条件も付加。
var points3d = from x in Enumerable.Range(-M, 2 * M) from y in Enumerable.Range(-M, 2 * M) from z in Enumerable.Range(-M, 2 * M) select new Vector3D(x, y, z) into p let distance = Math.Abs(Vector3D.DotProduct(p, normal)) where distance < THICKNESS select p; Vector3D i1, i2; GetOrthogonalBase(normal, out i1, out i2); var projectedPoints = from p in points3d let x = Vector3D.DotProduct(p, i1) let y = Vector3D.DotProduct(p, i2) where -WIDTH <= x && x <= WIDTH && -WIDTH <= y && y <= WIDTH select new Point(x, y);
結果、例えば・・・
法線が (1, 0, 0) みたいなのだと、投影結果もきれいに格子点になって、↓みたいな感じ。
法線を (1, 1, 1) とかにすると、最密充填な感じの6角形状の点が得られる↓。
(1, 5, 7) みたいな多少妙な比率にしても、有理比である限りきれいな格子模様になる↓。(精度の問題でぼやけてるけど、理屈の上ではちゃんと点になる。)
みたいに無理数比にしてしまうと、周期性がなくなる↓。
↑は厚み(平面からの距離)10くらいまでをプロットしたもの。厚みを太くすればするほど、全体が真っ赤に染まるはず。逆に薄くすると↓みたいな感じ(厚み 1.2)。規則性があるようなないようなちょっと不思議な模様に。
で、 みたいな比率にすると、x, y, z のうち2つだけが独立なので、縞模様になります(ある1方向には周期性がなくなって、別の1方向には周期性が残る)↓。
ちょっと数学的な話をすると、こういう、高次元の格子点を法線が無理数比の平面に投影するって話、準結晶の研究で出てきた話らしい。うまくやれば5回回転対称性を持つような準周期構造が作れるとか(結晶構造だと、1,2,3,4,6 回の回転対象性しか作れない)。