トーラス
よくさ、ドラクエの世界は南と北、東と西が繋がってるからドーナツ型だっていうんで普通のドーナツみたいな図を描いて説明するじゃん。こんな感じで。
でもさ、これだとドーナツの内側と外側で一周の長さが全然違うわけさ。で、その違いを小さくしようとしたらさ、こう細長いドーナツにしちゃう。
そうすると確かに内側と外側長さは近くなるけどさ、南北に一周した時と東西に一周した時の長さが全然違っちゃうわけさ。でも、ドラクエ世界の地図は正方形だから、南北と東西で長さが同じになってほしいじゃん。だとするとさ、ドラクエの世界ってこう筒みたいな形になるんじゃね?
半分に切るとこんな感じ。
というわけで、久しぶりに手描き PostScript でお絵描きしてみました。以下ソース。
%!PS-Adobe-2.0 %%BoundingBox: 0 0 200 250 gsave 100 dict begin % size %/a 50 def /b 25 def /c 25 def %/a 65 def /b 10 def /c 10 def /a 50 def /b 5 def /c 78.54 def /angle 180 def %/angle 360 def % sample number /nu 80 def /nv 40 def % center /cx 100 def /cy 125 def % view angle /rotx_deg -60 def % light source /light_source [0.75 sqrt 0.5 0] def % edge /write_edge? false def % functions /min{ % a b -> min(a,b) 2 copy gt{ exch }if pop }def /map{ % [a1 a2 a3] expr -> [expr(a1) expr(a2) expr(a3)] [ 3 1 roll forall ] }def /zip{ % [a1 a2 a3] [b1 b2 b3] -> [[a1 b1] [a2 b2] [a3 b3]] 3 dict begin /arr2 exch def /arr1 exch def [ 0 1 arr1 length arr2 length min 1 sub{ /i exch def [ arr1 i get arr2 i get ] }for ] end }def /v_add{ % [x1 y1 z1] [x2 y2 z2] -> [x1+x2 y1+y2 z1+z2] zip { aload pop add } map }def /v_sub{ % [x1 y1 z1] [x2 y2 z2] -> [x1-x2 y1-y2 z1-z2] zip { aload pop sub } map }def /vs_div{ % [x y z] a -> [x/a y/a z/a] 1 dict begin /a exch def { a div }map end }def /norm{ % [x y z] -> sqrt(x*x+y*y+z*z) 0.0 exch{ dup mul add }forall sqrt }def /cross{ % [x1 y1 z1] [x2 y2 z2] -> [y1*z2-z1*y2 z1*x2-x1*z2 x1*y2-y1*x2] 2 dict begin /v2 exch def /v1 exch def [ v1 1 get v2 2 get mul v1 2 get v2 1 get mul sub v1 2 get v2 0 get mul v1 0 get v2 2 get mul sub v1 0 get v2 1 get mul v1 1 get v2 0 get mul sub ] end }def /prod{ % [x1 y1 z1] [x2 y2 z2] -> x1*x2+y1*y2+z1*z2 zip 0.0 exch{ aload pop mul add }forall }def /rotx{ % [x y z] th -> [x y*cos(th)-z*sin(th) y*sin(th)+z*cos(th)] 4 dict begin /th exch def aload pop /z exch def /y exch def /x exch def [ x y th cos mul z th sin mul sub y th sin mul z th cos mul add ] end }def /center_of_face{ % face -> center [0.0 0.0 0.0] exch { v_add }forall { 4 div }map }def /normal_of_face{ % face -> nomal 1 dict begin /face exch def face 2 get face 0 get v_sub face 3 get face 1 get v_sub cross dup norm vs_div end }def /facestroke{ % face -> dup 0 get aload pop pop moveto 1 3 getinterval{ aload pop pop lineto }forall }def % faces [ /du angle nu div def /dv 360 nv div def 0 1 nu{ du mul /u exch def 0 1 nv{ dv mul /v exch def [ [ [u v] [u du add v] [u du add v dv add] [u v dv add] ]{ aload pop /v1 exch def /u1 exch def [ % (a+b*cos(v))*cos(u) a b v1 cos mul add u1 cos mul % (a+b*cos(v))*sin(u) a b v1 cos mul add u1 sin mul % c*sin(v) c v1 sin mul ] rotx_deg rotx }forall ] }for }for ] /faces exch def faces{ center_of_face 2 get exch center_of_face 2 get gt }.sort /faces exch def cx cy translate 0.5 setlinewidth faces{ dup normal_of_face light_source prod 2.5 div 0.6 add 0 exch 0 setrgbcolor dup facestroke fill write_edge?{ 0 setgray dup facestroke stroke }if pop }forall end grestore