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
2018-10-25 12:15:13 +02:00

421 lines
10 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* © Copyright 2014 Urheberrechtshinweis
* Alle Rechte vorbehalten / All Rights Reserved
*
* Programmcode ist urheberrechtlich geschuetzt.
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
* Keine Verwendung ohne explizite Genehmigung.
* (vgl. § 106 ff UrhG / § 97 UrhG)
*/
#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();
navMeshRenderer = new NavMeshRenderer();
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* btnDoor = new QPushButton(UIHelper::getIcon("door"), "", this);
btnDoor->setCheckable(true);
btnDoor->setStyleSheet(style);
btnDoor->setGeometry(16, 16+8+32+8+32+8+32, 32, 32);
connect(btnDoor, &QPushButton::clicked, [this] () {
this->floorplanRendererModel->showDoors = !this->floorplanRendererModel->showDoors;
layerChange();
emit update();
});
QPushButton* btnExp3D = new QPushButton(UIHelper::getIcon("save"), "", this);
btnExp3D->setStyleSheet(style);
btnExp3D->setGeometry(16, 16+8+32+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");
QMessageBox::information(this, "Export", "3D Model exported to /tmp/* as .obj and .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.setRenderableType(QSurfaceFormat::OpenGL);
//format.setVersion(3, 4);
//format.setSamples(2);
//format.setProfile(QSurfaceFormat::CompatibilityProfile);
//format.setOption(QSurfaceFormat::DebugContext);
format.setSamples(4);
setFormat(format);
auto ver = format.version();
std::cout << "OpenGL Context Version: " << ver.first << "." << ver.second << std::endl;
}
void MapView3D::initializeGL() {
//setFormat(QGLFormat(QGL::SampleBuffers));
QOpenGLWidget::initializeGL();
initializeOpenGLFunctions();
logger = new QOpenGLDebugLogger(this);
if (logger->initialize()) {
connect(logger, &QOpenGLDebugLogger::messageLogged, [] (const QOpenGLDebugMessage& debugMessage) {
std::cout << debugMessage.message().toStdString() << std::endl;
});
logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
}
// Print device info
const GLubyte* vendor = glGetString(GL_VENDOR);
const GLubyte* renderer = glGetString(GL_RENDERER);
const GLubyte* version = glGetString(GL_VERSION);
std::cout << "Device info: ";
if (vendor) {
std::cout << (const char*) vendor << " ";
}
if (renderer) {
std::cout << (const char*) renderer << " ";
}
if (version) {
std::cout << (const char*) version << " ";
}
std::cout << std::endl;
// this should be the default!!
glCullFace(GL_BACK);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
// additional settings
glEnable(GL_DEPTH_TEST);
glClearColor(0.5, 0.5, 0.5, 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) ? (1.5) : (0.75);
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)) {
(void) swipe;
//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) {
(void) 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(), this);
const Point3 c = center - floorplanRendererModel->getBBox().getCenter();
// 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(c.x, c.y, c.z);
float farPlane = 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, farPlane);
} 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, +farPlane);
}
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());
gridRenderer->render(rs, gridModel);
}
if (showNavMesh && navMeshModel) {
navMeshRenderer->render(rs, navMeshModel);
}
// // 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);
}
}