Customization of the select()
function that enables the selection of several
objects.
Object selection is preformed using the left mouse button. Press Shift to add objects to the selection, and Control to remove objects from the selection.
Individual objects as well as rectangular regions can be selected (click and drag mouse). To do
this, the selection region size is modified and the endSelection()
function has been
overloaded so that all the objects of the region are taken into account.
Arbitrary operations can then easily be applied to the selected objects : parameter edition, displacement, deletion...
#include "QGLViewer/qglviewer.h" class Sphere { public : void setPos(const qglviewer::Vec& pos) { pos_ = pos; }; void draw() const; private: qglviewer::Vec pos_; }; class Viewer : public QGLViewer { public: Viewer(); protected : virtual void draw(); virtual void init(); virtual QString helpString() const; // Selection functions virtual void drawWithNames(); virtual void endSelection(const QPoint&); // Mouse events functions virtual void mousePressEvent(QMouseEvent *e); virtual void mouseMoveEvent(QMouseEvent *e); virtual void mouseReleaseEvent(QMouseEvent *e); private : void drawSelectionRectangle() const; void addIdToSelection(int id); void removeIdFromSelection(int id); // Current rectangular selection QRect rectangle_; // Different selection modes enum SelectionMode { NONE, ADD, REMOVE }; SelectionMode selectionMode_; #if QT_VERSION < 0x040000 // Objects of the scene QValueVector<Sphere> sphere_; // ids of the selected objects QValueList<int> selection_; #else QList<Sphere> sphere_; QList<int> selection_; #endif };
#include "multiSelect.h" using namespace qglviewer; using namespace std; Viewer::Viewer() { selectionMode_ = NONE; // Fill the scene with spheres positionned on a regular grid. // Consider increasing selectBufferSize() if you use more spheres. const int nb = 10; for (int i=-nb; i<=nb; ++i) for (int j=-nb; j<=nb; ++j) { Sphere s; s.setPos(Vec(i/float(nb), j/float(nb), 0.0f)); sphere_.push_back(s); } } void Viewer::init() { glBlendFunc(GL_ONE, GL_ONE); restoreStateFromFile(); help(); } QString Viewer::helpString() const { QString text("<h2>m u l t i S e l e c t </h2>"); text += "This example illustrates an application of the <code>select()</code> function that "; text += "enables the selection of several objects.<br><br>"; text += "Object selection is preformed using the left mouse button. Press <b>Shift</b> to add objects "; text += "to the selection, and <b>Control</b> to remove objects from the selection.<br><br>"; text += "Individual objects as well as rectangular regions can be selected (click and drag mouse)."; text += "To do this, the selection region size is modified and the <code>endSelection()</code> function "; text += "has been overloaded so that <i>all</i> the objects of the region are taken into account "; text += "(default implementation only selects the closest object).<br><br>"; text += "Arbitrary operations can then easily be applied to the selected objects : parameter edition, "; text += "displacement, deletion..."; return text; } // D r a w i n g f u n c t i o n void Viewer::draw() { // Draw selected spheres only. glColor3f(0.9, 0.3, 0.3); #if QT_VERSION < 0x040000 for (QValueList<int>::const_iterator it=selection_.begin(), end=selection_.end(); it != end; ++it) #else for (QList<int>::const_iterator it=selection_.begin(), end=selection_.end(); it != end; ++it) #endif sphere_[*it].draw(); // Draw all the spheres. Selected ones are not repainted because of GL depth test. glColor3f(0.8, 0.8, 0.8); #if QT_VERSION < 0x040000 for (QValueVector<Sphere>::const_iterator it=sphere_.begin(), end=sphere_.end(); it != end; ++it) #else for (QList<Sphere>::const_iterator it=sphere_.begin(), end=sphere_.end(); it != end; ++it) #endif (*it).draw(); // Draw rectangular selection area. Could be done in postDraw() instead. if (selectionMode_ != NONE) drawSelectionRectangle(); } // C u s t o m i z e d m o u s e e v e n t s void Viewer::mousePressEvent(QMouseEvent* e) { // Start selection. Mode is ADD with Shift key and TOGGLE with Control key. rectangle_ = QRect(e->pos(), e->pos()); #if QT_VERSION < 0x040000 if ((e->button() == Qt::LeftButton) && (e->state() == Qt::ShiftButton)) #else if ((e->button() == Qt::LeftButton) && (e->modifiers() == Qt::ShiftModifier)) #endif selectionMode_ = ADD; else #if QT_VERSION < 0x040000 if ((e->button() == Qt::LeftButton) && (e->state() == Qt::ControlButton)) #else if ((e->button() == Qt::LeftButton) && (e->modifiers() == Qt::ControlModifier)) #endif selectionMode_ = REMOVE; else QGLViewer::mousePressEvent(e); } void Viewer::mouseMoveEvent(QMouseEvent* e) { if (selectionMode_ != NONE) { // Updates rectangle_ coordinates and redraws rectangle #if QT_VERSION < 0x030000 rectangle_.setX(e->x()); rectangle_.setY(e->y()); #else rectangle_.setBottomRight(e->pos()); #endif updateGL(); } else QGLViewer::mouseMoveEvent(e); } void Viewer::mouseReleaseEvent(QMouseEvent* e) { if (selectionMode_ != NONE) { // Actual selection on the rectangular area. // Possibly swap left/right and top/bottom to make rectangle_ valid. #if QT_VERSION < 0x040000 rectangle_ = rectangle_.normalize(); #else rectangle_ = rectangle_.normalized(); #endif // Define selection window dimensions setSelectRegionWidth(rectangle_.width()); setSelectRegionHeight(rectangle_.height()); // Compute rectangle center and perform selection select(rectangle_.center()); // Update display to show new selected objects updateGL(); } else QGLViewer::mouseReleaseEvent(e); } // C u s t o m i z e d s e l e c t i o n p r o c e s s void Viewer::drawWithNames() { #if QT_VERSION < 0x040000 for (unsigned int i=0; i<sphere_.size(); ++i) #else for (int i=0; i<sphere_.size(); ++i) #endif { glPushName(i); sphere_[i].draw(); glPopName(); } } void Viewer::endSelection(const QPoint&) { // Flush GL buffers glFlush(); // Get the number of objects that were seen through the pick matrix frustum. Reset GL_RENDER mode. GLint nbHits = glRenderMode(GL_RENDER); if (nbHits > 0) { // Interpret results : each object created 4 values in the selectBuffer(). // (selectBuffer())[4*i+3] is the id pushed on the stack. for (int i=0; i<nbHits; ++i) switch (selectionMode_) { case ADD : addIdToSelection((selectBuffer())[4*i+3]); break; case REMOVE : removeIdFromSelection((selectBuffer())[4*i+3]); break; default : break; } } selectionMode_ = NONE; } // S e l e c t i o n t o o l s void Viewer::addIdToSelection(int id) { if (!selection_.contains(id)) selection_.push_back(id); } void Viewer::removeIdFromSelection(int id) { #if QT_VERSION < 0x040000 selection_.remove(id); #else selection_.removeAll(id); #endif } void Viewer::drawSelectionRectangle() const { startScreenCoordinatesSystem(); glDisable(GL_LIGHTING); glEnable(GL_BLEND); glColor4f(0.0, 0.0, 0.3, 0.3); glBegin(GL_QUADS); glVertex2i(rectangle_.left(), rectangle_.top()); glVertex2i(rectangle_.right(), rectangle_.top()); glVertex2i(rectangle_.right(), rectangle_.bottom()); glVertex2i(rectangle_.left(), rectangle_.bottom()); glEnd(); glLineWidth(2.0); glColor4f(0.4, 0.4, 0.5, 0.5); glBegin(GL_LINE_LOOP); glVertex2i(rectangle_.left(), rectangle_.top()); glVertex2i(rectangle_.right(), rectangle_.top()); glVertex2i(rectangle_.right(), rectangle_.bottom()); glVertex2i(rectangle_.left(), rectangle_.bottom()); glEnd(); glDisable(GL_BLEND); glEnable(GL_LIGHTING); stopScreenCoordinatesSystem(); } // T h e S p h e r e c l a s s void Sphere::draw() const { static GLUquadric* quad = gluNewQuadric(); glPushMatrix(); glTranslatef(pos_.x, pos_.y, pos_.z); gluSphere(quad, 0.03, 10, 6); glPopMatrix(); }
#include "multiSelect.h" #include <qapplication.h> int main(int argc, char** argv) { // Read command lines arguments. QApplication application(argc,argv); // Create a viewer, show it on screen. Viewer viewer; viewer.show(); #if QT_VERSION < 0x040000 // Set the viewer as the application's main widget. application.setMainWidget(&viewer); #endif // Run main loop. return application.exec(); }
Back to the examples main page.