diff --git a/wrap/gui/coordinateframe.cpp b/wrap/gui/coordinateframe.cpp new file mode 100644 index 00000000..27fed4ed --- /dev/null +++ b/wrap/gui/coordinateframe.cpp @@ -0,0 +1,591 @@ +/**************************************************************************** + * 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 $ + +****************************************************************************/ + +#include +#include +#include +#include + +#include "coordinateframe.h" + +using namespace vcg; + + + +CoordinateFrame::CoordinateFrame(float s) +://QObject(), +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); + // assi positivi + 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 + //assi negativi + 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(10); + glColor(xcolor); + glw->renderText(size+(scalefactor*3),0,0,QString("X"),font); + glColor(ycolor); + glw->renderText(0,size+(scalefactor*3),0,QString("Y"),font); + glColor(zcolor); + glw->renderText(0,0,size+(scalefactor*3),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(mrot); + + CoordinateFrame::Render(gla); + + glPopMatrix(); +} + +void MovableCoordinateFrame::GetTransform(Matrix44f & transform) +{ + // costruisco la matrice che porta le coordinate in spazio di mondo + + // resetto la trasf + transform.SetIdentity(); + + // ruoto + Matrix44f rot; + rotation.ToMatrix(rot); + + transform = rot * transform ; + + // sposto in posizione + 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::Flip(const Point3f axis) +{ + Similarityf s; + s.SetRotate(M_PI,Inverse(rotation).Rotate(axis)); + Move(s); +} + +void MovableCoordinateFrame::AlignWith(const Point3f pri,const Point3f secondary) +{ + const float EPSILON=1e-6; + Point3f primary=pri; + + if( primary.Norm() < EPSILON*size ) + return; + + primary.Normalize(); // ho l'asse primario, lo normalizzo + Plane3f plane(0,primary); // piano di proiezione per la seconda rotazione + Point3f old_z = Inverse(rotation).Rotate(Point3f(0,0,1)); // l'asse z + Point3f old_y_pro = plane.Projection(Inverse(rotation).Rotate(Point3f(0,1,0))); //la proiezione dell'asse y + Point3f old_x_pro = plane.Projection(Inverse(rotation).Rotate(Point3f(1,0,0))); //la proiezione dell'asse x + + // allinea l'asse z corrente all'asse primary + RotateToAlign(old_z,primary); // prima rotazione + + Point3f secondary_pro = plane.Projection(secondary); // la proiezione di secondary + Point3f new_y_pro = plane.Projection(Inverse(rotation).Rotate(Point3f(0,1,0))); // la proiezione dell'asse y dopo la prima rotazione + + // se c'e` un asse secondary e la sua proiezione non e` 0 + if( secondary.Norm() > EPSILON*size && secondary_pro.Norm() > EPSILON ){ + // allinea la proiezione dell'asse y dopo la prima rotazione alla proiezione dell'asse secondary + secondary_pro.Normalize(); + RotateToAlign(new_y_pro,secondary_pro); + return; + } + // creco di riallineare la y + if ( old_y_pro.Norm() > EPSILON ) { + // allinea la proiezione dell'asse y dopo la prima rotazione alla proiezione dell'asse y + old_y_pro.Normalize(); + RotateToAlign(new_y_pro,old_y_pro); + return; + } + // cerco di riallineare la x + Point3f new_x_pro = plane.Projection(Inverse(rotation).Rotate(Point3f(1,0,0))); //la proiezione dell'asse x dopo la prima rotazione + assert(old_x_pro.Norm() > EPSILON ); // la proiezione dell'asse x non dovrebbe essere 0 + // allinea la proiezione dell'asse x dopo la prima rotazione alla proiezione dell'asse x + old_x_pro.Normalize(); + RotateToAlign(new_x_pro,old_x_pro); +} + +void MovableCoordinateFrame::Move(const Similarityf track) +{ + position = position + track.tra; + rotation = rotation * track.rot; +} + +void MovableCoordinateFrame::RotateToAlign(const Point3f source, const Point3f dest) +{ + const float EPSILON=1e-6; + // source e dest devono essere versori + 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; // angolo ~ 0, annullo + + if( math::Abs(math::Abs(angle)-M_PI) < EPSILON){ + // devo trovare un asse su cui flippare + Plane3f plane(0,source); + axis=plane.Projection(Point3f(1,0,0)); // proietto un punto a caso sul piano normale a source + if(axis.Norm() < EPSILON){ // source era ~ [1,0,0]... + axis=plane.Projection(Point3f(0,1,0)); + assert(axis.Norm() > EPSILON); // quest'altro punto deve andare bene + } + } + rotation = rotation * Quaternionf(angle,axis); +} + +ActiveCoordinateFrame::ActiveCoordinateFrame(float size) +:MovableCoordinateFrame(size),manipulator(NULL),drawmoves(true), +drawrotations(true), +movx(Trackball::BUTTON_RIGHT ), +movy(Trackball::BUTTON_RIGHT | Trackball::KEY_CTRL), +movz(Trackball::BUTTON_RIGHT | Trackball::KEY_SHIFT), +rotx(Trackball::BUTTON_LEFT), +roty(Trackball::BUTTON_LEFT | Trackball::KEY_CTRL), +rotz(Trackball::BUTTON_LEFT | Trackball::KEY_SHIFT), +x_axis(1,0,0),y_axis(0,1,0),z_axis(0,0,1),rot_snap_rad(0.0f),mov_snap(0.0f) +{ + manipulator=new Trackball(); + std::map::iterator it; + for(it = manipulator->modes.begin(); it != manipulator->modes.end(); it++) + { + if ((*it).second) + delete (*it).second; + } + manipulator->modes.clear(); + manipulator->modes[0] = NULL; + Update(); + } + +ActiveCoordinateFrame::~ActiveCoordinateFrame() +{ + if(manipulator!=NULL) { + delete manipulator; + manipulator=NULL; + } +} + +void ActiveCoordinateFrame::Render(QGLWidget* glw) +{ + glPushMatrix(); //occhio + + manipulator->radius=size; + manipulator->center=position; + manipulator->GetView(); + manipulator->Apply(false); + + MovableCoordinateFrame::Render(glw); + + // non devo disegnare + if(!drawmoves && !drawrotations){ + glPopMatrix(); //occhio + return; + } + + int current_mode=manipulator->current_button; + bool rotating=(current_mode==rotx)||(current_mode==roty)||(current_mode==rotz); + bool moving=(current_mode==movx)||(current_mode==movy)||(current_mode==movz); + + // non sto draggando o sto draggando quello che non devo disengnare + if( (!rotating && !moving)|| + (!((rotating && drawrotations)||(moving && drawmoves))) + ){ + glPopMatrix(); //occhio + return; + } + + // sto draggando e devo disegnare qualcosa + 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); + + Color4b color; + QString message; + char axis_name; + float verse; + if(rotating && drawrotations){ // devo disegnare una rotazione + Point3f axis, arc_point; + float angle; + manipulator->track.rot.ToAxis(angle,axis); + if(current_mode==rotx){ + verse=((axis+x_axis).Norm()<1?-1:1); + color=xcolor; axis_name='x'; arc_point=y_axis*(size*0.8); + } else if(current_mode==roty) { + verse=((axis+y_axis).Norm()<1?-1:1); + color=ycolor; axis_name='y'; arc_point=z_axis*(size*0.8); + } else if(current_mode==rotz) { + verse=((axis+z_axis).Norm()<1?-1:1); + color=zcolor; axis_name='z'; arc_point=x_axis*(size*0.8); + } else assert(0); // doveva essere una rotazione + // normalizzo la rotazione a [-180,180] + float sign = ((angle*verse)<0) ? -1 : 1; + float abs_angle = (angle<0) ? -angle : angle; + angle = sign * ( (abs_angle>M_PI) ? 2*M_PI-abs_angle : abs_angle ); + axis = axis * verse; + message = QString("rotated %1 deg around %2") + .arg(((angle*180.0)/M_PI),5,'f',3) + .arg(axis_name); + Quaternionf arc_rot; + arc_rot.FromAxis(angle/18.0,axis); + glColor(color); + glBegin(GL_POLYGON); + glVertex(position); + glVertex(position+arc_point); + for(int i=0;i<18;i++){ + arc_point = arc_rot.Rotate(arc_point); + glVertex(position+arc_point); + } + glEnd(); + } else if(moving && drawmoves){// devo disegnare una traslazione + Point3f ntra=manipulator->track.tra; + ntra.Normalize(); + if(current_mode==movx){ + verse=((ntra+x_axis).Norm()<1?-1:1); + color=xcolor; axis_name='x'; + }else if(current_mode==movy){ + verse=((ntra+y_axis).Norm()<1?-1:1); + color=ycolor; axis_name='y'; + }else if(current_mode==movz){ + verse=((ntra+z_axis).Norm()<1?-1:1); + color=zcolor; axis_name='z'; + }else assert(0); // doveva essere una traslazione + message = QString("moved %1 units along %2") + .arg(verse*manipulator->track.tra.Norm(),5,'f',3) + .arg(axis_name); + Point3f old_pos = position-manipulator->track.tra; + glLineWidth(2*linewidth); + glPointSize(4*linewidth); + glColor(color); + glBegin(GL_LINES); + glVertex(position); + glVertex(old_pos); + glEnd(); + glBegin(GL_POINTS); + glVertex(old_pos); + glEnd(); + } else assert(0); // qualcosa lo dovevo disegnare + // disegno la stringa + font.setBold(true); + font.setPixelSize(12); + glw->renderText(cursor.x()+16,cursor.y()+16,message,font); + + glPopAttrib(); + glPopMatrix(); //occhio +} + + +void ActiveCoordinateFrame::Reset(bool reset_position,bool reset_alignment) +{ + MovableCoordinateFrame::Reset(reset_position, reset_alignment); + Update(); + manipulator->Reset(); +} + +void ActiveCoordinateFrame::SetPosition(const Point3f newpos) +{ + MovableCoordinateFrame::SetPosition(newpos); + Update(); + manipulator->Reset(); +} + +void ActiveCoordinateFrame::SetRotation(const Quaternionf newrot) +{ + MovableCoordinateFrame::SetRotation(newrot); + Update(); + manipulator->Reset(); +} + +void ActiveCoordinateFrame::AlignWith(const Point3f primary,const Point3f secondary=Point3f(0,0,0)) +{ + MovableCoordinateFrame::AlignWith(primary,secondary); + Update(); + manipulator->Reset(); +} + +void ActiveCoordinateFrame::MouseDown(QPoint c,int x, int y, /*Button*/ int button) +{ + cursor=c; + Move(manipulator->track); + manipulator->Reset(); + manipulator->MouseDown(x,y,button); +} + +void ActiveCoordinateFrame::MouseMove(QPoint c,int x, int y) +{ + cursor=c; + manipulator->MouseMove(x,y); +} + +void ActiveCoordinateFrame::MouseUp(int x, int y, /*Button */ int button) +{ + Move(manipulator->track); + manipulator->Reset(); + manipulator->MouseUp(x, y, button); +} + +void ActiveCoordinateFrame::ButtonUp(int button) +{ + Move(manipulator->track); + manipulator->Reset(); + manipulator->ButtonUp((Trackball::Button) button); +} + +void ActiveCoordinateFrame::ButtonDown(int button) +{ + Move(manipulator->track); + manipulator->Reset(); + manipulator->ButtonDown((Trackball::Button) button); +} + +void ActiveCoordinateFrame::SetSnap(float rot_deg) +{ + assert((rot_deg>=0.0)&&(rot_deg<=180)); + rot_snap_rad=rot_deg*M_PI/180.0; + Update(); +} + +void ActiveCoordinateFrame::Move(const Similarityf track) +{ + MovableCoordinateFrame::Move(track); + Update(); +} + +void ActiveCoordinateFrame::Update() +{ + Point3f p=position; + Quaternionf r=Inverse(rotation); + x_axis=r.Rotate(Point3f(1,0,0)); + y_axis=r.Rotate(Point3f(0,1,0)); + z_axis=r.Rotate(Point3f(0,0,1)); + + if(manipulator->modes[movx]!=NULL) + delete manipulator->modes[movx]; + manipulator->modes[movx] = new AxisMode(p,x_axis); + + if(manipulator->modes[movy]!=NULL) + delete manipulator->modes[movy]; + manipulator->modes[movy] = new AxisMode(p,y_axis); + + if(manipulator->modes[movz]!=NULL) + delete manipulator->modes[movz]; + manipulator->modes[movz] = new AxisMode(p,z_axis); + + if(manipulator->modes[rotx]!=NULL) + delete manipulator->modes[rotx]; + manipulator->modes[rotx] = new CylinderMode(p,x_axis,rot_snap_rad); + + if(manipulator->modes[roty]!=NULL) + delete manipulator->modes[roty]; + manipulator->modes[roty] = new CylinderMode(p,y_axis,rot_snap_rad); + + if(manipulator->modes[rotz]!=NULL) + delete manipulator->modes[rotz]; + manipulator->modes[rotz] = new CylinderMode(p,z_axis,rot_snap_rad); + + manipulator->SetCurrentAction(); +} diff --git a/wrap/gui/coordinateframe.h b/wrap/gui/coordinateframe.h new file mode 100644 index 00000000..04da7cb1 --- /dev/null +++ b/wrap/gui/coordinateframe.h @@ -0,0 +1,134 @@ +/**************************************************************************** + * 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 $ + +****************************************************************************/ +#ifndef COORDINATEFRAME_H +#define COORDINATEFRAME_H + + +#include +#include + +#include + +#include +#include + +namespace vcg { + +class CoordinateFrame//: public QObject +{ +// Q_OBJECT + +public: + // functions: + CoordinateFrame(float); + virtual ~CoordinateFrame() {} + virtual void Render(QGLWidget*); + // data + Color4b basecolor; + Color4b xcolor; + Color4b ycolor; + Color4b zcolor; + float size; + float linewidth; + QFont font; + bool drawaxis; + bool drawlabels; + bool drawvalues; + +protected: + // functions: + void drawTickedLine(const Point3d &, const Point3d &, float, float,float); + float calcSlope(const Point3d &, const Point3d &, float, int , double *, double *, GLint *); + float niceRound(float); +}; + +class MovableCoordinateFrame: public CoordinateFrame +{ +// Q_OBJECT + +public: + MovableCoordinateFrame(float); + virtual ~MovableCoordinateFrame(){} + virtual void Render(QGLWidget*); + virtual void Reset(bool ,bool); + virtual void SetPosition(const Point3f); + virtual void SetRotation(const Quaternionf); + virtual Point3f GetPosition(); + virtual Quaternionf GetRotation(); + virtual void GetTransform(Matrix44f &); + virtual void Flip(const Point3f); + virtual void AlignWith(const Point3f, const Point3f); + +protected: + // data: + Point3f position; + Quaternionf rotation; + + // functions: + virtual void Move(const Similarityf); + void RotateToAlign(const Point3f, const Point3f); + +}; + +class ActiveCoordinateFrame: public MovableCoordinateFrame +{ +// Q_OBJECT + +public: + ActiveCoordinateFrame(float); + virtual ~ActiveCoordinateFrame(); + virtual void Render(QGLWidget*); + virtual void Reset(bool, bool); + virtual void SetPosition(const Point3f); + virtual void SetRotation(const Quaternionf); + virtual void AlignWith(const Point3f, const Point3f); + void MouseDown(QPoint,int, int, int); + void MouseMove(QPoint,int, int); + void MouseUp(int, int, int); + void ButtonUp(int); + void ButtonDown(int); + void SetSnap(float); + + Trackball *manipulator; + bool drawmoves; + bool drawrotations; +protected: + // data: + const int movx,movy,movz,rotx,roty,rotz; + Point3f x_axis,y_axis,z_axis; + float rot_snap_rad,mov_snap; + QPoint cursor; + + // functions: + virtual void Move(const Similarityf); + void Update(); + +}; + +}//namespace +#endif /*COORDINATEFRAME_H*/ diff --git a/wrap/gui/rubberband.cpp b/wrap/gui/rubberband.cpp new file mode 100644 index 00000000..ed806529 --- /dev/null +++ b/wrap/gui/rubberband.cpp @@ -0,0 +1,240 @@ +/**************************************************************************** + * 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 $ + +****************************************************************************/ + +#include +#include +#include + +#include "rubberband.h" + +using namespace vcg; + +Rubberband::Rubberband(Color4b c) +:color(c),currentphase(RUBBER_BEGIN),qt_cursor(), +start(0,0,0),end(0,0,0),have_to_pick(false),font() +{ + font.setFamily("Helvetica"); + font.setPixelSize(10); +} + +void Rubberband::Render(QGLWidget* gla) +{ + if(have_to_pick){ + assert(currentphase!=RUBBER_DRAGGED); + Point3f pick_point; + bool picked = Pick(qt_cursor.x(), gla->height() - qt_cursor.y(), pick_point); + if(picked){ // we have not picked the background + have_to_pick=false; + switch(currentphase){ + case RUBBER_BEGIN: + start = pick_point; + gla->setMouseTracking(true); + currentphase = RUBBER_DRAGGING; + break; + case RUBBER_DRAGGING: + if(pick_point==start){ + have_to_pick=true; + break; + } + end = pick_point; + gla->setMouseTracking(false); + currentphase = RUBBER_DRAGGED; + break; + default: + assert(0); + } + } + } + + if(currentphase==RUBBER_BEGIN) return; + + // Drawing of the current line + glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + glDepthMask(false); + glLineWidth(2.5); + glPointSize(5.0); + if(currentphase==RUBBER_DRAGGING ) { + Point3f qt_start_point; + qt_start_point = PixelConvert(start); + glColor(color); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(0,gla->width(),gla->height(),0); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glDisable(GL_DEPTH_TEST); + glBegin(GL_LINES); + glVertex2f(qt_start_point[0],qt_start_point[1]); + glVertex2f(qt_cursor.x(),qt_cursor.y()); + glEnd(); + glEnable(GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + } else { + assert(currentphase == RUBBER_DRAGGED); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_LINE_SMOOTH); + glEnable(GL_POINT_SMOOTH); + glColor(color); + glBegin(GL_LINES); + glVertex(start); + glVertex(end); + glEnd(); + glBegin(GL_POINTS); + glVertex(start); + glVertex(end); + glEnd(); + glDisable(GL_DEPTH_TEST); + glLineWidth(0.7); + glPointSize(1.4); + glBegin(GL_LINES); + glVertex(start); + glVertex(end); + glEnd(); + glBegin(GL_POINTS); + glVertex(start); + glVertex(end); + glEnd(); + } + glPopAttrib(); + assert(!glGetError()); +} + +void Rubberband::Drag(QPoint p) +{ + if(currentphase==RUBBER_DRAGGING); + qt_cursor=p; +} + +void Rubberband::Pin(QPoint p) +{ + if(IsReady()) + return; + qt_cursor=p; + have_to_pick=true; +} + +void Rubberband::Reset() +{ + currentphase = RUBBER_BEGIN; + qt_cursor = QPoint(); + start = Point3f(0,0,0); + end = Point3f(0,0,0); + have_to_pick = false; +} + +bool Rubberband::IsReady() +{ + return currentphase==RUBBER_DRAGGED; +} + +void Rubberband::GetPoints(Point3f &s,Point3f &e) +{ + assert(IsReady()); + s=start; + e=end; +} + +void Rubberband::RenderLabel(QString text,QGLWidget* gla) +{ + if(currentphase==RUBBER_BEGIN) return; + + int x,y; + if(currentphase==RUBBER_DRAGGING){ + x=qt_cursor.x()+16; + y=qt_cursor.y()+16; + } else { + Point3f qt_start = PixelConvert(start); + Point3f qt_end = PixelConvert(end); + if(qt_start[0]>qt_end[0]){ + x=int(qt_start[0]+5); + y=int(qt_start[1]); + }else{ + x=int(qt_end[0]+5); + y=int(qt_end[1]); + } + } + + QFontMetrics fm(font); + QRect brec=fm.boundingRect(text); + glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT ); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D(0,gla->width(),gla->height(),0); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glColor4f(0,0,0,0.5); + glBegin(GL_QUADS); + glVertex2f(x+brec.left(),y+brec.bottom()); + glVertex2f(x+brec.right(),y+brec.bottom()); + glVertex2f(x+brec.right(),y+brec.top()); + glVertex2f(x+brec.left(),y+brec.top()); + glEnd(); + int offset=2; + glColor4f(0,0,0,0.2); + glBegin(GL_QUADS); + glVertex2f(x+brec.left()-offset,y+brec.bottom()+offset); + glVertex2f(x+brec.right()+offset,y+brec.bottom()+offset); + glVertex2f(x+brec.right()+offset,y+brec.top()-offset); + glVertex2f(x+brec.left()-offset,y+brec.top()-offset); + glEnd(); + glColor3f(1,1,1); + gla->renderText(x,y,0.99f,text,font); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); +} + +Point3f Rubberband::PixelConvert(const Point3f p) +{ + GLint vm[4]; + GLdouble mm[16]; + GLdouble pm[16]; + glGetIntegerv(GL_VIEWPORT, vm); + glGetDoublev(GL_MODELVIEW_MATRIX, mm); + glGetDoublev(GL_PROJECTION_MATRIX, pm); + GLdouble wx,wy,wz; + gluProject(p[0], p[1], p[2], mm, pm, vm, &wx, &wy, &wz); + return Point3f(wx,vm[3]-wy,wz); +} diff --git a/wrap/gui/rubberband.h b/wrap/gui/rubberband.h new file mode 100644 index 00000000..b5bbdb65 --- /dev/null +++ b/wrap/gui/rubberband.h @@ -0,0 +1,70 @@ +/**************************************************************************** + * 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 $ + +****************************************************************************/ +#ifndef RUBBERBAND_H +#define RUBBERBAND_H + +#include +#include + +namespace vcg { + +class Rubberband +{ +public: + //data: + Color4b color; + // functions: + Rubberband(Color4b); + virtual ~Rubberband() {} + void Render(QGLWidget*); + void Drag(QPoint); + void Pin(QPoint); + void Reset(); + bool IsReady(); + void GetPoints(Point3f &,Point3f &); + void RenderLabel(QString text,QGLWidget* gla); +private: + // types: + typedef enum { RUBBER_BEGIN = 0, + RUBBER_DRAGGING = 1, + RUBBER_DRAGGED = 2, + } RubberPhase; + // data: + RubberPhase currentphase; + QPoint qt_cursor; + Point3f start, end; + bool have_to_pick; + QFont font; + // functions: + Point3f PixelConvert(const Point3f); + +}; + +}//namespace + +#endif /*RUBBERBAND_H*/