/**************************************************************************** * MeshLab o o * * A versatile mesh processing toolbox o o * * _ O _ * * Copyright(C) 2008 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ /**************************************************************************** History $Log: not supported by cvs2svn $ Revision 1.8 2008/03/02 16:44:18 benedetti moved ActiveCoordinateFrame to its own files Revision 1.7 2008/02/26 18:22:42 benedetti corrected after quaternion/similarity/trackball changes Revision 1.6 2008/02/22 20:34:35 benedetti corrected typo Revision 1.5 2008/02/22 20:04:02 benedetti many user interface improvements, cleaned up a little Revision 1.4 2008/02/17 20:52:53 benedetti some generalization made Revision 1.3 2008/02/16 14:12:30 benedetti first version ****************************************************************************/ #include #include #include #include #include "coordinateframe.h" using namespace vcg; CoordinateFrame::CoordinateFrame(float s) :basecolor(Color4b::White),xcolor(Color4b::Red) ,ycolor(Color4b::Green),zcolor(Color4b::Blue),size(s),linewidth(2.0) ,font(),drawaxis(true),drawlabels(true),drawvalues(false) { font.setFamily("Helvetica"); } void CoordinateFrame::Render(QGLWidget* glw) { assert( glw!= NULL); glPushAttrib(GL_ALL_ATTRIB_BITS); glDisable(GL_LIGHTING); glDisable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_LINE_SMOOTH); glEnable(GL_POINT_SMOOTH); glLineWidth(linewidth); glPointSize(linewidth*1.5); Point3d o(0,0,0); Point3d a(size,0,0); Point3d b(0,size,0); Point3d c(0,0,size); // Get gl state values double mm[16],mp[16]; GLint vp[4]; glGetDoublev(GL_MODELVIEW_MATRIX,mm); glGetDoublev(GL_PROJECTION_MATRIX,mp); glGetIntegerv(GL_VIEWPORT,vp); float slope_a=calcSlope(-a,a,2*size,10,mm,mp,vp); float slope_b=calcSlope(-b,b,2*size,10,mm,mp,vp); float slope_c=calcSlope(-c,c,2*size,10,mm,mp,vp); float scalefactor = size*0.02f; if(drawaxis){ glBegin(GL_LINES); glColor(xcolor); glVertex(-a); glVertex(a); glColor(ycolor); glVertex(-b); glVertex(b); glColor(zcolor); glVertex(-c); glVertex(c); glEnd(); glColor(basecolor); // positive axes drawTickedLine(o,a,size,slope_a,linewidth); // Draws x axis drawTickedLine(o,b,size,slope_b,linewidth); // Draws y axis drawTickedLine(o,c,size,slope_c,linewidth); // Draws z axis // negative axes drawTickedLine(o,-a,size,slope_a,linewidth); // Draws x axis drawTickedLine(o,-b,size,slope_b,linewidth); // Draws y axis drawTickedLine(o,-c,size,slope_c,linewidth); // Draws z axis glPushMatrix(); glTranslate(a); glScalef(scalefactor,scalefactor,scalefactor); Add_Ons::Cone(10,linewidth*1.5,linewidth*0.5,true); glPopMatrix(); glPushMatrix(); glTranslate(b); glRotatef(90,0,0,1); glScalef(scalefactor,scalefactor,scalefactor); Add_Ons::Cone(10,linewidth*1.5,linewidth*0.5,true); glPopMatrix(); glPushMatrix(); glTranslate(c); glRotatef(-90,0,1,0); glScalef(scalefactor,scalefactor,scalefactor); Add_Ons::Cone(10,linewidth*1.5,linewidth*0.5,true); glPopMatrix(); } if(drawlabels){ font.setBold(true); font.setPixelSize(12); float d=size+scalefactor*linewidth*1.5; glColor(xcolor); glw->renderText(d,0,0,QString("X"),font); glColor(ycolor); glw->renderText(0,d,0,QString("Y"),font); glColor(zcolor); glw->renderText(0,0,d,QString("Z"),font); } if(drawvalues){ font.setBold(false); font.setPixelSize(8); float i; glColor(Color4b::LightGray); for(i=slope_a;irenderText( i,0,0,QString(" %1").arg(i,3,'f',1),font); glw->renderText(-i,0,0,QString("-%1").arg(i,3,'f',1),font); } for(i=slope_b;irenderText(0, i,0,QString(" %1").arg(i,3,'f',1),font); glw->renderText(0,-i,0,QString("-%1").arg(i,3,'f',1),font); } for(i=slope_c;irenderText(0,0, i,QString(" %1").arg(i,3,'f',1),font); glw->renderText(0,0,-i,QString("-%1").arg(i,3,'f',1),font); } } glPopAttrib(); assert(!glGetError()); } void CoordinateFrame::drawTickedLine(const Point3d &a,const Point3d &b, float dim,float tickDist,float linewidth) { Point3d v(b-a); v = v /dim; // normalize without computing square roots and powers glBegin(GL_POINTS); float i; for(i=tickDist;i(niceRound(dim*.001f),nslope); // prevent too small slope return nslope; } float CoordinateFrame::niceRound(float val) { return powf(10.f,ceil(log10(val))); } MovableCoordinateFrame::MovableCoordinateFrame(float size) :CoordinateFrame(size),position(0,0,0),rotation(0,Point3f(1,0,0)) { // nothing here } void MovableCoordinateFrame::Render(QGLWidget* gla) { glPushMatrix(); glTranslate(position); Matrix44f mrot; rotation.ToMatrix(mrot); glMultMatrix(Inverse(mrot)); CoordinateFrame::Render(gla); glPopMatrix(); } void MovableCoordinateFrame::GetTransform(Matrix44f & transform) { // build the matrix that moves points in world coordinates // clean transform transform.SetIdentity(); // apply rotation Matrix44f rot; rotation.ToMatrix(rot); transform = Inverse(rot) * transform ; // apply translation Matrix44f pos; pos.SetTranslate(position); transform = pos * transform; } void MovableCoordinateFrame::Reset(bool reset_position,bool reset_alignment) { if(reset_position) position = Point3f(0,0,0); if(reset_alignment) rotation = Quaternionf(0,Point3f(1,0,0)); } void MovableCoordinateFrame::SetPosition(const Point3f newpos) { position = newpos; } void MovableCoordinateFrame::SetRotation(const Quaternionf newrot) { rotation = newrot; } Point3f MovableCoordinateFrame::GetPosition() { return position; } Quaternionf MovableCoordinateFrame::GetRotation() { return rotation; } void MovableCoordinateFrame::Rot(float angle_deg,const Point3f axis) { Similarityf s; s.SetRotate(angle_deg*M_PI/180.0f,(rotation).Rotate(axis)); Move(s); } void MovableCoordinateFrame::AlignWith(const Point3f pri,const Point3f secondary,const char c1, const char c2) { const float EPSILON=1e-6f; Point3f primary=pri; if( primary.Norm() < EPSILON*size ) return; primary.Normalize(); Plane3f plane(0,primary); // projection plane for the second rotation Point3f x(1,0,0),y(0,1,0),z(0,0,1); Point3f first(0,0,0),second(0,0,0),third(0,0,0); if(c1=='X'){ first = x; if((c2=='Y')||(c2==' ')){ second = y; third = z; } else if(c2=='Z'){ second = z; third = y; } else assert (0); } else if(c1=='Y'){ first = y; if((c2=='Z')||(c2==' ')){ second = z; third = x; } else if(c2=='X'){ second = x; third = z; } else assert (0); } else if(c1=='Z'){ first = z; if((c2=='X')||(c2==' ')){ second = x; third = y; } else if(c2=='Y'){ second = y; third = x; } else assert (0); } else assert (0); Point3f old_first = Inverse(rotation).Rotate(first); // axis 1 Point3f old_second_pro = plane.Projection(Inverse(rotation).Rotate(second)); // axis 2 projection Point3f old_third_pro = plane.Projection(Inverse(rotation).Rotate(third)); // axis 3 projection // align axis 1 to primary RotateToAlign(old_first,primary); Point3f secondary_pro = plane.Projection(secondary); // secondary's projection Point3f new_second_pro = plane.Projection(Inverse(rotation).Rotate(second)); // axis 2 projection after the first rotation if( secondary.Norm() > EPSILON*size && secondary_pro.Norm() > EPSILON ){ // secondary is not null nor parallel to primary // align axis 2 projection after the first rotation to secondary's projection secondary_pro.Normalize(); RotateToAlign(new_second_pro,secondary_pro); return; } if ( old_second_pro.Norm() > EPSILON ) { // can realign axis 2 // align axis 2 projection after the first rotation to old axis 2 projection old_second_pro.Normalize(); RotateToAlign(new_second_pro,old_second_pro); return; } // realign axis 3 Point3f new_third_pro = plane.Projection(Inverse(rotation).Rotate(third));// axis 3 projection after the first rotation assert(old_third_pro.Norm() > EPSILON ); // old axis 3 projection should not be null // align axis 3 projection after the first rotation to old axis 3 projection old_third_pro.Normalize(); RotateToAlign(new_third_pro,old_third_pro); } void MovableCoordinateFrame::Move(const Similarityf track) { position = position + track.tra; rotation = rotation * Inverse(track.rot); } void MovableCoordinateFrame::RotateToAlign(const Point3f source, const Point3f dest) { const float EPSILON=1e-6f; // source and dest must be versors assert( math::Abs(source.Norm() - 1) < EPSILON); assert( math::Abs(dest.Norm() - 1) < EPSILON); Point3f axis = dest ^ source; float sinangle = axis.Norm(); float cosangle = dest * source; float angle = math::Atan2(sinangle,cosangle); if( math::Abs(angle) < EPSILON ) return; // angle ~ 0, aborting if( math::Abs(math::Abs(angle)-M_PI) < EPSILON){ // must find a axis to flip on Plane3f plane(0,source); axis=plane.Projection(Point3f(1,0,0)); // project a "random" point on source's normal plane if(axis.Norm() < EPSILON){ // source was ~ [1,0,0]... axis=plane.Projection(Point3f(0,1,0)); assert(axis.Norm() > EPSILON); // this point must be good } } rotation = rotation * Quaternionf(angle,axis); }