#2011.5.5 require "opengl" require "glut" require "matrix" class Matrix def []=(i,j,x) @rows[i][j]=x end end #class class Vector def outer_product(u) Vector[ self[1] * u[2] - self[2] * u[1], self[2] * u[0] - self[0] * u[2], self[0] * u[1] - self[1] * u[0], ] end end class Rubic # with tetragonal shape Face=20 Color=[ [0,0,0.6],[0,0,1], [1,0,0],[1,0,1], [0,1,0],[0,1,1], [1,1,0],[1,1,1], [0,0.7,0],[0,0.7,1], [1,0.7,0],[1,0.7,1], [0.5,0,0],[0.5,0,1], #[0.5,1,0],[0.5,1,1], [0.5,0.7,0],[0.5,0.7,1], [0.5,0.7,0.6],[0,1,0.6], [1,1,0.6],[1,0.7,0.6], ] #1 0.7 0 Fa,Fb=2.0*0.25,(1.0+Math::sqrt(5))*0.25 Vertex=[ [Fb,Fa,0],[0,Fb,Fa],[Fa,0,Fb], [Fb,-Fa,0],[0,Fb,-Fa],[-Fa,0,Fb], [-Fb,-Fa,0],[0,-Fb,-Fa],[-Fa,0,-Fb], [-Fb,Fa,0],[0,-Fb,Fa],[Fa,0,-Fb], ] Faces=[ [ 0, 3, 2],[ 6, 8, 9], [ 0,11, 3],[ 6, 9, 5], [ 1, 4, 0],[ 6,10, 7], [ 1, 9, 4],[ 7,10, 3], [ 2, 5, 1],[ 7,11, 8], [ 2,10, 5],[ 8,11, 4], [0,2,1],[6,7,8], [9,1,5],[3,11,7], [3,10,2],[4,9,8], [0,4,11],[6,5,10], ] def initialize(div=3) @div=div @face=[] Face.times{|i| face=[] div.times{ face<=(@div.to_f-1)/2 @div.times{|dd| rotate(k,dd) if dd>=d } else @div.times{|dd| rotate(k,dd) if dd<=d } end end def to_n(i=0,x=0,y=0) ((i*@div)+x)*@div+y end def to_ixy(n=0) i=n.to_i/(@div**2) xy=n.to_i%(@div**2) x=xy/@div y=xy%@div [i,x,y] end end #class n=ARGV[0].to_i n=3 if n==0 cube=Rubic::new(n) v=Vector[0,0,1] # view vector r=Vector[1,0,0] # right vector u=Vector[0,1,0] # up vector mx,my=0,0 # mouse rf=0 # rotation face rd=0 # rotation depth su=nil # selected unit ra=0 # rotation angle mode=0 viewport=[0,0,400,400] shuffle=[] view=proc{ angl=24.0 w,h=viewport[2,2] #puts 2*Math::asin(Math::sin(10.0/180*Math::PI)/w.to_f*h)/Math::PI*180 GLU.Perspective((w>=h)?angl: 2*Math::asin(Math::sin(angl/2/180*Math::PI)/w.to_f*h)/Math::PI*180, w.to_f/h, 1.0, 100.0) GL.Translate(0.0, 0.0, -3.0); vx,vy,vz=v.to_a ux,uy,uz=u.to_a GLU.LookAt(2.0*vx,2.0*vy,2.0*vz,0.0,0.0,0.0,ux,uy,uz) } reshape= proc {|w,h| GL.MatrixMode(GL::PROJECTION) viewport=[0,0,w,h] GL.Viewport(*viewport) GL.LoadIdentity() view.call GLUT.PostRedisplay() } display = proc { GL.Clear(GL::COLOR_BUFFER_BIT | GL::DEPTH_BUFFER_BIT) GL.MatrixMode(GL::MODELVIEW) hkl=Vector[*(Rubic::Vertex[rf])] Rubic::Face.times{|i| cube.div.times{|x| cube.div.times{|y| GL.Color3d(*Rubic::Color[cube.face[i][x][y]]) rdf=Vector[*cube.center(i,x,y)]*cube.div ip=rdf.inner_product(hkl) if (rd>=-0.2)? rd-0.510 # lock ratation face imin=[i,Rubic::Face-1-i].min hkl=Vector[*(Rubic::Vertex[rf])] rd=Vector[*cube.center(*(cube.to_ixy(su)))]*cube.div rd=rd.inner_product(hkl) #p [i,rf,rd,ra] end GLUT.PostRedisplay() } timer=proc{ if shuffle.size>0 hkl=Vector[*(Rubic::Vertex[0])] if ra==0 rf,rd=shuffle[0] rd=(rd-(cube.div-1)/2.0)*hkl.r end ra+=3*cube.div if ra>=72 rd=(rd/(hkl.r)+(cube.div-1)/2.0).round (((ra.to_f/72).round)%5).times{ #p [rf,rd] cube.rotates(rf,rd) } ra=0 shuffle.shift p shuffle.size end GLUT.PostRedisplay() end GLUT.TimerFunc(10, timer, 0) } GLUT.Init() GLUT.InitDisplayMode(GLUT::RGBA | GLUT::DEPTH | GLUT::DOUBLE) GLUT.CreateWindow("Rubic Icosahedron") GL.Enable(GL::DEPTH_TEST) #GLUT.SetCursor(GLUT::CURSOR_CYCLE) GLUT.DisplayFunc(display) GLUT.ReshapeFunc(reshape) GLUT.MouseFunc(mouse) GLUT.MotionFunc(motion) GL.ClearColor(0.5,0.5,0.5,1.0) #motion.call(0,0) GLUT.TimerFunc(10, timer, 0) GLUT.MainLoop()