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