current revision
This commit is contained in:
141
ui/map/3D/elements/ColorPoints.h
Normal file
141
ui/map/3D/elements/ColorPoints.h
Normal file
@@ -0,0 +1,141 @@
|
||||
#ifndef GL_PARTICLES_H
|
||||
#define GL_PARTICLES_H
|
||||
|
||||
|
||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||
#include <KLib/math/filter/particles/ParticleFilter.h>
|
||||
|
||||
#include "../gl/GLHelper.h"
|
||||
#include "../gl/GLPoints.h"
|
||||
//#include "../gl/GLTriangles.h"
|
||||
#include "../Renderable.h"
|
||||
|
||||
#include "../../../../nav/Node.h"
|
||||
|
||||
class ColorPoints : public Renderable {
|
||||
|
||||
private:
|
||||
|
||||
GLPoints points;
|
||||
float size = 3.0f;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
ColorPoints() {
|
||||
|
||||
}
|
||||
|
||||
/** NOTE: must be called from Qt's main thread! */
|
||||
void setFromGridImportance(Grid<MyGridNode>* grid) {
|
||||
|
||||
points.clear();
|
||||
|
||||
float min = +INFINITY;
|
||||
float max = -INFINITY;
|
||||
|
||||
for (const MyGridNode& n : *grid) {
|
||||
const float f = n.getWalkImportance();
|
||||
if (f < min) {min = f;}
|
||||
if (f > max) {max = f;}
|
||||
}
|
||||
|
||||
max = 1.2;
|
||||
|
||||
for (const MyGridNode& n : *grid) {
|
||||
const QVector3D pt(n.x_cm/100.0f, n.z_cm/100.0f + 0.1f, n.y_cm/100.0f); // swap z and y
|
||||
const float f = n.getWalkImportance();
|
||||
float h = 0.66 - ((f-min)/(max-min)) * 0.66; // 0.66 is blue on the HSV-scale
|
||||
if (h < 0) {h = 0;}
|
||||
if (h > 1) {h = 1;}
|
||||
const QColor color = QColor::fromHsvF(h, 1, 1);
|
||||
points.addPoint(pt, color);
|
||||
}
|
||||
|
||||
size = 8.0f;
|
||||
points.rebuild();
|
||||
|
||||
}
|
||||
|
||||
/** NOTE: must be called from Qt's main thread! */
|
||||
template <typename T> void setFromParticles(const std::vector<K::Particle<T>>& particles) {
|
||||
|
||||
points.clear();
|
||||
|
||||
// group particles by grid-point
|
||||
std::unordered_map<GridPoint, float> weights;
|
||||
for (const K::Particle<T>& p : particles) {
|
||||
const GridPoint gp = p.state.position;
|
||||
if (weights.find(gp) != weights.end()) {continue;}
|
||||
weights[gp] += p.weight;
|
||||
}
|
||||
|
||||
// find min/max
|
||||
float min = +INFINITY;
|
||||
float max = -INFINITY;
|
||||
for (auto it : weights) {
|
||||
if (it.second > max) {max = it.second;}
|
||||
if (it.second < min) {min = it.second;}
|
||||
}
|
||||
|
||||
// draw colored
|
||||
for (auto it : weights) {
|
||||
const GridPoint gp = it.first;
|
||||
const float w = it.second;
|
||||
const float p = (w-min) / (max-min); // [0:1]
|
||||
const QVector3D pt(gp.x_cm/100.0f, gp.z_cm/100.0f + 0.1f, gp.y_cm/100.0f); // swap z and y
|
||||
float h = 0.66 - (p*0.66); // 0.66 is blue on the HSV-scale
|
||||
const QColor color = QColor::fromHsvF(h, 1, 1);
|
||||
points.addPoint(pt, color);
|
||||
}
|
||||
|
||||
|
||||
// for (const K::Particle<T>& p : particles) {
|
||||
// const GridPoint gp = p.state.position;
|
||||
// const QVector3D pt(gp.x_cm/100.0f, gp.z_cm/100.0f + 0.1f, gp.y_cm/100.0f); // swap z and y
|
||||
// const QColor color = Qt::blue;
|
||||
// points.addPoint(pt, color);
|
||||
// }
|
||||
|
||||
size = 8.0f;
|
||||
points.rebuild();
|
||||
|
||||
}
|
||||
|
||||
// void addPoint(const QVector3D pt, const QColor color) {
|
||||
|
||||
// const float s = 5 / 100.0f;
|
||||
// const QVector3D col(color.redF(), color.greenF(), color.blueF());
|
||||
// const VertColor vc1(pt + QVector3D(-s, -s, 0), col);
|
||||
// const VertColor vc2(pt + QVector3D(+s, -s, 0), col);
|
||||
// const VertColor vc3(pt + QVector3D(+s, +s, 0), col);
|
||||
// const VertColor vc4(pt + QVector3D(-s, +s, 0), col);
|
||||
|
||||
// points.addQuad(vc1, vc2, vc3, vc4);
|
||||
|
||||
// }
|
||||
|
||||
void initGL() override {
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentColorPoint.glsl");
|
||||
//program.setUniformValue("color", QVector4D(0.5, 0.5, 0.5, 1.0));
|
||||
points.initGL();
|
||||
}
|
||||
|
||||
/** render the floor */
|
||||
void _render(const RenderParams& params) override {
|
||||
|
||||
(void) params;
|
||||
//glDisable(GL_DEPTH_TEST);
|
||||
|
||||
#ifndef ANDROID
|
||||
glPointSize(size);
|
||||
#endif
|
||||
points.render(&program);
|
||||
//glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // GL_PARTICLES_H
|
||||
106
ui/map/3D/elements/Doors.h
Normal file
106
ui/map/3D/elements/Doors.h
Normal file
@@ -0,0 +1,106 @@
|
||||
#ifndef DOORS_H
|
||||
#define DOORS_H
|
||||
|
||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||
#include "../gl/GLHelper.h"
|
||||
#include "../gl/GLTriangles.h"
|
||||
#include "../Renderable.h"
|
||||
|
||||
class Doors : public Renderable {
|
||||
|
||||
private:
|
||||
|
||||
Floorplan::Floor* floor;
|
||||
|
||||
GLTriangles<VertNormTexTan> doors;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Doors(Floorplan::Floor* floor) : floor(floor) {
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void initGL() override {
|
||||
|
||||
build();
|
||||
doors.setDiffuse(":/res/gl/tex/door2.jpg");
|
||||
doors.setNormalMap(":/res/gl/tex/door2_normal.jpg");
|
||||
|
||||
doors.build();
|
||||
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
|
||||
program.setUniformValue("texDiffuse", 0);
|
||||
program.setUniformValue("texNormalMap", 1);
|
||||
|
||||
}
|
||||
|
||||
/** render the floor */
|
||||
void _render(const RenderParams& params) override {
|
||||
|
||||
// skip me?
|
||||
if (params.clipAboveHeight_m < floor->atHeight) {return;}
|
||||
|
||||
doors.render(&program);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void build() {
|
||||
|
||||
for (Floorplan::FloorObstacle* obstacle : floor->obstacles) {
|
||||
|
||||
if (dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle)) {
|
||||
Floorplan::FloorObstacleDoor* door = dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle);
|
||||
addFace(door->from, door->to, floor->getStartingZ(), floor->getStartingZ() + door->height, door->swap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void addFace(const Point2 from, Point2 to, const float h1, const float h2, const bool swap) {
|
||||
|
||||
to = from + (to-from).rotated(60/180.0f*M_PI * ((swap)?(-1):(+1)) );
|
||||
|
||||
const QVector3D vert1(from.x, h1, from.y);
|
||||
const QVector3D vert2(to.x, h1, to.y);
|
||||
const QVector3D vert3(to.x, h2, to.y);
|
||||
const QVector3D vert4(from.x, h2, from.y);
|
||||
|
||||
const QVector3D n1 = GLHelper::getNormal(vert1, vert2, vert3);
|
||||
const QVector3D n2 = -n1;
|
||||
|
||||
QVector3D tan = (vert1-vert2).normalized();
|
||||
tan = GLHelper::isCCW(vert1, vert2, vert3) ? (tan) : (-tan);
|
||||
|
||||
const QVector2D tex1(0, 0);
|
||||
const QVector2D tex2(1, 0);
|
||||
const QVector2D tex3(1, 1);
|
||||
const QVector2D tex4(0, 1);
|
||||
|
||||
{
|
||||
const VertNormTexTan vnt1(vert1, n1, tex1, tan);
|
||||
const VertNormTexTan vnt2(vert2, n1, tex2, tan);
|
||||
const VertNormTexTan vnt3(vert3, n1, tex3, tan);
|
||||
const VertNormTexTan vnt4(vert4, n1, tex4, tan);
|
||||
doors.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
|
||||
} {
|
||||
const VertNormTexTan vnt1(vert1, n2, tex1, -tan);
|
||||
const VertNormTexTan vnt2(vert2, n2, tex2, -tan);
|
||||
const VertNormTexTan vnt3(vert3, n2, tex3, -tan);
|
||||
const VertNormTexTan vnt4(vert4, n2, tex4, -tan);
|
||||
doors.addQuadCW(vnt1, vnt2, vnt3, vnt4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // DOORS_H
|
||||
178
ui/map/3D/elements/Ground.h
Normal file
178
ui/map/3D/elements/Ground.h
Normal file
@@ -0,0 +1,178 @@
|
||||
#ifndef GROUND_H
|
||||
#define GROUND_H
|
||||
|
||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||
#include "../gl/GLHelper.h"
|
||||
#include "../gl/GLTriangles.h"
|
||||
#include "../gl/GLLines.h"
|
||||
#include "../Renderable.h"
|
||||
|
||||
#include "../../../../lib/gpc/Polygon.h"
|
||||
|
||||
class Ground : public Renderable {
|
||||
|
||||
private:
|
||||
|
||||
Floorplan::Floor* floor;
|
||||
|
||||
GLTriangles<VertNormTexTan> flooring;
|
||||
GLTriangles<VertNormTexTan> ceiling;
|
||||
|
||||
GLLines outline;
|
||||
|
||||
bool outlineOnly = false;
|
||||
bool transparent = false;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Ground(Floorplan::Floor* floor) : floor(floor) {
|
||||
setOutlineOnly(false);
|
||||
}
|
||||
|
||||
|
||||
void initGL() override {
|
||||
|
||||
build();
|
||||
|
||||
flooring.setDiffuse(":/res/gl/tex/floor4.jpg");
|
||||
flooring.setNormalMap(":/res/gl/tex/floor4_normal.jpg");
|
||||
|
||||
ceiling.setDiffuse(":/res/gl/tex/floor4.jpg");
|
||||
ceiling.setNormalMap(":/res/gl/tex/floor4_normal.jpg");
|
||||
|
||||
flooring.build();
|
||||
ceiling.build();
|
||||
outline.build();
|
||||
|
||||
//loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
|
||||
//program.setUniformValue("texDiffuse", 0);
|
||||
//program.setUniformValue("texNormalMap", 1);
|
||||
|
||||
}
|
||||
|
||||
/** render the floor */
|
||||
void _render(const RenderParams& params) override {
|
||||
|
||||
// skip me?
|
||||
if (params.clipAboveHeight_m < floor->atHeight) {return;}
|
||||
|
||||
if (transparent) {
|
||||
program.setUniformValue("alpha", 0.5f);
|
||||
glEnable(GL_BLEND);
|
||||
} else {
|
||||
program.setUniformValue("alpha", 1.0f);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
if (outlineOnly) {
|
||||
glLineWidth(5);
|
||||
outline.render(&program);
|
||||
} else {
|
||||
flooring.render(&program);
|
||||
ceiling.render(&program);
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
}
|
||||
|
||||
/** render only the outline? */
|
||||
void setOutlineOnly(const bool outline) override {
|
||||
(void) outline;
|
||||
// this->outlineOnly = outline;
|
||||
// if (outlineOnly) {
|
||||
// loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
|
||||
// program.setUniformValue("color", QVector4D(0.0, 0.0, 0.4, 1.0));
|
||||
// } else {
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
|
||||
program.setUniformValue("texDiffuse", 0);
|
||||
program.setUniformValue("texNormalMap", 1);
|
||||
// }
|
||||
}
|
||||
|
||||
void setTransparent(const bool transparent) override {
|
||||
this->transparent = transparent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void build() {
|
||||
|
||||
std::vector<gpc_polygon> add;
|
||||
std::vector<gpc_polygon> rem;
|
||||
|
||||
const std::vector<Floorplan::FloorOutlinePolygon*>& polys = floor->outline;
|
||||
|
||||
Polygon pol;
|
||||
|
||||
for (Floorplan::FloorOutlinePolygon* poly : polys) {
|
||||
switch (poly->method) {
|
||||
case Floorplan::OutlineMethod::ADD: pol.add(poly->poly); break;
|
||||
case Floorplan::OutlineMethod::REMOVE: pol.remove(poly->poly); break;
|
||||
default: throw 1;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::vector<Point3>> trias = pol.get(floor->atHeight);
|
||||
|
||||
|
||||
// is stored as TRIANGLE_STRIP
|
||||
// => triangle might have more than 3 points
|
||||
for (const std::vector<Point3>& tria : trias) {
|
||||
|
||||
|
||||
const QVector3D normFloor(0, +1, 0);
|
||||
const QVector3D normCeil(0, -1, 0);
|
||||
const QVector3D t(1,0,0);
|
||||
|
||||
const float s = 0.6;
|
||||
|
||||
// add vertices
|
||||
for (int i = 2; i < (int) tria.size(); i+=1) {
|
||||
|
||||
const Point3 p1 = tria[i-2];
|
||||
const Point3 p2 = tria[i-1];
|
||||
const Point3 p3 = tria[i-0];
|
||||
|
||||
const QVector3D vert1(p1.x, p1.z, p1.y);
|
||||
const QVector3D vert2(p2.x, p2.z, p2.y);
|
||||
const QVector3D vert3(p3.x, p3.z, p3.y);
|
||||
|
||||
{
|
||||
const VertNormTexTan vnt1(vert1, normFloor, tex(vert1*s), t);
|
||||
const VertNormTexTan vnt2(vert2, normFloor, tex(vert2*s), t);
|
||||
const VertNormTexTan vnt3(vert3, normFloor, tex(vert3*s), t);
|
||||
flooring.addFaceCCW(vnt1, vnt2, vnt3);
|
||||
} {
|
||||
const VertNormTexTan vnt1(vert1, normCeil, tex(vert1*s), t);
|
||||
const VertNormTexTan vnt2(vert2, normCeil, tex(vert2*s), t);
|
||||
const VertNormTexTan vnt3(vert3, normCeil, tex(vert3*s), t);
|
||||
ceiling.addFaceCW(vnt1, vnt2, vnt3);
|
||||
}
|
||||
|
||||
outline.addLine(vert1, vert2);
|
||||
outline.addLine(vert2, vert3);
|
||||
outline.addLine(vert3, vert1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
QVector2D tex(const QVector3D vert) {
|
||||
return QVector2D(vert.x(), vert.z());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // GROUND_H
|
||||
90
ui/map/3D/elements/Handrails.h
Normal file
90
ui/map/3D/elements/Handrails.h
Normal file
@@ -0,0 +1,90 @@
|
||||
#ifndef HANDRAIL_H
|
||||
#define HANDRAIL_H
|
||||
|
||||
|
||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||
#include "../gl/GLHelper.h"
|
||||
#include "../gl/GLLines.h"
|
||||
#include "../Renderable.h"
|
||||
|
||||
|
||||
class Handrails : public Renderable {
|
||||
|
||||
private:
|
||||
|
||||
Floorplan::Floor* floor;
|
||||
|
||||
GLLines lines;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Handrails(Floorplan::Floor* floor) : floor(floor) {
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void initGL() override {
|
||||
build();
|
||||
lines.build();
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
|
||||
program.setUniformValue("color", QVector4D(0.5, 0.5, 0.5, 1.0));
|
||||
}
|
||||
|
||||
/** render the floor */
|
||||
void _render(const RenderParams& params) override {
|
||||
if (params.clipAboveHeight_m < floor->atHeight) {return;}
|
||||
glLineWidth(2);
|
||||
lines.render(&program);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void build() {
|
||||
|
||||
for (Floorplan::FloorObstacle* obstacle : floor->obstacles) {
|
||||
|
||||
if (dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle)) {
|
||||
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle);
|
||||
if (line->type != Floorplan::ObstacleType::HANDRAIL) {continue;}
|
||||
add(line->from, line->to, floor->getStartingZ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void add(const Point2 from, const Point2 to, const float h1) {
|
||||
|
||||
// handrail height
|
||||
const float h2 = h1 + 0.8;
|
||||
|
||||
const QVector3D v1(to.x, h2, to.y);
|
||||
const QVector3D v2(from.x, h2, from.y);
|
||||
|
||||
// upper
|
||||
lines.addLine(v1, v2);
|
||||
|
||||
const float stepSize = 0.5;
|
||||
const float len = from.getDistance(to);
|
||||
const float steps = std::round(len / stepSize);
|
||||
|
||||
for (int i = 0; i <= steps; ++i) {
|
||||
const float percent = (float) i / (float) steps;
|
||||
const Point2 pos = from + (to-from) * percent;
|
||||
const QVector3D v1(pos.x, h1, pos.y);
|
||||
const QVector3D v2(pos.x, h2, pos.y);
|
||||
lines.addLine(v1, v2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // HANDRAIL_H
|
||||
85
ui/map/3D/elements/Object.h
Normal file
85
ui/map/3D/elements/Object.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
|
||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||
#include "../gl/GLHelper.h"
|
||||
#include "../gl/GLTriangles.h"
|
||||
#include "../Renderable.h"
|
||||
|
||||
#include <KLib/data/obj/ObjectFile.h>
|
||||
|
||||
|
||||
class Object : public Renderable {
|
||||
|
||||
private:
|
||||
|
||||
GLTriangles<VertNormTex> triangles;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Object(const std::string& file, const std::string& colorTexture, std::string normalsTexture, const float scale = 1.0) {
|
||||
|
||||
K::ObjFileReader reader(file, false);
|
||||
|
||||
|
||||
if (normalsTexture.empty()) {normalsTexture = ":/res/gl/tex/empty_normals.jpg";}
|
||||
|
||||
triangles.setDiffuse(colorTexture.c_str());
|
||||
triangles.setNormalMap(normalsTexture.c_str());
|
||||
|
||||
for (const K::ObjFileReader::Face& face : reader.getData().faces) {
|
||||
|
||||
const QVector3D vertex1(face.vnt[0].vertex.x, face.vnt[0].vertex.y, face.vnt[0].vertex.z);
|
||||
const QVector3D vertex2(face.vnt[1].vertex.x, face.vnt[1].vertex.y, face.vnt[1].vertex.z);
|
||||
const QVector3D vertex3(face.vnt[2].vertex.x, face.vnt[2].vertex.y, face.vnt[2].vertex.z);
|
||||
|
||||
const QVector3D normal1(face.vnt[0].normal.x, face.vnt[0].normal.y, face.vnt[0].normal.z);
|
||||
const QVector3D normal2(face.vnt[1].normal.x, face.vnt[1].normal.y, face.vnt[1].normal.z);
|
||||
const QVector3D normal3(face.vnt[2].normal.x, face.vnt[2].normal.y, face.vnt[2].normal.z);
|
||||
|
||||
const QVector2D texture1(face.vnt[0].texture.x, face.vnt[0].texture.y);
|
||||
const QVector2D texture2(face.vnt[1].texture.x, face.vnt[1].texture.y);
|
||||
const QVector2D texture3(face.vnt[2].texture.x, face.vnt[2].texture.y);
|
||||
|
||||
const QVector3D o(0, 0.0, 0);
|
||||
|
||||
const VertNormTex vnt1(vertex1*scale+o, normal1, texture1);
|
||||
const VertNormTex vnt2(vertex2*scale+o, normal2, texture2);
|
||||
const VertNormTex vnt3(vertex3*scale+o, normal3, texture3);
|
||||
|
||||
triangles.addFace(vnt1, vnt2, vnt3);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void initGL() override {
|
||||
build();
|
||||
triangles.build();
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
|
||||
program.setUniformValue("texDiffuse", 0);
|
||||
program.setUniformValue("texNormalMap", 1);
|
||||
}
|
||||
|
||||
/** render the floor */
|
||||
void _render(const RenderParams& params) override {
|
||||
(void) params;
|
||||
triangles.render(&program);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void build() {
|
||||
triangles.build();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // OBJECT_H
|
||||
220
ui/map/3D/elements/Path.h
Normal file
220
ui/map/3D/elements/Path.h
Normal file
@@ -0,0 +1,220 @@
|
||||
#ifndef PATH_H
|
||||
#define PATH_H
|
||||
|
||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||
#include <Indoor/nav/dijkstra/DijkstraPath.h>
|
||||
|
||||
|
||||
#include "../gl/GLHelper.h"
|
||||
#include "../gl/GLTriangles.h"
|
||||
#include "../Renderable.h"
|
||||
|
||||
|
||||
class Path : public Renderable {
|
||||
|
||||
private:
|
||||
|
||||
GLTriangles<VertNormTex> lines;
|
||||
|
||||
/** path's width (in meter) */
|
||||
float width;
|
||||
|
||||
/** the path's color */
|
||||
QVector4D color;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Path() {
|
||||
setColor(QVector4D(0.0, 0.4, 1.0, 0.6));
|
||||
setWidth(0.8);
|
||||
}
|
||||
|
||||
|
||||
void initGL() override {
|
||||
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
|
||||
//loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTexSimple.glsl");
|
||||
|
||||
lines.setDiffuse(":/res/gl/tex/arrows.png");
|
||||
program.setUniformValue("texNormalMap", 0);
|
||||
|
||||
}
|
||||
|
||||
/** set the path's color */
|
||||
void setColor(const QVector4D& color) {
|
||||
this->color = color;
|
||||
}
|
||||
|
||||
/** set the path's color */
|
||||
void setColor(const QColor& color) {
|
||||
setColor(QVector4D(color.redF(), color.greenF(), color.blueF(), color.alphaF()));
|
||||
}
|
||||
|
||||
/** set the path's width (in meter) */
|
||||
void setWidth(const float width) {
|
||||
this->width = width;
|
||||
}
|
||||
|
||||
/** render the floor */
|
||||
void _render(const RenderParams& params) override {
|
||||
|
||||
(void) params;
|
||||
program.setUniformValue("color", color);
|
||||
|
||||
//glEnable(GL_BLEND);
|
||||
glDisable(GL_CULL_FACE);
|
||||
//glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
lines.render(&program);
|
||||
//glDisable(GL_BLEND);
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <typename Node> void set(const DijkstraPath<Node>& path) {
|
||||
|
||||
std::vector<Point3> out;
|
||||
for (const DijkstraNode<Node>* node : path.getVector()) {
|
||||
if (!node) {break;}
|
||||
const Node* elem = node->element;
|
||||
out.push_back(Point3(elem->x_cm/100.0f, elem->y_cm/100.0f, elem->z_cm/100.0f));
|
||||
}
|
||||
|
||||
set(out);
|
||||
|
||||
}
|
||||
|
||||
/** combine nodes while the direction stays the same (many small quads -> one large quad) */
|
||||
std::vector<Point3> simplify(const std::vector<Point3>& path) {
|
||||
|
||||
// copy
|
||||
std::vector<Point3> out = path;
|
||||
|
||||
// remove unneccesary nodes
|
||||
for (int i = 1; i < (int) out.size() - 1; ++i) {
|
||||
|
||||
const Point3 pa = out[i-1];
|
||||
const Point3 pb = out[i-0];
|
||||
const Point3 pc = out[i+1];
|
||||
|
||||
// same direction as last segment? combine segments!
|
||||
const float dir1 = std::atan2(pb.y-pa.y, pb.x-pa.x); // last edge
|
||||
const float dir2 = std::atan2(pc.y-pb.y, pc.x-pb.x); // next edge
|
||||
const bool isSameDir = std::abs(dir1-dir2) < 0.03; // last-edge and next-edge have (approx) the same direction?
|
||||
if (isSameDir) {out.erase(out.begin()+i); --i; continue;} // no additional information! remove the center node
|
||||
|
||||
// too many changes in a small space? -> remove some!
|
||||
const float d1 = pb.getDistance(pa); // distance to last node
|
||||
const float d2 = pb.getDistance(pc); // distance to next node
|
||||
const float min = 0.8;
|
||||
const bool isPackedChange = d1 < min && d2 < min; // both distances below a threshold?
|
||||
if (isPackedChange) {out.erase(out.begin()+i); --i; continue;} // -> many changes in a small area -> remove current node!
|
||||
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
/** MUST BE CALLED FROM THE MAIN THREAD */
|
||||
void set(const std::vector<Point3>& _path) {
|
||||
|
||||
std::vector<Point3> path = simplify(_path);
|
||||
|
||||
// reset
|
||||
lines.clear();
|
||||
|
||||
// half the width of the path
|
||||
const float s = this->width * 0.5;
|
||||
std::vector<Floorplan::Quad3> quads;
|
||||
|
||||
for (int i = 1; i < (int) path.size(); ++i) {
|
||||
|
||||
Point3 pa = path[i-1];
|
||||
Point3 pb = path[i-0];
|
||||
const Point3 pc(0, 0, 1);
|
||||
Point3 dir = (pb - pa).normalized();
|
||||
|
||||
// produce a small gap between path-segments
|
||||
// those segments will be smoothly connected using another quad
|
||||
pa += dir * 0.35;
|
||||
pb -= dir * 0.35;
|
||||
|
||||
const Point3 perb = cross(pa-pb, pc).normalized();
|
||||
|
||||
// quad's edges
|
||||
const Point3 p1 = pa - perb*s;
|
||||
const Point3 p2 = pa + perb*s;
|
||||
const Point3 p3 = pb + perb*s;
|
||||
const Point3 p4 = pb - perb*s;
|
||||
|
||||
// add
|
||||
quads.push_back(Floorplan::Quad3(p1,p2,p3,p4));
|
||||
|
||||
}
|
||||
|
||||
float l1 = 0;
|
||||
float l2 = 0;
|
||||
|
||||
for (int i = 0; i < (int) quads.size(); ++i) {
|
||||
|
||||
// add the line-segment
|
||||
const Floorplan::Quad3 q1 = quads[i];
|
||||
l2 += ((q1.p1 + q1.p2) / 2).getDistance( (q1.p3 + q1.p4) / 2 );
|
||||
addQuad(q1, l1, l2);
|
||||
l1 = l2;
|
||||
|
||||
// done?
|
||||
if (i == (int) quads.size() - 1) {break;}
|
||||
|
||||
// construct the quad between adjacent segments
|
||||
const Floorplan::Quad3 q2 = quads[i+1];
|
||||
const Floorplan::Quad3 q3(q1.p4, q1.p3, q2.p2, q2.p1);
|
||||
l2 += ((q3.p1 + q3.p2) / 2).getDistance( (q3.p3 + q3.p4) / 2 );
|
||||
addQuad(q3, l1, l2);
|
||||
l1 = l2;
|
||||
|
||||
}
|
||||
|
||||
lines.rebuild();
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void addQuad(const Floorplan::Quad3& q, const float l1, const float l2) {
|
||||
|
||||
// move the path upwards (slightly above the ground)
|
||||
const float h = 0.40;
|
||||
|
||||
const QVector3D v1(q.p1.x, q.p1.z+h, q.p1.y);
|
||||
const QVector3D v2(q.p2.x, q.p2.z+h, q.p2.y);
|
||||
const QVector3D v3(q.p3.x, q.p3.z+h, q.p3.y);
|
||||
const QVector3D v4(q.p4.x, q.p4.z+h, q.p4.y);
|
||||
|
||||
const QVector3D n(0,1,0);
|
||||
|
||||
const QVector2D tex1(0, l1);
|
||||
const QVector2D tex2(1, l1);
|
||||
const QVector2D tex3(1, l2);
|
||||
const QVector2D tex4(0, l2);
|
||||
|
||||
// const QVector2D tex1(q.p1.x, q.p1.y);
|
||||
// const QVector2D tex2(q.p2.x, q.p2.y);
|
||||
// const QVector2D tex3(q.p3.x, q.p3.y);
|
||||
// const QVector2D tex4(q.p4.x, q.p4.y);
|
||||
|
||||
const VertNormTex vnt1(v1, n, tex1);
|
||||
const VertNormTex vnt2(v2, n, tex2);
|
||||
const VertNormTex vnt3(v3, n, tex3);
|
||||
const VertNormTex vnt4(v4, n, tex4);
|
||||
|
||||
lines.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // PATH_H
|
||||
154
ui/map/3D/elements/Stairs.h
Normal file
154
ui/map/3D/elements/Stairs.h
Normal file
@@ -0,0 +1,154 @@
|
||||
#ifndef STAIRS_H
|
||||
#define STAIRS_H
|
||||
|
||||
|
||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||
#include "../gl/GLHelper.h"
|
||||
#include "../gl/GLTriangles.h"
|
||||
#include "../Renderable.h"
|
||||
|
||||
|
||||
class Stairs : public Renderable {
|
||||
|
||||
private:
|
||||
|
||||
Floorplan::Floor* floor;
|
||||
|
||||
GLTriangles<VertNormTex> parts;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Stairs(Floorplan::Floor* floor) : floor(floor) {
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void initGL() override {
|
||||
|
||||
build();
|
||||
// parts.setDiffuse(":/res/gl/tex/granite1.jpg");
|
||||
// parts.setNormalMap(":/res/gl/tex/granite1_normal.jpg");
|
||||
parts.setDiffuse(":/res/gl/tex/floor4.jpg");
|
||||
parts.setNormalMap(":/res/gl/tex/floor4_normal.jpg");
|
||||
parts.build();
|
||||
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
|
||||
program.setUniformValue("texDiffuse", 0);
|
||||
program.setUniformValue("texNormalMap", 1);
|
||||
|
||||
}
|
||||
|
||||
/** render the floor */
|
||||
void _render(const RenderParams& params) override {
|
||||
(void) params;
|
||||
parts.render(&program);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void build() {
|
||||
|
||||
for (Floorplan::Stair* stair : floor->stairs) {
|
||||
|
||||
if (dynamic_cast<Floorplan::Stair*>(stair)) {
|
||||
Floorplan::StairFreeform* freeform = dynamic_cast<Floorplan::StairFreeform*>(stair);
|
||||
add(Floorplan::getQuads(freeform->getParts(), floor));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void add(const std::vector<Floorplan::Quad3>& quads) {
|
||||
|
||||
for (const Floorplan::Quad3& quad : quads) {
|
||||
|
||||
//void addQuad(quad);
|
||||
|
||||
stepify(quad);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void stepify(const Floorplan::Quad3& quad) {
|
||||
|
||||
const float len = (quad.p4 - quad.p1).length();
|
||||
const float stepLen = 0.3;
|
||||
const int steps = std::round(len / stepLen);
|
||||
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
const float per1 = (float) (i+0) / (float) steps;
|
||||
const float per2 = (float) (i+1) / (float) steps;
|
||||
|
||||
const Point3 p1 = quad.p1 + (quad.p4 - quad.p1) * per1;
|
||||
const Point3 p2 = quad.p2 + (quad.p3 - quad.p2) * per1;
|
||||
const Point3 p5 = quad.p2 + (quad.p3 - quad.p2) * per2;
|
||||
const Point3 p6 = quad.p1 + (quad.p4 - quad.p1) * per2;
|
||||
Point3 p3 = p5; p3.z = p2.z;
|
||||
Point3 p4 = p6; p4.z = p1.z;
|
||||
|
||||
|
||||
addQuad(Floorplan::Quad3(p1, p2, p3, p4));
|
||||
addQuad(Floorplan::Quad3(p3, p4, p6, p5));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void addQuad(const Floorplan::Quad3& quad) {
|
||||
|
||||
const QVector3D vert1(quad.p1.x, quad.p1.z, quad.p1.y);
|
||||
const QVector3D vert2(quad.p2.x, quad.p2.z, quad.p2.y);
|
||||
const QVector3D vert3(quad.p3.x, quad.p3.z, quad.p3.y);
|
||||
const QVector3D vert4(quad.p4.x, quad.p4.z, quad.p4.y);
|
||||
|
||||
const QVector3D n1 = GLHelper::getNormal(vert1, vert2, vert3);
|
||||
const QVector3D n2 = -n1;
|
||||
|
||||
// const float o =
|
||||
|
||||
// const QVector2D tex1(quad.p1.length(), quad.p1.y);
|
||||
// const QVector2D tex2(quad.p2.x, quad.p2.y+quad.p2.z);
|
||||
// const QVector2D tex3(quad.p3.x, quad.p3.y+quad.p3.z);
|
||||
// const QVector2D tex4(quad.p4.x, quad.p4.y+quad.p4.z);
|
||||
|
||||
const float h = quad.p4.getDistance(quad.p1);
|
||||
const float l = quad.p1.getDistance(quad.p2);
|
||||
const float o = quad.p1.length();
|
||||
const float s = 1.1; // 0.5;
|
||||
|
||||
const QVector2D tex1(o+0, h); // start texturing at the ceiling so above-door-sections and walls have the same textre
|
||||
const QVector2D tex2(o+l, h);
|
||||
const QVector2D tex3(o+l, 0);
|
||||
const QVector2D tex4(o+0, 0);
|
||||
|
||||
// const VertNormTex vnt1(vert1, n1, tex1*s);
|
||||
// const VertNormTex vnt2(vert2, n1, tex2*s);
|
||||
// const VertNormTex vnt3(vert3, n1, tex3*s);
|
||||
// const VertNormTex vnt4(vert4, n1, tex4*s);
|
||||
|
||||
{
|
||||
const VertNormTex vnt1(vert1, n1, tex1*s);
|
||||
const VertNormTex vnt2(vert2, n1, tex2*s);
|
||||
const VertNormTex vnt3(vert3, n1, tex3*s);
|
||||
const VertNormTex vnt4(vert4, n1, tex4*s);
|
||||
parts.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
|
||||
} {
|
||||
const VertNormTex vnt1(vert1, n2, tex1*s);
|
||||
const VertNormTex vnt2(vert2, n2, tex2*s);
|
||||
const VertNormTex vnt3(vert3, n2, tex3*s);
|
||||
const VertNormTex vnt4(vert4, n2, tex4*s);
|
||||
parts.addQuadCW(vnt1, vnt2, vnt3, vnt4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // STAIRS_H
|
||||
163
ui/map/3D/elements/Walls.h
Normal file
163
ui/map/3D/elements/Walls.h
Normal file
@@ -0,0 +1,163 @@
|
||||
#ifndef WALLS_H
|
||||
#define WALLS_H
|
||||
|
||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||
#include "../gl/GLHelper.h"
|
||||
#include "../gl/GLTriangles.h"
|
||||
#include "../gl/GLLines.h"
|
||||
#include "../Renderable.h"
|
||||
#include "../gl/Shader.h"
|
||||
|
||||
|
||||
class Walls : public Renderable {
|
||||
|
||||
private:
|
||||
|
||||
Floorplan::Floor* floor;
|
||||
|
||||
GLTriangles<VertNormTexTan> triangles;
|
||||
GLLines outlines;
|
||||
|
||||
bool outlineOnly = false;
|
||||
bool transparent = false;
|
||||
|
||||
public:
|
||||
|
||||
/** ctor */
|
||||
Walls(Floorplan::Floor* floor) : floor(floor) {
|
||||
setOutlineOnly(false);
|
||||
}
|
||||
|
||||
|
||||
void initGL() override {
|
||||
|
||||
build();
|
||||
|
||||
triangles.build();
|
||||
triangles.setDiffuse(":/res/gl/tex/wall3.jpg");
|
||||
triangles.setNormalMap(":/res/gl/tex/wall3_normal.jpg");
|
||||
|
||||
outlines.build();
|
||||
|
||||
}
|
||||
|
||||
/** render the floor */
|
||||
void _render(const RenderParams& params) override {
|
||||
|
||||
// skip me?
|
||||
if (params.clipAboveHeight_m < floor->atHeight) {return;}
|
||||
|
||||
if (transparent) {
|
||||
program.setUniformValue("alpha", 0.5f);
|
||||
glEnable(GL_BLEND);
|
||||
} else {
|
||||
program.setUniformValue("alpha", 1.0f);
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
if (outlineOnly) {
|
||||
glLineWidth(1);
|
||||
outlines.render(&program);
|
||||
} else {
|
||||
triangles.render(&program);
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
}
|
||||
|
||||
/** render only the outline? */
|
||||
void setOutlineOnly(const bool outline) override {
|
||||
this->outlineOnly = outline;
|
||||
if (outlineOnly) {
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
|
||||
program.setUniformValue("color", QVector4D(0.9, 0.9, 0.9, 1.0));
|
||||
} else {
|
||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
|
||||
program.setUniformValue("texDiffuse", 0);
|
||||
program.setUniformValue("texNormalMap", 1);
|
||||
}
|
||||
}
|
||||
|
||||
void setTransparent(const bool transparent) override {
|
||||
this->transparent = transparent;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
void build() {
|
||||
|
||||
for (Floorplan::FloorObstacle* obstacle : floor->obstacles) {
|
||||
|
||||
if (dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle)) {
|
||||
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle);
|
||||
if (line->type != Floorplan::ObstacleType::WALL) {continue;}
|
||||
addFace(line->from, line->to, floor->getStartingZ(), floor->getEndingZ());
|
||||
} else if (dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle)) {
|
||||
Floorplan::FloorObstacleDoor* door = dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle);
|
||||
addFace(door->from, door->to, floor->getStartingZ() + door->height, floor->getEndingZ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void addFace(const Point2 from, const Point2 to, const float h1, const float h2) {
|
||||
|
||||
const QVector3D vert1(from.x, h1, from.y);
|
||||
const QVector3D vert2(to.x, h1, to.y);
|
||||
const QVector3D vert3(to.x, h2, to.y);
|
||||
const QVector3D vert4(from.x, h2, from.y);
|
||||
|
||||
const QVector3D n1 = GLHelper::getNormal(vert1, vert2, vert3);
|
||||
const QVector3D n2 = -n1;
|
||||
|
||||
|
||||
|
||||
QVector3D tan = (vert1-vert2).normalized();
|
||||
tan = GLHelper::isCCW(vert1, vert2, vert3) ? (tan) : (-tan);
|
||||
|
||||
const float l = from.getDistance(to);
|
||||
const float h = h2-h1;
|
||||
const float o = std::min(from.length(), to.length());
|
||||
|
||||
const QVector2D tex1(o+0, h); // start texturing at the ceiling so above-door-sections and walls have the same textre
|
||||
const QVector2D tex2(o+l, h);
|
||||
const QVector2D tex3(o+l, 0);
|
||||
const QVector2D tex4(o+0, 0);
|
||||
|
||||
const float s = 0.65;
|
||||
|
||||
|
||||
|
||||
{
|
||||
const VertNormTexTan vnt1(vert1, n1, tex1*s, tan);
|
||||
const VertNormTexTan vnt2(vert2, n1, tex2*s, tan);
|
||||
const VertNormTexTan vnt3(vert3, n1, tex3*s, tan);
|
||||
const VertNormTexTan vnt4(vert4, n1, tex4*s, tan);
|
||||
triangles.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
|
||||
} {
|
||||
const VertNormTexTan vnt1(vert1, n2, tex1*s, -tan);
|
||||
const VertNormTexTan vnt2(vert2, n2, tex2*s, -tan);
|
||||
const VertNormTexTan vnt3(vert3, n2, tex3*s, -tan);
|
||||
const VertNormTexTan vnt4(vert4, n2, tex4*s, -tan);
|
||||
triangles.addQuadCW(vnt1, vnt2, vnt3, vnt4);
|
||||
}
|
||||
|
||||
outlines.addLine(vert1, vert2);
|
||||
outlines.addLine(vert2, vert3);
|
||||
outlines.addLine(vert3, vert4);
|
||||
outlines.addLine(vert4, vert1);
|
||||
|
||||
}
|
||||
|
||||
//private:
|
||||
//
|
||||
// QVector2D tex(const QVector3D vert) {
|
||||
// return QVector2D(vert.x(), vert.y());
|
||||
// }
|
||||
|
||||
};
|
||||
|
||||
#endif // WALLS_H
|
||||
Reference in New Issue
Block a user