1. 程式人生 > >基於QGLViewer實現的點雲顯示、框選(例項)

基於QGLViewer實現的點雲顯示、框選(例項)

生活中處處面臨著狗血的選擇,如果你是個很吸引人的青年,你會發現身邊有很多選擇,但做出選擇往往是很難的。
        而且大家有時候只能看,不能選,因為不會選,選錯了你就完蛋了。
        如果這時候你會選了,選對了,就不用一個人過節了。
        好,那麼今天講一下究竟怎麼選,怎麼選才能得到你想要的。
        (大家準備好雞蛋)
        其實點雲的選擇問題並不難。
        只是大家有時候沒有好好鑽。
        筆者基於QGLVewer簡單做了一下點雲的讀取、顯示、還有框選。(別扔臉,哎...哎...)
        那麼工程的程式碼採用的是QtainRibbon風格的QT介面,也是非常給力的。所有程式碼分享到置頂部落格的網盤中了。大家自行去下載即可,名字叫NinRibbonCloud。我就不往CSDN上弄了,太麻煩了,還收你積分,有空我會好好研究GitHub的用法。。。。

https://me.csdn.net/qq_30547073 部落格在這裡。
廢話不多說。
首先我們會看到QGLVewer的官方例子裡面,有一個MultSelect,它在上面那個圖裡面。對,這就是原始的例子。我們要改成自己想要的。


首先是object。主要繪製就繪製這個object,右邊兩行註釋是原有的,我改成繪製點雲了。


constrant 是用來約束相機的類,由於我們選完了之後還要讓選擇後的點雲發生變化,比如說旋轉,那麼我們就用這個來控制。

這張圖片剛好能裝下所有的程式碼。
那麼重頭戲還是在如何呼叫上。
新建一個類,繼承自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<Object *> objects_;

  QList<int> selection_;

};


然後是相應的CPP:
    整個的程式碼大致的流程是,上來建構函式初始化的時載入了所有的Object,就是繪製出來的那些小球。然後當你按住Shift的時候,就會啟用selectmode = true;這時候拖動滑鼠就會繪製出一個框框來。然後當你鬆手的時候就會呼叫mouseRelease以及select函式。所選擇的東西的Index全部儲存在私有的QList中。然後程式碼內將所有selectList中的點繪製成另一種顏色。也是很有趣的。
    不過這樣寫的缺點是,載入的點過多的時候就會很卡,想必是因為呼叫了過多次glBegin的問題。這一點應該是可以修改的。我們在最後還放了幾個結果。

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

#include "Example_multiSelect.h"

#include "manipulatedFrameSetConstraint.h"

#include <QGLViewer/manipulatedFrame.h>

#include <QMouseEvent>

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<int>::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<int>::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必須要帥!!

讀取點雲,不用說了,然後兔子進來,我們按住shift框選。

這樣我們選擇了兔子的屁股之後,拉開一段距離,兔子就被分開了。