class Disp3D::Manipulator
Public Class Methods
new(camera, picker)
click to toggle source
# File lib/manipulator.rb, line 6 def initialize(camera, picker) @camera = camera @picker = picker @start_x = 0 @start_y = 0 @rotating = false @scalling = false @translating = false @trackball_size = 0.8 end
Public Instance Methods
centering(scene_graph)
click to toggle source
# File lib/manipulator.rb, line 19 def centering(scene_graph) @camera.pre_translate = Vector3.new() set_rotation_ceter(scene_graph.center) end
fit(scene_graph)
click to toggle source
# File lib/manipulator.rb, line 24 def fit(scene_graph) centering(scene_graph) @camera.fit(scene_graph.radius) end
motion(x,y)
click to toggle source
return true if should be redisplay
# File lib/manipulator.rb, line 68 def motion(x,y) dmy, dmy, width, height = @camera.viewport() if( @translating ) delta_x = 2*((@start_x - x).to_f/width) delta_y = 2*((@start_y - y).to_f/height) @start_x = x @start_y = y @camera.pre_translate.x -= delta_x*@camera.obj_rep_length @camera.pre_translate.y += delta_y*@camera.obj_rep_length return true elsif ( @scalling ) @camera.scale *= (1.0+(@start_y - y).to_f/height) @start_y = y return true elsif ( @rotating ) @lastquat =trackball( (2.0 * @start_x - width) / width, (height - 2.0 * @start_y) / height, (2.0 * x - width) / width, (height - 2.0 * y) / height) @start_x = x @start_y = y @camera.rotate = @lastquat * @camera.rotate if( @lastquat ) return true end return false end
mouse(button,state,x,y)
click to toggle source
# File lib/manipulator.rb, line 41 def mouse(button,state,x,y) if (state == GLUT::GLUT_DOWN && ((button == GLUT::GLUT_RIGHT_BUTTON && @rotating == true) || (button == GLUT::GLUT_LEFT_BUTTON && @scalling == true) )) # pushed left and right at the same time @translating = true @start_x = x @start_y = y elsif (button == GLUT::GLUT_RIGHT_BUTTON && state == GLUT::GLUT_DOWN) @scalling = true @start_y = y elsif ( button == GLUT::GLUT_LEFT_BUTTON && state == GLUT::GLUT_DOWN ) @rotating = true @start_x = x @start_y = y elsif ( button == GLUT::GLUT_MIDDLE_BUTTON && state == GLUT::GLUT_DOWN ) set_clicked_point_as_rotation_center(x,y) elsif ( button == GLUT::GLUT_RIGHT_BUTTON && state == GLUT::GLUT_UP ) @scalling = false @translating = false elsif ( button == GLUT::GLUT_LEFT_BUTTON && state == GLUT::GLUT_UP ) @rotating = false @translating = false end end
set_rotation_ceter(rot_center)
click to toggle source
# File lib/manipulator.rb, line 29 def set_rotation_ceter(rot_center) scale = @camera.scale post_trans_vec = @camera.post_translate.to_column_vector pre_trans_vec = @camera.pre_translate.to_column_vector rot_mat = Matrix.from_quat(@camera.rotate) new_pre_translate = ( rot_mat.t * post_trans_vec * scale + pre_trans_vec ) + rot_mat.t * rot_center.to_column_vector * scale new_pre_translate = GMath3D::Vector3.new(new_pre_translate[0,0], new_pre_translate[1,0], new_pre_translate[2,0]) @camera.pre_translate = new_pre_translate @camera.post_translate = rot_center*-1.0 end
Private Instance Methods
project_to_sphere(r, x, y)
click to toggle source
# File lib/manipulator.rb, line 105 def project_to_sphere(r, x, y) d = Math.sqrt(x*x + y*y) if (d < r * Math.sqrt(2)/2) # inside sphere z = Math.sqrt(r*r - d*d) else t = r / Math.sqrt(2) z = t*t / d end return z end
set_clicked_point_as_rotation_center(x,y)
click to toggle source
# File lib/manipulator.rb, line 98 def set_clicked_point_as_rotation_center(x,y) results = @picker.pick(x,y) nearest = results.min {|a,b| a.near <=> b.near} return if(nearest.nil?) set_rotation_ceter(nearest.world_position) end
trackball(p1x, p1y, p2x, p2y)
click to toggle source
# File lib/manipulator.rb, line 116 def trackball(p1x, p1y, p2x, p2y) if( p1x == p2x && p1y == p2y) return Quat.new(0,0,0,1) end p1 = Vector3.new( p1x, p1y, project_to_sphere(@trackball_size, p1x, p1y)) p2 = Vector3.new( p2x, p2y, project_to_sphere(@trackball_size, p2x, p2y)) a = p1.cross(p2) d = p1 - p2 t = d.length / (2*@trackball_size) t = 1 if( t > 1) t = -1 if( t < -1 ) phi = 2*Math.asin(t) a = a.normalize return Quat.from_axis(a, phi) end