You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
370 lines
12 KiB
370 lines
12 KiB
/**************************************************************************** |
|
* 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 <GL/glew.h> |
|
#include <wrap/gl/math.h> |
|
#include <wrap/gl/space.h> |
|
#include <wrap/gl/addons.h> |
|
#include <wrap/qt/gl_label.h> |
|
|
|
#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,QPainter* p) |
|
{ |
|
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); |
|
glLabel::Mode md; |
|
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){ |
|
md.qFont.setBold(true); |
|
md.qFont.setPixelSize(12); |
|
float d=size+scalefactor*linewidth*1.5; |
|
if (p) { |
|
vcg::glLabel::render(p,vcg::Point3f(d,0,0),QString("X"),md); |
|
vcg::glLabel::render(p,vcg::Point3f(0,d,0),QString("Y"),md); |
|
vcg::glLabel::render(p,vcg::Point3f(0,0,d),QString("Z"),md); |
|
} |
|
} |
|
if(drawvalues){ |
|
md.qFont.setBold(false); |
|
md.qFont.setPixelSize(8); |
|
md.color=Color4b(Color4b::LightGray); |
|
float i; |
|
glColor(Color4b(Color4b::LightGray)); |
|
for(i=slope_a;i<size;i+=slope_a){ |
|
vcg::glLabel::render(p,vcg::Point3f( i,0,0),QString(" %1").arg(i,3,'f',1),md); |
|
vcg::glLabel::render(p,vcg::Point3f(-i,0,0),QString(" %1").arg(i,3,'f',1),md); |
|
} |
|
for(i=slope_b;i<size;i+=slope_b){ |
|
vcg::glLabel::render(p,vcg::Point3f(0, i,0),QString(" %1").arg(i,3,'f',1),md); |
|
vcg::glLabel::render(p,vcg::Point3f(0,-i,0),QString(" %1").arg(i,3,'f',1),md); |
|
} |
|
for(i=slope_c;i<size;i+=slope_c){ |
|
vcg::glLabel::render(p,vcg::Point3f(0,0, i),QString(" %1").arg(i,3,'f',1),md); |
|
vcg::glLabel::render(p,vcg::Point3f(0,0,-i),QString(" %1").arg(i,3,'f',1),md); |
|
} |
|
} |
|
glGetError(); // Patch to buggy qt rendertext; |
|
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<dim;i+=tickDist) |
|
glVertex3f(a[0] + i*v[0],a[1] + i*v[1],a[2] + i*v[2]); |
|
glEnd(); |
|
|
|
glPushAttrib(GL_POINT_BIT); |
|
glPointSize(linewidth*3); |
|
glBegin(GL_POINTS); |
|
glVertex3f(a[0] + dim*v[0],a[1] + dim*v[1],a[2] + dim*v[2]); |
|
glEnd(); |
|
|
|
glPopAttrib(); |
|
} |
|
|
|
float CoordinateFrame::calcSlope(const Point3d &a,const Point3d &b,float dim,int spacing,double *mm,double *mp,GLint *vp) |
|
{ |
|
Point3d p1,p2; |
|
|
|
gluProject(a[0],a[1],a[2],mm,mp,vp,&p1[0],&p1[1],&p1[2]); |
|
gluProject(b[0],b[1],b[2],mm,mp,vp,&p2[0],&p2[1],&p2[2]); |
|
p1[2]=p2[2]=0; |
|
|
|
float tickNum = spacing/Distance(p2,p1);// pxl spacing |
|
float slope = dim*tickNum; |
|
float nslope = math::Min(niceRound(slope), 0.5f*niceRound(2.0f*slope), 0.2f*niceRound(5.0f*slope)); |
|
nslope = std::max(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, QPainter *p) |
|
{ |
|
glPushMatrix(); |
|
|
|
glTranslate(position); |
|
Matrix44f mrot; |
|
rotation.ToMatrix(mrot); |
|
|
|
glMultMatrix(Inverse(mrot)); |
|
|
|
CoordinateFrame::Render(gla,p); |
|
|
|
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(math::ToRad(angle_deg),(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.dot(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); |
|
}
|
|
|