changes to Floorplan 3D
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "Handrails.h"
|
||||
#include "Objects.h"
|
||||
#include "Pillars.h"
|
||||
#include "Doors.h"
|
||||
|
||||
#include "Walls.h"
|
||||
#include "WallsViaCubes.h"
|
||||
@@ -102,6 +103,8 @@ namespace Floorplan3D {
|
||||
res.insert(res.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (exportHandrails) {
|
||||
Handrails rails;
|
||||
const std::vector<Obstacle3D> tmp = rails.getHandrails(f);
|
||||
@@ -120,6 +123,12 @@ namespace Floorplan3D {
|
||||
res.insert(res.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
if (exportDoors) {
|
||||
Doors doors;
|
||||
const std::vector<Obstacle3D> tmp = doors.getDoors(f);
|
||||
res.insert(res.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
|
||||
// for (const Floorplan::FloorObstacle* fo : f->obstacles) {
|
||||
// std::vector<Obstacle3D> tmp = getWalls(f);
|
||||
// res.insert(res.end(), tmp.begin(), tmp.end());
|
||||
@@ -161,7 +170,11 @@ namespace Floorplan3D {
|
||||
|
||||
for (const Floorplan::FloorObstacle* obs : f->obstacles) {
|
||||
const Floorplan::FloorObstacleLine* line = dynamic_cast<const Floorplan::FloorObstacleLine*>(obs);
|
||||
if (line) {walls.add(f, line, nullptr);}
|
||||
if (line) {
|
||||
if (line->type == Floorplan::ObstacleType::WALL) {
|
||||
walls.add(f, line, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return walls.get();
|
||||
|
||||
67
floorplan/3D/Doors.h
Normal file
67
floorplan/3D/Doors.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef FLOORPLAN_3D_DOORS_H
|
||||
#define FLOORPLAN_3D_DOORS_H
|
||||
|
||||
#include "Walls.h"
|
||||
#include "misc.h"
|
||||
#include "primitives/Cube.h"
|
||||
|
||||
namespace Floorplan3D {
|
||||
|
||||
class Doors {
|
||||
|
||||
Cube::Part cubeParts = (Cube::Part) 63; // leftright,topbottom,rearfront
|
||||
|
||||
public:
|
||||
|
||||
std::vector<Obstacle3D> getDoors(const Floorplan::Floor* floor) {
|
||||
std::vector<Obstacle3D> res;
|
||||
for (const Floorplan::FloorObstacle* o: floor->obstacles) {
|
||||
const Floorplan::FloorObstacleWall* wall = dynamic_cast<const Floorplan::FloorObstacleWall*>(o);
|
||||
if (wall) {
|
||||
for (const Floorplan::FloorObstacleWallDoor* door : wall->doors) {
|
||||
res.push_back(getDoor(floor, wall, door));
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Obstacle3D getDoor(const Floorplan::Floor* f, const Floorplan::FloorObstacleWall* wall, const Floorplan::FloorObstacleWallDoor* door) {
|
||||
|
||||
FloorPos fpos(f);
|
||||
|
||||
const float thickness_m = 0.1;
|
||||
const Point2 from = door->getStart(wall);
|
||||
const Point2 to = door->getEnd(wall);
|
||||
const Point2 cen2 = (from+to)/2;
|
||||
|
||||
const float rad = std::atan2(to.y - from.y, to.x - from.x);
|
||||
const float deg = rad * 180 / M_PI;
|
||||
|
||||
// cube's destination center
|
||||
const double height = door->height;
|
||||
const double cenZ = (fpos.z1 + height/2);
|
||||
const Point3 pos(cen2.x, cen2.y, cenZ);
|
||||
|
||||
// div by 2.01 to prevent overlapps and z-fighting
|
||||
const float sx = from.getDistance(to) / 2;
|
||||
const float sy = thickness_m / 2;
|
||||
const float sz = height / 2.01f; // prevent overlaps
|
||||
const Point3 size(sx, sy, sz);
|
||||
const Point3 rot(0,0,deg);
|
||||
|
||||
// build
|
||||
Cube cube(pos, size, rot, cubeParts);
|
||||
|
||||
// done
|
||||
Obstacle3D res(Obstacle3D::Type::DOOR, door->material);
|
||||
res.triangles = cube.getTriangles();
|
||||
return res;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FLOORPLAN_3D_DOORS_H
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <vector>
|
||||
#include "../../geo/Triangle3.h"
|
||||
#include "../../geo/Sphere3.h"
|
||||
#include "../../geo/TriangleStrip3.h"
|
||||
|
||||
#include "../v2/Floorplan.h"
|
||||
|
||||
@@ -41,15 +42,35 @@ namespace Floorplan3D {
|
||||
|
||||
|
||||
/** append a new triangle. REFERENCE ONLY VALID UNTIL NEXT ADD */
|
||||
Triangle3& addTriangle(const Point3 p1, const Point3 p2, const Point3 p3) {
|
||||
triangles.push_back(Triangle3(p1, p2, p3));
|
||||
Triangle3& addTriangle(const Point3 p1, const Point3 p2, const Point3 p3, const bool reverse) {
|
||||
Triangle3 t(p1, p2, p3);
|
||||
if (reverse) {t.reverse();}
|
||||
triangles.push_back(t);
|
||||
return triangles.back();
|
||||
}
|
||||
|
||||
void addTriangleStrip(std::initializer_list<Point3> pts, bool reverse = false) {
|
||||
TriangleStrip3 strip;
|
||||
for (const Point3& p : pts) {strip.add(p);}
|
||||
for (Triangle3 t : strip.toTriangles()) {
|
||||
if (reverse) {t.reverse();}
|
||||
triangles.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
void addTriangleStrip(const std::vector<Point3>& pts, bool reverse = false) {
|
||||
TriangleStrip3 strip;
|
||||
for (const Point3& p : pts) {strip.add(p);}
|
||||
for (Triangle3 t : strip.toTriangles()) {
|
||||
if (reverse) {t.reverse();}
|
||||
triangles.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
/** append a new quad by splitting into two triangles */
|
||||
void addQuad(const Point3 p1, const Point3 p2, const Point3 p3, const Point3 p4) {
|
||||
addTriangle(p1, p2, p3);
|
||||
addTriangle(p1, p3, p4);
|
||||
void addQuad(const Point3 p1, const Point3 p2, const Point3 p3, const Point3 p4, const bool reverse = false) {
|
||||
addTriangle(p1, p2, p3, reverse);
|
||||
addTriangle(p1, p3, p4, reverse);
|
||||
}
|
||||
|
||||
/** reverse all faces (CW<->CCW) */
|
||||
|
||||
@@ -167,26 +167,205 @@ namespace Floorplan3D {
|
||||
}
|
||||
|
||||
|
||||
/** convert one wall into an obstacle */
|
||||
Obstacle3D toObstacle(const Wall& wall, const Floorplan::Floor* f) {
|
||||
Obstacle3D toObstacle(const Wall& w, const Floorplan::Floor* f) {
|
||||
|
||||
FloorPos fp(f);
|
||||
|
||||
Obstacle3D::Type type = (wall.error) ? (Obstacle3D::Type::ERROR) : (getType(wall.line));
|
||||
Obstacle3D obs(type, wall.line->material);
|
||||
const Floorplan::FloorObstacleWall* wall = w.line;
|
||||
Obstacle3D::Type type = (w.error) ? (Obstacle3D::Type::ERROR) : (getType(wall));
|
||||
Obstacle3D obs(type, wall->material);
|
||||
|
||||
const float z1 = fp.z1;
|
||||
const float z2 = (wall.line->height_m > 0) ? (fp.z1 + wall.line->height_m) : (fp.z2);
|
||||
const float z2 = (wall->height_m > 0) ? (fp.z1 + wall->height_m) : (fp.z2);
|
||||
|
||||
// const Point3 p1 = Point3(wall.getP1().x, wall.getP1().y, z1);
|
||||
// const Point3 p2 = Point3(wall.getP2().x, wall.getP2().y, z1);
|
||||
// const Point3 p3 = Point3(wall.getP3().x, wall.getP3().y, z1);
|
||||
// const Point3 p4 = Point3(wall.getP4().x, wall.getP4().y, z1);
|
||||
const Point3 p1 = Point3(w.getP1().x, w.getP1().y, z1); // front
|
||||
const Point3 p2 = Point3(w.getP2().x, w.getP2().y, z1); // front
|
||||
const Point3 p3 = Point3(w.getP3().x, w.getP3().y, z1); // back
|
||||
const Point3 p4 = Point3(w.getP4().x, w.getP4().y, z1); // back
|
||||
|
||||
const Point3 p1u = Point3(w.getP1().x, w.getP1().y, z2); // front upper
|
||||
const Point3 p2u = Point3(w.getP2().x, w.getP2().y, z2); // front upper
|
||||
const Point3 p3u = Point3(w.getP3().x, w.getP3().y, z2); // back upper
|
||||
const Point3 p4u = Point3(w.getP4().x, w.getP4().y, z2); // back upper
|
||||
|
||||
const Point2 dir = (wall->to - wall->from).normalized();
|
||||
const Point2 perp = dir.perpendicular().normalized() * (wall->thickness_m/2);
|
||||
|
||||
// move from wall's center line towards front (- half thickness)
|
||||
auto toFront = [perp] (const Point2 pt, const float z) {
|
||||
const Point2 tmp = pt + perp;
|
||||
return Point3(tmp.x, tmp.y, z);
|
||||
};
|
||||
|
||||
// move from wall's center line towards back (+ half thickness)
|
||||
auto toBack = [perp] (const Point2 pt, const float z) {
|
||||
const Point2 tmp = pt - perp;
|
||||
return Point3(tmp.x, tmp.y, z);
|
||||
};
|
||||
|
||||
// above window, below window, window frame
|
||||
for (const Floorplan::FloorObstacleWallWindow* win : wall->windows) {
|
||||
|
||||
// quad below the window (1,2,3,4) CCW
|
||||
// quad above the window (5,6,7,8) CCW
|
||||
// -> window = (4,3,6,5) CCW
|
||||
|
||||
const float za = z1 + win->startsAtHeight;
|
||||
const float zb = za + win->height;
|
||||
|
||||
const Point3 p1f = toFront(win->getStart(wall), z1);
|
||||
const Point3 p2f = toFront(win->getEnd(wall), z1);
|
||||
const Point3 p3f = toFront(win->getEnd(wall), za);
|
||||
const Point3 p4f = toFront(win->getStart(wall), za);
|
||||
|
||||
const Point3 p1b = toBack(win->getStart(wall), z1);
|
||||
const Point3 p2b = toBack(win->getEnd(wall), z1);
|
||||
const Point3 p3b = toBack(win->getEnd(wall), za);
|
||||
const Point3 p4b = toBack(win->getStart(wall), za);
|
||||
|
||||
const Point3 p5f = toFront(win->getStart(wall), zb);
|
||||
const Point3 p6f = toFront(win->getEnd(wall), zb);
|
||||
const Point3 p7f = toFront(win->getEnd(wall), z2);
|
||||
const Point3 p8f = toFront(win->getStart(wall), z2);
|
||||
|
||||
const Point3 p5b = toBack(win->getStart(wall), zb);
|
||||
const Point3 p6b = toBack(win->getEnd(wall), zb);
|
||||
const Point3 p7b = toBack(win->getEnd(wall), z2);
|
||||
const Point3 p8b = toBack(win->getStart(wall), z2);
|
||||
|
||||
// quad below the window
|
||||
obs.addQuad(p1f, p2f, p3f, p4f, true); // front
|
||||
obs.addQuad(p1b, p2b, p3b, p4b, false); // back
|
||||
|
||||
// quad above the window
|
||||
obs.addQuad(p5f, p6f, p7f, p8f, true); // front
|
||||
obs.addQuad(p5b, p6b, p7b, p8b, false); // back
|
||||
|
||||
// window frame
|
||||
obs.addTriangleStrip({p4f, p4b, p3f, p3b, p6f, p6b, p5f, p5b, p4f, p4b});
|
||||
|
||||
}
|
||||
|
||||
// start mantle surface (zig-zag around the wall)
|
||||
std::vector<Point3> ptsLateralSurface;
|
||||
ptsLateralSurface.push_back(p1);
|
||||
ptsLateralSurface.push_back(p4);
|
||||
|
||||
|
||||
// sort doors along the wall
|
||||
std::vector<Floorplan::FloorObstacleWallDoor*> doors = wall->doors;
|
||||
std::sort(doors.begin(), doors.end(), [] (const Floorplan::FloorObstacleWallDoor* d1, const Floorplan::FloorObstacleWallDoor* d2) {
|
||||
return d1->atLinePos < d2->atLinePos;
|
||||
});
|
||||
|
||||
// above door, append lateral surface around wall
|
||||
for (const Floorplan::FloorObstacleWallDoor* door : doors) {
|
||||
|
||||
Point2 ps = door->getStart(wall);
|
||||
Point2 pe = door->getEnd(wall);
|
||||
if (door->leftRight) {std::swap(ps,pe);}
|
||||
|
||||
const float zb = z1 + door->height;
|
||||
|
||||
{
|
||||
|
||||
const Point3 p1f = toFront(ps, zb);
|
||||
const Point3 p2f = toFront(pe, zb);
|
||||
const Point3 p3f = toFront(pe, z2);
|
||||
const Point3 p4f = toFront(ps, z2);
|
||||
|
||||
const Point3 p1b = toBack(ps, zb);
|
||||
const Point3 p2b = toBack(pe, zb);
|
||||
const Point3 p3b = toBack(pe, z2);
|
||||
const Point3 p4b = toBack(ps, z2);
|
||||
|
||||
// quad above the door (front)
|
||||
obs.addQuad(p1f, p2f, p3f, p4f, true);
|
||||
|
||||
// quad above the door (back)
|
||||
obs.addQuad(p1b, p2b, p3b, p4b, false);
|
||||
|
||||
}
|
||||
|
||||
const Point3 p1f = toFront(ps, z1);
|
||||
const Point3 p2f = toFront(pe, z1);
|
||||
const Point3 p3f = toFront(pe, zb);
|
||||
const Point3 p4f = toFront(ps, zb);
|
||||
|
||||
const Point3 p1b = toBack(ps, z1);
|
||||
const Point3 p2b = toBack(pe, z1);
|
||||
const Point3 p3b = toBack(pe, zb);
|
||||
const Point3 p4b = toBack(ps, zb);
|
||||
|
||||
// continue mantle surface
|
||||
ptsLateralSurface.push_back(p1f);
|
||||
ptsLateralSurface.push_back(p1b);
|
||||
ptsLateralSurface.push_back(p4f);
|
||||
ptsLateralSurface.push_back(p4b);
|
||||
ptsLateralSurface.push_back(p3f);
|
||||
ptsLateralSurface.push_back(p3b);
|
||||
ptsLateralSurface.push_back(p2f);
|
||||
ptsLateralSurface.push_back(p2b);
|
||||
|
||||
}
|
||||
|
||||
// complete mantle surface
|
||||
ptsLateralSurface.push_back(p2);
|
||||
ptsLateralSurface.push_back(p3);
|
||||
ptsLateralSurface.push_back(p2u);
|
||||
ptsLateralSurface.push_back(p3u);
|
||||
ptsLateralSurface.push_back(p1u);
|
||||
ptsLateralSurface.push_back(p4u);
|
||||
ptsLateralSurface.push_back(p1);
|
||||
ptsLateralSurface.push_back(p4);
|
||||
obs.addTriangleStrip(ptsLateralSurface, true);
|
||||
|
||||
// get all points along the wall start, doorstart,doorend, doorstart,doorend, .., end
|
||||
std::vector<Point3> ptsFront;
|
||||
ptsFront.push_back(p1);
|
||||
ptsFront.push_back(p2);
|
||||
|
||||
std::vector<Point3> ptsBack;
|
||||
ptsBack.push_back(p3);
|
||||
ptsBack.push_back(p4);
|
||||
|
||||
for (const Floorplan::FloorObstacleWallDoor* door : wall->doors) {
|
||||
ptsFront.push_back(toFront(door->getStart(wall), z1));
|
||||
ptsFront.push_back(toFront(door->getEnd(wall), z1));
|
||||
ptsBack.push_back(toBack(door->getStart(wall), z1));
|
||||
ptsBack.push_back(toBack(door->getEnd(wall), z1));
|
||||
}
|
||||
for (const Floorplan::FloorObstacleWallWindow* window : wall->windows) {
|
||||
ptsFront.push_back(toFront(window->getStart(wall), z1));
|
||||
ptsFront.push_back(toFront(window->getEnd(wall), z1));
|
||||
ptsBack.push_back(toBack(window->getStart(wall), z1));
|
||||
ptsBack.push_back(toBack(window->getEnd(wall), z1));
|
||||
}
|
||||
|
||||
// sort all points by distance from start (correct on-off-on-off-on order)
|
||||
auto compFront = [p1] (const Point3 _p1, const Point3 _p2) { return p1.getDistance(_p1) < p1.getDistance(_p2); };
|
||||
std::sort(ptsFront.begin(), ptsFront.end(), compFront);
|
||||
auto compBack = [p4] (const Point3 _p1, const Point3 _p2) { return p4.getDistance(_p1) < p4.getDistance(_p2); };
|
||||
std::sort(ptsBack.begin(), ptsBack.end(), compBack);
|
||||
|
||||
// from wall segment to wall segment, excluding doors
|
||||
|
||||
for (size_t i = 0; i < ptsFront.size(); i += 2) {
|
||||
const Point3 p1 = ptsFront[i+0];
|
||||
const Point3 p2 = ptsFront[i+1];
|
||||
const Point3 p3(p2.x, p2.y, z2);
|
||||
const Point3 p4(p1.x, p1.y, z2);
|
||||
obs.addQuad(p1, p2, p3, p4, true);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < ptsBack.size(); i += 2) {
|
||||
const Point3 p1 = ptsBack[i+0];
|
||||
const Point3 p2 = ptsBack[i+1];
|
||||
const Point3 p3(p2.x, p2.y, z2);
|
||||
const Point3 p4(p1.x, p1.y, z2);
|
||||
obs.addQuad(p1, p2, p3, p4, false);
|
||||
}
|
||||
|
||||
// const Point3 p1u = Point3(wall.getP1().x, wall.getP1().y, z2);
|
||||
// const Point3 p2u = Point3(wall.getP2().x, wall.getP2().y, z2);
|
||||
// const Point3 p3u = Point3(wall.getP3().x, wall.getP3().y, z2);
|
||||
// const Point3 p4u = Point3(wall.getP4().x, wall.getP4().y, z2);
|
||||
|
||||
// obs.addQuad(p1, p2, p2u, p1u);
|
||||
// obs.addQuad(p2, p3, p3u, p2u);
|
||||
@@ -198,7 +377,58 @@ namespace Floorplan3D {
|
||||
|
||||
// obs.reverseFaces();
|
||||
|
||||
// return obs;
|
||||
return obs;
|
||||
}
|
||||
|
||||
/*
|
||||
Obstacle3D toObstacle(const Wall& wall, const Floorplan::Floor* f) {
|
||||
|
||||
FloorPos fp(f);
|
||||
|
||||
Obstacle3D::Type type = (wall.error) ? (Obstacle3D::Type::ERROR) : (getType(wall.line));
|
||||
Obstacle3D obs(type, wall.line->material);
|
||||
|
||||
const float z1 = fp.z1;
|
||||
const float z2 = (wall.line->height_m > 0) ? (fp.z1 + wall.line->height_m) : (fp.z2);
|
||||
|
||||
const Point3 p1 = Point3(wall.getP1().x, wall.getP1().y, z1);
|
||||
const Point3 p2 = Point3(wall.getP2().x, wall.getP2().y, z1);
|
||||
const Point3 p3 = Point3(wall.getP3().x, wall.getP3().y, z1);
|
||||
const Point3 p4 = Point3(wall.getP4().x, wall.getP4().y, z1);
|
||||
|
||||
const Point3 p1u = Point3(wall.getP1().x, wall.getP1().y, z2);
|
||||
const Point3 p2u = Point3(wall.getP2().x, wall.getP2().y, z2);
|
||||
const Point3 p3u = Point3(wall.getP3().x, wall.getP3().y, z2);
|
||||
const Point3 p4u = Point3(wall.getP4().x, wall.getP4().y, z2);
|
||||
|
||||
obs.addQuad(p1, p2, p2u, p1u);
|
||||
obs.addQuad(p2, p3, p3u, p2u);
|
||||
obs.addQuad(p3, p4, p4u, p3u);
|
||||
obs.addQuad(p4, p1, p1u, p4u);
|
||||
|
||||
obs.addQuad(p1u, p2u, p3u, p4u);
|
||||
obs.addQuad(p4, p3, p2, p1);
|
||||
|
||||
obs.reverseFaces();
|
||||
|
||||
return obs;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/** convert one wall into an obstacle */
|
||||
/*
|
||||
Obstacle3D toObstacle(const Wall& wall, const Floorplan::Floor* f) {
|
||||
|
||||
FloorPos fp(f);
|
||||
|
||||
Obstacle3D::Type type = (wall.error) ? (Obstacle3D::Type::ERROR) : (getType(wall.line));
|
||||
Obstacle3D obs(type, wall.line->material);
|
||||
|
||||
const float z1 = fp.z1;
|
||||
const float z2 = (wall.line->height_m > 0) ? (fp.z1 + wall.line->height_m) : (fp.z2);
|
||||
|
||||
|
||||
|
||||
Point3 p0 = Point3(wall.line->from.x, wall.line->from.y, z1);
|
||||
|
||||
@@ -394,6 +624,7 @@ namespace Floorplan3D {
|
||||
return obs;
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
void fixTria(Triangle3& t, std::function<Point3(Point3)> func) {
|
||||
t.p1 = func(t.p1);
|
||||
|
||||
@@ -5,59 +5,7 @@
|
||||
#include "Polygon2.h"
|
||||
#include "Triangle3.h"
|
||||
|
||||
class TriangleStrip {
|
||||
|
||||
private:
|
||||
std::vector<Point3> pts;
|
||||
|
||||
public:
|
||||
|
||||
void add(const Point3 p) {
|
||||
pts.push_back(p);
|
||||
}
|
||||
|
||||
void set(const std::vector<Point3>& pts) {
|
||||
this->pts = pts;
|
||||
}
|
||||
|
||||
void toTriangles(std::vector<Triangle3>& trias) const {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Triangle_strip
|
||||
// GL_TRIANGLE_STRIP
|
||||
// Draws a series of triangles (three-sided polygons) using vertices v0, v1, v2, then v2, v1, v3 (note the order), then v2, v3, v4, and so on. The ordering is to ensure that the triangles are all drawn with the same orientation so that the strip can correctly form part of a surface.
|
||||
// For odd n, vertices n, n+1, and n+2 define triangle n. For even n, vertices n+1, n, and n+2 define triangle n. N-2 triangles are drawn.
|
||||
|
||||
|
||||
|
||||
for (size_t j = 2; j < pts.size(); ++j) {
|
||||
|
||||
|
||||
if (j % 2 == 0) {
|
||||
Triangle3 tria(
|
||||
pts[j-2],
|
||||
pts[j-1],
|
||||
pts[j]
|
||||
);
|
||||
trias.push_back(tria);
|
||||
} else {
|
||||
Triangle3 tria(
|
||||
pts[j-1],
|
||||
pts[j-2],
|
||||
pts[j]
|
||||
);
|
||||
trias.push_back(tria);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<Triangle3> toTriangles() const {
|
||||
std::vector<Triangle3> trias;
|
||||
toTriangles(trias);
|
||||
return trias;
|
||||
}
|
||||
|
||||
};
|
||||
#include "TriangleStrip3.h"
|
||||
|
||||
class GPCPolygon2 {
|
||||
|
||||
@@ -168,7 +116,7 @@ public:
|
||||
for (int i = 0; i < res.num_strips; ++i) {
|
||||
gpc_vertex_list lst = res.strip[i];
|
||||
|
||||
TriangleStrip strip;
|
||||
TriangleStrip3 strip;
|
||||
for (int j = 0; j < lst.num_vertices; ++j) {
|
||||
gpc_vertex& v = lst.vertex[j];
|
||||
strip.add(Point3(v.x, v.y, z));
|
||||
|
||||
59
geo/TriangleStrip3.h
Normal file
59
geo/TriangleStrip3.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#ifndef TRIANGLESTRIP3_H
|
||||
#define TRIANGLESTRIP3_H
|
||||
|
||||
#include <vector>
|
||||
#include "Point3.h"
|
||||
#include "Triangle3.h"
|
||||
|
||||
class TriangleStrip3 {
|
||||
|
||||
private:
|
||||
std::vector<Point3> pts;
|
||||
|
||||
public:
|
||||
|
||||
void add(const Point3 p) {
|
||||
pts.push_back(p);
|
||||
}
|
||||
|
||||
void set(const std::vector<Point3>& pts) {
|
||||
this->pts = pts;
|
||||
}
|
||||
|
||||
void toTriangles(std::vector<Triangle3>& trias) const {
|
||||
|
||||
// https://en.wikipedia.org/wiki/Triangle_strip
|
||||
// GL_TRIANGLE_STRIP
|
||||
// Draws a series of triangles (three-sided polygons) using vertices v0, v1, v2, then v2, v1, v3 (note the order), then v2, v3, v4, and so on. The ordering is to ensure that the triangles are all drawn with the same orientation so that the strip can correctly form part of a surface.
|
||||
// For odd n, vertices n, n+1, and n+2 define triangle n. For even n, vertices n+1, n, and n+2 define triangle n. N-2 triangles are drawn.
|
||||
|
||||
for (size_t j = 2; j < pts.size(); ++j) {
|
||||
|
||||
if (j % 2 == 0) {
|
||||
Triangle3 tria(
|
||||
pts[j-2],
|
||||
pts[j-1],
|
||||
pts[j]
|
||||
);
|
||||
trias.push_back(tria);
|
||||
} else {
|
||||
Triangle3 tria(
|
||||
pts[j-1],
|
||||
pts[j-2],
|
||||
pts[j]
|
||||
);
|
||||
trias.push_back(tria);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<Triangle3> toTriangles() const {
|
||||
std::vector<Triangle3> trias;
|
||||
toTriangles(trias);
|
||||
return trias;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // TRIANGLESTRIP3_H
|
||||
@@ -137,16 +137,24 @@ namespace NM {
|
||||
// get all obstacles of this floor and remove them from the polygon as well (many will be outside of the added polygon)
|
||||
for (Floorplan::FloorObstacle* obs : floor->obstacles) {
|
||||
|
||||
// wall-obstacles
|
||||
Floorplan::FloorObstacleWall* wall = dynamic_cast<Floorplan::FloorObstacleWall*>(obs);
|
||||
if (wall != nullptr) {
|
||||
for (const Floorplan::Polygon2& poly : getPolygons(wall, false)) {
|
||||
nmPoly.remove(poly);
|
||||
}
|
||||
}
|
||||
|
||||
// line-obstacles
|
||||
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obs);
|
||||
if (line != nullptr) {
|
||||
nmPoly.remove(getPolygon(line));
|
||||
nmPoly.remove(getPolygon(line));
|
||||
}
|
||||
|
||||
// object-obstacles
|
||||
Floorplan::FloorObstacleObject* obj = dynamic_cast<Floorplan::FloorObstacleObject*>(obs);
|
||||
if (obj != nullptr) {
|
||||
nmPoly.remove(getPolygon(obj));
|
||||
nmPoly.remove(getPolygon(obj));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -201,6 +209,15 @@ namespace NM {
|
||||
}
|
||||
}
|
||||
|
||||
for (Floorplan::FloorObstacle* obs : floor->obstacles) {
|
||||
Floorplan::FloorObstacleWall* wall = dynamic_cast<Floorplan::FloorObstacleWall*>(obs);
|
||||
if (wall != nullptr) {
|
||||
for (const Floorplan::Polygon2& poly : getPolygons(wall, true)) {
|
||||
nmDoors.add(poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// construct and add triangles
|
||||
std::vector<std::vector<Point3>> tmp = nmDoors.get();
|
||||
for (const std::vector<Point3>& tria : tmp) {
|
||||
@@ -626,6 +643,58 @@ namespace NM {
|
||||
return res;
|
||||
}
|
||||
|
||||
/** create all polygons describing the walls floor outline, excluding doors */
|
||||
std::vector<Floorplan::Polygon2> getPolygons(const Floorplan::FloorObstacleWall* wall, bool invert) const {
|
||||
|
||||
// invert = true -> door polygons
|
||||
// invert = false -> wall polygons
|
||||
|
||||
const float thickness_m = std::max(wall->thickness_m, settings.maxQuality_m); // wall's thickness (make thin walls big enough to be detected)
|
||||
|
||||
// get all points along the wall start, doorstart,doorend, doorstart,doorend, .., end
|
||||
std::vector<Point2> pts;
|
||||
pts.push_back(wall->from);
|
||||
pts.push_back(wall->to);
|
||||
for (const Floorplan::FloorObstacleWallDoor* door : wall->doors) {
|
||||
pts.push_back(door->getStart(wall));
|
||||
pts.push_back(door->getEnd(wall));
|
||||
}
|
||||
|
||||
// sort all points by distance from start (correct on-off-on-off-on order)
|
||||
auto comp = [wall] (const Point2 p1, const Point2 p2) {
|
||||
return wall->from.getDistance(p1) < wall->from.getDistance(p2);
|
||||
};
|
||||
std::sort(pts.begin(), pts.end(), comp);
|
||||
|
||||
std::vector<Floorplan::Polygon2> polys;
|
||||
|
||||
const size_t start = (invert) ? (1) : (0);
|
||||
|
||||
// from wall segment to wall segment, excluding doors
|
||||
for (size_t i = start; i < pts.size()-start; i += 2) {
|
||||
|
||||
const Point2 ps = pts[i+0];
|
||||
const Point2 pe = pts[i+1];
|
||||
|
||||
const Point2 dir = (pe - ps); // part's direction
|
||||
const Point2 perp = dir.perpendicular().normalized(); // perpendicular direction (90 degree)
|
||||
const Point2 p1 = ps + perp * thickness_m/2; // start-up
|
||||
const Point2 p2 = ps - perp * thickness_m/2; // start-down
|
||||
const Point2 p3 = pe + perp * thickness_m/2; // end-up
|
||||
const Point2 p4 = pe - perp * thickness_m/2; // end-down
|
||||
Floorplan::Polygon2 res;
|
||||
res.points.push_back(p1);
|
||||
res.points.push_back(p2);
|
||||
res.points.push_back(p4);
|
||||
res.points.push_back(p3);
|
||||
polys.push_back(res);
|
||||
|
||||
}
|
||||
|
||||
return polys;
|
||||
|
||||
}
|
||||
|
||||
/** convert the given 3D object to a polygon outline */
|
||||
Floorplan::Polygon2 getPolygon(const Floorplan::FloorObstacleObject* obj) const {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user