#include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #else #include #endif #include #include #include class Camera { public: // m_zoom Zoom of camera lens {1} // m_angle Field of view angle in degrees {15} // m_aspect Aspect ratio {1} // m_near near clipping plane {1e-2} // m_far far clipping plane {100} // m_rotation Rotation part of rigid transformation of camera {identity} // m_translation Translation part of rigid transformation of camera // {(0,0,1)} double m_zoom, m_angle, m_aspect, m_near, m_far; Eigen::Quaterniond m_rotation; Eigen::Vector3d m_translation; Camera(): m_zoom(1), m_angle(15.0), m_aspect(1), m_near(1e-2), m_far(100), m_rotation(1,0,0,0), m_translation(0,0,1) { } Eigen::Vector3d eye() const { using namespace Eigen; Affine3d t = Affine3d::Identity(); t.rotate(m_rotation); t.translate(m_translation); return t * Vector3d(0,0,0); } Eigen::Vector3d at() const { using namespace Eigen; Affine3d t = Affine3d::Identity(); t.rotate(m_rotation); t.translate(m_translation); return t * Vector3d(0,0,-1); } Eigen::Vector3d up() const { using namespace Eigen; Affine3d t = Affine3d::Identity(); t.rotate(m_rotation); return t * Vector3d(0,1,0); } void dolly(const double d) { using namespace Eigen; Vector3d dv(0,0,d); m_translation += m_rotation.conjugate() * dv; } void look_at( const Eigen::Vector3d & eye, const Eigen::Vector3d & at, const Eigen::Vector3d & up) { using namespace Eigen; using namespace std; using namespace igl; // http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml // Normalize vector from at to eye const Vector3d F = (eye-at).normalized(); // Project up onto plane orthogonal to F and normalize const Vector3d proj_up = (up-(up.dot(F))*F).normalized(); Quaterniond a,b; a.setFromTwoVectors(Vector3d(0,0,-1),-F); b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up); m_rotation = a*b; m_translation = m_rotation.conjugate() * eye; assert( (eye-this->eye()).squaredNorm() < DOUBLE_EPS); assert((F-(this->eye()-this->at())).squaredNorm() < DOUBLE_EPS); assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS); } }; enum RotationType { ROTATION_TYPE_IGL_TRACKBALL = 0, ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1, NUM_ROTATION_TYPES = 2, } rotation_type = ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP; int width,height; #define REBAR_NAME "temp.rbr" igl::ReTwBar rebar; struct State { int viewing_camera; std::vector cameras; State():viewing_camera(0),cameras(2){} } s; std::stack undo_stack; bool is_rotating = false; Camera down_camera; int down_x,down_y; std::stack redo_stack; void push_undo() { undo_stack.push(s); // Clear redo_stack = std::stack(); } void undo() { if(!undo_stack.empty()) { redo_stack.push(s); s = undo_stack.top(); undo_stack.pop(); } } void redo() { if(!redo_stack.empty()) { undo_stack.push(s); s = redo_stack.top(); redo_stack.pop(); } } void print(const Camera & camera) { using namespace std; cout<< "rotation: "<( width, height, 2.0, down_camera.m_rotation.coeffs().data(), down_x, down_y, mouse_x, mouse_y, camera.m_rotation.coeffs().data()); break; } case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP: { Quaterniond down_q = down_camera.m_rotation; Vector3d axis(0,1,0); const double speed = 2.0; Quaterniond q; q = down_q * Quaterniond( AngleAxisd( M_PI*((double)(mouse_x-down_x))/(double)width*speed/2.0, axis.normalized())); q.normalize(); { Vector3d axis(1,0,0); const double speed = 2.0; if(axis.norm() != 0) { q = Quaterniond( AngleAxisd( M_PI*(mouse_y-down_y)/(double)width*speed/2.0, axis.normalized())) * q; q.normalize(); } } camera.m_rotation = q; break; } default: break; } const bool orbit = true; if(orbit) { // at should be fixed // Undo rotation from translation part: translation along view (from // `at`) Vector3d t = down_camera.m_rotation * down_camera.m_translation; // Rotate to match new rotation camera.m_translation = camera.m_rotation * t; //assert((down_camera.at() - camera.at()).squaredNorm() < DOUBLE_EPS); }else { // eye should be fixed // flip rotation? } } } void key(unsigned char key, int mouse_x, int mouse_y) { using namespace std; int mod = glutGetModifiers(); switch(key) { // ESC case char(27): rebar.save(REBAR_NAME); // ^C case char(3): exit(0); case 'z': case 'Z': if(mod & GLUT_ACTIVE_COMMAND) { if(mod & GLUT_ACTIVE_SHIFT) { redo(); }else { undo(); } break; } default: if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y)) { cout<<"Unknown key command: "<=8"); // Top right corner glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)/2.0); glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH)/2.0,-1); glutCreateWindow("camera"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutMouseFunc(mouse); glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT); glutMotionFunc(mouse_drag); glutMainLoop(); return 0; }