This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
IndoorMap/mapview/3D/MapView3D.cpp
kazu 52ab71fac5 some refactoring
hopefully improved rendering speed
added support to add .obj obstacles
2018-02-17 17:39:18 +01:00

362 lines
8.6 KiB
C++

#include "../../fixC11.h"
#include "MapView3D.h"
#include "../model/MapModelElement.h"
#include "../model/MapModel.h"
#include "../3D/grid/GridModel.h"
#include "../3D/grid/GridRenderer.h"
#include "../3D/navMesh/NavMeshModel.h"
#include "../3D/navMesh/NavMeshRenderer.h"
#include "../3D/floorplan/FloorplanRenderer.h"
#include "../3D/floorplan/FloorplanRendererModel.h"
#include <QPushButton>
MapView3D::MapView3D(QWidget *parent) : QOpenGLWidget(parent) {
rot.x = 0;
rot.y = 0;
rot.z = 0;
center.x = 0;
center.y = 0;
center.z = 0;
scale.x = 1.0f;
scale.y = 1.0f;
scale.z = 1.0f;
gridRenderer = new GridRenderer();
floorplanRenderer = new FloorplanRenderer();
floorplanRendererModel = new FloorplanRendererModel();
QString style = "QPushButton:checked{\
background-color: rgb(200, 200, 230);\
border: none; \
}";
QPushButton* btnFloorplan = new QPushButton(UIHelper::getIcon("floorplan"), "", this);
btnFloorplan->setGeometry(16, 16, 32, 32);
btnFloorplan->setCheckable(true);
btnFloorplan->setChecked(true);
btnFloorplan->setStyleSheet(style);
connect(btnFloorplan, &QPushButton::toggled, [btnFloorplan,this] () {
emit onShow3DFloorplan(btnFloorplan->isChecked());
});
QPushButton* btnPerspective = new QPushButton(UIHelper::getIcon("perspective"), "", this);
btnPerspective->setGeometry(16, 16+8+32, 32, 32);
connect(btnPerspective, &QPushButton::clicked, [this] () {
usePerspectiveProjection = !usePerspectiveProjection;
emit update();
});
QPushButton* btnWireframe = new QPushButton(UIHelper::getIcon("wireframe"), "", this);
btnWireframe->setCheckable(true);
btnWireframe->setStyleSheet(style);
btnWireframe->setGeometry(16, 16+8+32+8+32, 32, 32);
connect(btnWireframe, &QPushButton::clicked, [this] () {
useWireframe = !useWireframe;
emit update();
});
QPushButton* btnExp3D = new QPushButton(UIHelper::getIcon("save"), "", this);
btnExp3D->setStyleSheet(style);
btnExp3D->setGeometry(16, 16+8+32+8+32+8+32, 32, 32);
connect(btnExp3D, &QPushButton::clicked, [this] () {
floorplanRendererModel->getMesh().exportOBJsimple("/tmp/map.obj");
floorplanRendererModel->getMesh().exportOBJcomplex("/tmp/map_complex", "map_complex");
floorplanRendererModel->getMesh().exportPLY("/tmp/map.ply");
});
QPushButton* btnGrid = new QPushButton(UIHelper::getIcon("grid"), "", this);
btnGrid->setCheckable(true);
btnGrid->setChecked(false);
btnGrid->setGeometry(16+16+32, 16, 32, 32);
btnGrid->setStyleSheet(style);
connect(btnGrid, &QPushButton::toggled, [btnGrid, this] () {
emit onShow3DGrid(btnGrid->isChecked());
});
QPushButton* btnNavMesh = new QPushButton(UIHelper::getIcon("mesh"), "", this);
btnNavMesh->setCheckable(true);
btnNavMesh->setChecked(false);
btnNavMesh->setGeometry(16+16+32+16+32, 16, 32, 32);
btnNavMesh->setStyleSheet(style);
connect(btnNavMesh, &QPushButton::toggled, [btnNavMesh, this] () {
emit onShow3DNavMesh(btnNavMesh->isChecked());
});
// android
setAttribute(Qt::WA_AcceptTouchEvents, true);
grabGesture(Qt::PanGesture);
grabGesture(Qt::PinchGesture);
auto format = QSurfaceFormat();
//format.setVersion(4,3);
format.setSamples(2);
//format.setProfile(QSurfaceFormat::CoreProfile);
setFormat(format);
}
void MapView3D::initializeGL() {
//setFormat(QGLFormat(QGL::SampleBuffers));
QOpenGLWidget::initializeGL();
// this should be the default!!
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
// additional settings
glEnable(GL_DEPTH_TEST);
glClearColor(0.9, 0.9, 1.0, 1.0);
}
void MapView3D::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw();
}
void MapView3D::resizeGL(int width, int height) {
glViewport(0, 0, width, height);
}
void MapView3D::mousePressEvent(QMouseEvent* e) {
mouse.btn = e->button();
mouse.x = e->x();
mouse.y = e->y();
update();
}
void MapView3D::mouseMoveEvent(QMouseEvent* e) {
float dx = mouse.x - e->x();
float dy = mouse.y - e->y();
if (mouse.btn == 1) {
rot.z -= dx/2.0f;
rot.x -= dy/2.0f;
} else if (mouse.btn == 4) {
moveXY(dx, dy);
}
mouse.x = e->x();
mouse.y = e->y();
update();
}
void MapView3D::moveXY(float dx, float dy) {
//Point3 vec(-dx / width() * 2 * viewport.size.x, 0, +dy / height() * 2 * viewport.size.y);
Point3 vec(-dx / width() * 2 * viewport.size.x, +dy / height() * 2 * viewport.size.y, 0);
//Point3 vec(-dx * 2 / width() , 0, +dy * 2 / height());
vec = vec.rot(-rot.x/180*M_PI, -rot.y/180*M_PI, -rot.z/180*M_PI);
vec /= scale;
center += vec;
}
void MapView3D::mouseReleaseEvent(QMouseEvent* e) {
(void) e;
update();
}
void MapView3D::wheelEvent(QWheelEvent* e) {
float f = e->delta() / 120.0f;
scale *= (f > 0) ? (2) : (0.5);
update();
}
// android
bool MapView3D::event(QEvent* event) {
if (event->type() == QEvent::Gesture) {
return gestureEvent(static_cast<QGestureEvent*>(event));
//} else if (event->type() == QEvent::TouchBegin) {
// return true;
//} else if (event->type() == QEvent::TouchUpdate) {
// return true;
} else {
return QWidget::event(event);
}
}
bool MapView3D::gestureEvent(QGestureEvent* event) {
if (QGesture *swipe = event->gesture(Qt::SwipeGesture)) {
//swipeTriggered(static_cast<QSwipeGesture *>(swipe));
} else if (QGesture *pan = event->gesture(Qt::PanGesture))
panTriggered(static_cast<QPanGesture *>(pan));
return true;
if (QGesture *pinch = event->gesture(Qt::PinchGesture)) {
pinchTriggered(static_cast<QPinchGesture *>(pinch));
return true;
}
return false;
}
void MapView3D::pinchTriggered(QPinchGesture* gesture) {
update();
}
void MapView3D::panTriggered(QPanGesture* gesture) {
moveXY(gesture->delta().x(), gesture->delta().y());
update();
}
void MapView3D::setShowFloorplan(bool show) {
this->showFloorplan = show;
if (!show) {update(); return;}
// refresh
layerChange();
}
void MapView3D::setShowGrid(bool show) {
this->showGrid = show;
if (!show) {update(); return;}
// delete the previous grid (if any)
if (gridModel) {delete gridModel; gridModel = nullptr;}
// build a new model
GridModel* gm = new GridModel();
Floorplan::IndoorMap* im = getModel()->getMap();
gm->rebuild(im);
// remember
this->gridModel = gm;
// update UI
update();
}
void MapView3D::setShowNavMesh(bool show) {
this->showNavMesh = show;
if (!show) {update(); return;}
// delete the previous grid (if any)
if (navMeshModel) {delete navMeshModel; navMeshModel = nullptr;}
// build a new model
NavMeshModel* nm = new NavMeshModel();
Floorplan::IndoorMap* im = getModel()->getMap();
nm->rebuild(im);
// remember
this->navMeshModel = nm;
// update UI
update();
}
void MapView3D::layerChange() {
// todo: layers??
Floorplan::IndoorMap* im = getModel()->getMap();
this->floorplanRendererModel->rebuild(im);
update();
}
#include "misc/Shader.h"
void MapView3D::draw() {
static RenderSettings rs = RenderSettings(new Shader());
// view
QMatrix4x4 V;
V.translate(0,0,-50); // above the building
V.scale(scale.x, scale.y, scale.z);
V.rotate(rot.x, 1.0, 0.0, 0.0);
V.rotate(rot.y, 0.0, 1.0, 0.0);
V.rotate(rot.z, 0.0, 0.0, 1.0);
V.translate(center.x, center.y, center.z);
float far = 200; // TODO
// projection
QMatrix4x4 P;
float aspect = (float) width() / (float) height();
if (usePerspectiveProjection) {
float w = width() / 30;
float h = height() / 30;
viewport.size.x = w;
viewport.size.y = h;
P.perspective(45.0f, aspect, 0.01, far);
} else {
// default size: 50 * 50/aspect meters
float w = 50.0f;
float h = 50.0f * height() / width();
viewport.size.x = w;
viewport.size.y = h;
P.ortho(-w, +w, -h, +h, 0.1f, +far);
}
rs.shader->bind();
rs.shader->setViewMatrix(V);
rs.shader->setProjectionMatrix(P);
if (showFloorplan && floorplanRendererModel) {
floorplanRenderer->renderSolid(rs, floorplanRendererModel->getTriaSolid(), useWireframe );
}
// // solid floorplan parts
// if (showFloorplan) {
// std::vector<MapModelElement*> elements = getModel()->getVisibleElements();
// for (MapModelElement* el : elements) {
// if (el->getMV3D() && !el->getMV3D()->isTransparent()) {el->getMV3D()->render(rs);}
// }
// }
// if (showGrid && gridModel) {
// gridRenderer->paintGL(gridModel->getGrid());
// }
if (showNavMesh && navMeshModel) {
navMeshRenderer->render(rs, navMeshModel->getNavMesh(), this);
}
// // transparant floorplan parts
// if (showFloorplan) {
// std::vector<MapModelElement*> elements = getModel()->getVisibleElements();
// for (MapModelElement* el : elements) {
// if (el->getMV3D() && el->getMV3D()->isTransparent()) {el->getMV3D()->render(rs);}
// }
// }
if (showFloorplan && floorplanRendererModel) {
floorplanRenderer->renderTransp(rs, floorplanRendererModel->getTriaTransp(), useWireframe);
}
}