基于QGLViewer实现的点云显示、框选(实例)

生活中处处面临着狗血的选择,如果你是个很吸引人的青年,你会发现身边有很多选择,但做出选择往往是很难的。
        而且大家有时候只能看,不能选,因为不会选,选错了你就完蛋了。
        如果这时候你会选了,选对了,就不用一个人过节了。
        好,那么今天讲一下究竟怎么选,怎么选才能得到你想要的。
        (大家准备好鸡蛋)
        其实点云的选择问题并不难。
        只是大家有时候没有好好钻。
        笔者基于QGLVewer简单做了一下点云的读取、显示、还有框选。(别扔脸,哎...哎...)
        那么工程的代码采用的是QtainRibbon风格的QT界面,也是非常给力的。所有代码分享到置顶博客的网盘中了。大家自行去下载即可,名字叫NinRibbonCloud。我就不往CSDN上弄了,太麻烦了,还收你积分,有空我会好好研究GitHub的用法。。。。
https://me.csdn.net/qq_30547073 博客在这里。
废话不多说。
首先我们会看到QGLVewer的官方例子里面,有一个MultSelect,它在上面那个图里面。对,这就是原始的例子。我们要改成自己想要的。

基于QGLViewer实现的点云显示、框选(实例)_第1张图片
首先是object。主要绘制就绘制这个object,右边两行注释是原有的,我改成绘制点云了。
基于QGLViewer实现的点云显示、框选(实例)_第2张图片

constrant 是用来约束相机的类,由于我们选完了之后还要让选择后的点云发生变化,比如说旋转,那么我们就用这个来控制。
基于QGLViewer实现的点云显示、框选(实例)_第3张图片
这张图片刚好能装下所有的代码。
那么重头戏还是在如何调用上。
新建一个类,继承自QGLVewer

#pragma once

#include "QGLViewer/qglviewer.h"

#include "object.h"

#include"../ExampleBase.h"

#include"MasterHeader.h"

class Example_MultiSelectViewer : public QGLViewer, public ExampleBase

{

public:

Example_MultiSelectViewer(QMainWindow *parent = 0);

void do_ClearSet();//清除所有当前的物体咯

void do_ReloadSet();//重新加载所有当前物体咯

void do_LoadCloud(VertexPositionColor* Cloudptr, int num);

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);

 

  virtual void TriggerOn() override;//=========继承的====

 

 

private:

  void startManipulation();

  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_;

 

  QList objects_;

  QList selection_;

};


然后是相应的CPP:
    整个的代码大致的流程是,上来构造函数初始化的时加载了所有的Object,就是绘制出来的那些小球。然后当你按住Shift的时候,就会启用selectmode = true;这时候拖动鼠标就会绘制出一个框框来。然后当你松手的时候就会调用mouseRelease以及select函数。所选择的东西的Index全部保存在私有的QList中。然后代码内将所有selectList中的点绘制成另一种颜色。也是很有趣的。
    不过这样写的缺点是,加载的点过多的时候就会很卡,想必是因为调用了过多次glBegin的问题。这一点应该是可以修改的。我们在最后还放了几个结果。

/****************************************************************************

#include "Example_multiSelect.h"

#include "manipulatedFrameSetConstraint.h"

#include

#include

using namespace qglviewer;

Example_MultiSelectViewer::Example_MultiSelectViewer(QMainWindow *parent) :ExampleBase(parent)

{

do_ReloadSet();

}

//确认不会报错

void Example_MultiSelectViewer::do_ClearSet()

{

selectionMode_ = NONE;

objects_.clear();

selection_.clear();

update();

}

void Example_MultiSelectViewer::do_ReloadSet()

{

do_ClearSet();

selectionMode_ = NONE;

// Fill the scene with objects positionned on a regular grid.

// Consider increasing selectBufferSize() if you use more objects.

const int nb = 10;

for (int i = -nb; i <= nb; ++i)

{

for (int j = -nb; j <= nb; ++j)

{

Object *o = new Object();

o->frame.setPosition(Vec(i / float(nb), j / float(nb), 0.0));

objects_.append(o);

}

}

update();

}

 

void Example_MultiSelectViewer::do_LoadCloud(VertexPositionColor* Cloudptr, int num)

{

do_ClearSet();

setSelectBufferSize(num);

selectionMode_ = NONE;

for (int i = 0; i < num; i++)

{

if (i % 20 != 0)continue;

VertexPositionColor pt = Cloudptr[i];

Object *o = new Object();

o->frame.setPosition(Vec(pt.x, pt.y, pt.z));

objects_.append(o);

}

/*camera()->setPosition(qglviewer::Vec(5, 5, 5));

camera()->lookAt(qglviewer::Vec(0, 0, 0));*/

update();

 

}

 

void Example_MultiSelectViewer::init() 

{

// A ManipulatedFrameSetConstraint will apply displacements to the selection

setManipulatedFrame(new qglviewer::ManipulatedFrame());

manipulatedFrame()->setConstraint(new ManipulatedFrameSetConstraint());

 

// Used to display semi-transparent relection rectangle

glBlendFunc(GL_ONE, GL_ONE);

 

restoreStateFromFile();

// help();

}
 

void Example_MultiSelectViewer::draw() {

  // Draws selected objects only.

  glColor3f(0.9f, 0.3f, 0.3f);

  for (QList::const_iterator it = selection_.begin(),

                                  end = selection_.end();

       it != end; ++it)

    objects_.at(*it)->draw();

 

  // Draws all the objects. Selected ones are not repainted because of GL depth

  // test.

  glColor3f(0.8f, 0.8f, 0.8f);

  for (int i = 0; i < int(objects_.size()); i++)

    objects_.at(i)->draw();

 

  // Draws manipulatedFrame (the set's rotation center)

  if (manipulatedFrame()->isManipulated()) {

    glPushMatrix();

    glMultMatrixd(manipulatedFrame()->matrix());

    drawAxis(0.5);

    glPopMatrix();

  }

 

  // Draws rectangular selection area. Could be done in postDraw() instead.

  if (selectionMode_ != NONE)

    drawSelectionRectangle();

}

 

void Example_MultiSelectViewer::mousePressEvent(QMouseEvent *e) {

  // Start selection. Mode is ADD with Shift key and TOGGLE with Alt key.

  rectangle_ = QRect(e->pos(), e->pos());

 

  if ((e->button() == Qt::LeftButton) && (e->modifiers() == Qt::ShiftModifier))

    selectionMode_ = ADD;

  else if ((e->button() == Qt::LeftButton) &&

           (e->modifiers() == Qt::AltModifier))

    selectionMode_ = REMOVE;

  else 

  {

    if (e->modifiers() == Qt::ControlModifier)

      startManipulation();

    QGLViewer::mousePressEvent(e);

  }

}

 

void Example_MultiSelectViewer::mouseMoveEvent(QMouseEvent *e) {

  if (selectionMode_ != NONE) 

  {

    // Updates rectangle_ coordinates and redraws rectangle

    rectangle_.setBottomRight(e->pos());

    update();

  } 

  else

    QGLViewer::mouseMoveEvent(e);

}

 

void Example_MultiSelectViewer::mouseReleaseEvent(QMouseEvent *e) {

  if (selectionMode_ != NONE) {

    // Actual selection on the rectangular area.

    // Possibly swap left/right and top/bottom to make rectangle_ valid.

    rectangle_ = rectangle_.normalized();

    // 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

    update();

  } else

    QGLViewer::mouseReleaseEvent(e);

}

void Example_MultiSelectViewer::drawWithNames() {

  for (int i = 0; i < int(objects_.size()); i++) {

    glPushName(i);

    objects_.at(i)->draw();

    glPopName();

  }

}

 

void Example_MultiSelectViewer::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;

}

 

void Example_MultiSelectViewer::startManipulation() {

  Vec averagePosition;

  ManipulatedFrameSetConstraint *mfsc =

      (ManipulatedFrameSetConstraint *)(manipulatedFrame()->constraint());

  mfsc->clearSet();

 

  for (QList::const_iterator it = selection_.begin(),

                                  end = selection_.end();

       it != end; ++it) {

    mfsc->addObjectToSet(objects_[*it]);

    averagePosition += objects_[*it]->frame.position();

  }

 

  if (selection_.size() > 0)

    manipulatedFrame()->setPosition(averagePosition / selection_.size());

}

 

//   S e l e c t i o n   t o o l s

 

void Example_MultiSelectViewer::addIdToSelection(int id) {

  if (!selection_.contains(id))

    selection_.push_back(id);

}

 

void Example_MultiSelectViewer::removeIdFromSelection(int id) { selection_.removeAll(id); }

 

void Example_MultiSelectViewer::drawSelectionRectangle() const {

  startScreenCoordinatesSystem();

  glDisable(GL_LIGHTING);

  glEnable(GL_BLEND);

 

  glColor4f(0.0, 0.0, 0.3f, 0.3f);

  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.4f, 0.4f, 0.5f, 0.5f);

  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();

}

 

void Example_MultiSelectViewer::TriggerOn()//=========继承的====

{

if (m_patrentWin != 0)

{

m_patrentWin->setCentralWidget(this);

}



没错,启动软件的时候首先Logo必须要帅!!

基于QGLViewer实现的点云显示、框选(实例)_第4张图片

读取点云,不用说了,然后兔子进来,我们按住shift框选。
基于QGLViewer实现的点云显示、框选(实例)_第5张图片
这样我们选择了兔子的屁股之后,拉开一段距离,兔子就被分开了。
基于QGLViewer实现的点云显示、框选(实例)_第6张图片

你可能感兴趣的:(QT,QGLViewer)