#2011.5.5 shuffle method 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=8 Color=[ [0,0,1],#blue [1,1,1],#white [1,0.5,0],#orange, [1,0,0],#red [0,1,0],#green [1,1,0],#yellow [0,1,1], [1,0,1], ] 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 def hkl(f) ("%03b"%f).split(//).map{|l| l.to_i*2-1} 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=14.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) Rubic::Face.times{|i| cube.div.times{|x| cube.div.times{|y| GL.Color3d(*Rubic::Color[cube.face[i][x][y]]) rdc=rd-cube.div/2.0+0.5 #3d rdf=cube.center(i,x,y) rdf=Vector[*rdf]*cube.div hkl=Vector[*(cube.hkl(rf))] ip=rdf.inner_product(hkl) # if rdc-0.50<=ip and ip<=rdc+0.50 # if (rdc>=0)? ip>rdc-0.51 : ip10 # lock ratation face imin=[i,Rubic::Face-1-i].min if imin+rf==3 rd=(x+y<=cube.div-1)? x : cube.div-1-x elsif (imin-rf).abs==2 rd=(x+y<=cube.div-1)? cube.div-1-y : y else rd=(x+y<=cube.div-1)? x+y : 2*cube.div-1-x-y end rd=cube.div-1-rd if i>3 end GLUT.PostRedisplay() } timer=proc{ if shuffle.size>0 rf,rd=shuffle[0] if ra==0 ra+=3*cube.div if ra>=120 ra=-ra if [1,2,4,7].include?(rf) (((ra.to_f/120).round)%3).times{ 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 Octahedron") 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()