746 lines
22 KiB
C++
746 lines
22 KiB
C++
/*
|
||
* © 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)
|
||
*/
|
||
|
||
#ifndef FLOORPLAN_3D_WALLSVIACUTTEDQUADS_H
|
||
#define FLOORPLAN_3D_WALLSVIACUTTEDQUADS_H
|
||
|
||
#include "../../geo/Line2.h"
|
||
#include "../../geo/Polygon2.h"
|
||
#include "../../geo/GPCPolygon2.h"
|
||
|
||
//#include "Walls.h"
|
||
#include "misc.h"
|
||
|
||
#include <functional>
|
||
#include <iostream>
|
||
|
||
namespace Floorplan3D {
|
||
|
||
/**
|
||
* interpret walls als quads (polygons)
|
||
* intersect them with each other to prevent overlaps
|
||
*/
|
||
class WallsViaCuttedQuads {
|
||
|
||
private:
|
||
|
||
struct Wall {
|
||
|
||
/** algorithms set error flag here */
|
||
bool error = false;
|
||
|
||
/** original line from floorplan */
|
||
const Floorplan::FloorObstacleWall* line;
|
||
|
||
/** outlines after applying thickness */
|
||
Line2 l1;
|
||
Line2 l2;
|
||
|
||
Wall(const Floorplan::FloorObstacleWall* line) : line(line) {
|
||
|
||
const Point2 from = line->from;
|
||
const Point2 to = line->to;
|
||
const Point2 dir = (to-from).normalized();
|
||
const Point2 dirP = dir.perpendicular();
|
||
const float w = line->thickness_m;
|
||
const float w2 = w/2;
|
||
|
||
const Point2 p1 = from + dirP * w2;
|
||
const Point2 p2 = from - dirP * w2;
|
||
const Point2 p3 = to - dirP * w2;
|
||
const Point2 p4 = to + dirP * w2;
|
||
|
||
l1 = Line2(p1, p4);
|
||
l2 = Line2(p2, p3);
|
||
|
||
}
|
||
|
||
/** get points for CCW wall outline (p1->p2->p3->p4) */
|
||
Point2 getP1() const {return l1.p1;}
|
||
Point2 getP2() const {return l1.p2;}
|
||
Point2 getP3() const {return l2.p2;}
|
||
Point2 getP4() const {return l2.p1;}
|
||
|
||
Point2& getP1() {return l1.p1;}
|
||
Point2& getP2() {return l1.p2;}
|
||
Point2& getP3() {return l2.p2;}
|
||
Point2& getP4() {return l2.p1;}
|
||
|
||
struct CutRes {
|
||
Point2 p;
|
||
Line2* l1; // affected line within this wall
|
||
Line2* l2; // affected line within the other wall
|
||
CutRes(Point2 p, Line2* l1, Line2* l2) : p(p), l1(l1), l2(l2) {;}
|
||
};
|
||
|
||
/** get all intersecting points between the two walls */
|
||
std::vector<CutRes> getIntersections(Wall& o, bool limit = true) {
|
||
std::vector<CutRes> res;
|
||
Point2 p;
|
||
if (intersects(l1, o.l1, limit, p)) {res.push_back(CutRes(p,&l1, &o.l1));}
|
||
if (intersects(l1, o.l2, limit, p)) {res.push_back(CutRes(p,&l1, &o.l2));}
|
||
if (intersects(l2, o.l1, limit, p)) {res.push_back(CutRes(p,&l2, &o.l1));}
|
||
if (intersects(l2, o.l2, limit, p)) {res.push_back(CutRes(p,&l2, &o.l2));}
|
||
return res;
|
||
}
|
||
|
||
/** is this wall directly attached to the given wall? */
|
||
bool directlyConnectedTo(const Wall& o) const {
|
||
const float d = 0.001;
|
||
return
|
||
(line->from.eq( o.line->from, d)) ||
|
||
(line->to.eq( o.line->from, d)) ||
|
||
(line->from.eq( o.line->to, d)) ||
|
||
(line->to.eq( o.line->to, d));
|
||
}
|
||
|
||
/** does this wall end within the given wall? */
|
||
bool endsWithin(const Wall& o) const {
|
||
return o.containsPoint(line->from) || o.containsPoint(line->to);
|
||
}
|
||
|
||
/** does this wall contain the given point */
|
||
bool containsPoint(const Point2 p) const {
|
||
return polygonContainsPoint({getP1(), getP2(), getP3(), getP4()}, p);
|
||
}
|
||
|
||
};
|
||
|
||
void cropLine(Line2* l, Point2 p) {
|
||
|
||
// determine which line-end to crop
|
||
if (p.getDistance(l->p1) < p.getDistance(l->p2)) {
|
||
l->p1 = p;
|
||
} else {
|
||
l->p2 = p;
|
||
}
|
||
|
||
}
|
||
|
||
void cutInMiddle(Point2& pa1, Point2& pa2, Point2& pb1, Point2& pb2) {
|
||
|
||
// line from pa1->pa2, and pb1->pb2
|
||
// intersection expected near pa2|pb1
|
||
|
||
Line2 l1(pa1, pa2); l1 = l1.longerAtEnd(10);
|
||
Line2 l2(pb1, pb2); l2 = l2.longerAtStart(10);
|
||
|
||
Point2 pi;
|
||
if (intersects(l1, l2, true, pi)) {
|
||
pa2 = pi; // replace end of line1
|
||
pb1 = pi; // replace start of line2
|
||
}
|
||
|
||
}
|
||
|
||
std::vector<Wall> walls;
|
||
const Floorplan::Floor* floor;
|
||
std::vector<Obstacle3D> obs;
|
||
|
||
public:
|
||
|
||
|
||
void clear() {
|
||
walls.clear();
|
||
}
|
||
|
||
void add(const Floorplan::Floor* f, const Floorplan::FloorObstacleWall* fow) {
|
||
if (fow->type != Floorplan::ObstacleType::WALL) {return;}
|
||
this->floor = f;
|
||
walls.push_back(Wall(fow));
|
||
}
|
||
|
||
virtual const std::vector<Obstacle3D>& get() {
|
||
std::vector<Wall> tmp = walls;
|
||
tmp = cutConnected(tmp);
|
||
tmp = cutProtruding(tmp);
|
||
obs = toObstacle(tmp, floor);
|
||
return obs;
|
||
}
|
||
|
||
private:
|
||
|
||
/** convert all walls to obstacles */
|
||
std::vector<Obstacle3D> toObstacle(const std::vector<Wall>& walls, const Floorplan::Floor* f) {
|
||
std::vector<Obstacle3D> res;
|
||
for (const Wall& w : walls) {
|
||
res.push_back(toObstacle(w, f));
|
||
}
|
||
return res;
|
||
}
|
||
|
||
|
||
Obstacle3D toObstacle(const Wall& w, const Floorplan::Floor* f) {
|
||
|
||
FloorPos fp(f);
|
||
|
||
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->height_m > 0) ? (fp.z1 + wall->height_m) : (fp.z2);
|
||
|
||
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);
|
||
}
|
||
|
||
|
||
// 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;
|
||
}
|
||
|
||
/*
|
||
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);
|
||
|
||
Point3 p1 = Point3(wall.getP1().x, wall.getP1().y, z1);
|
||
Point3 p2 = Point3(wall.getP2().x, wall.getP2().y, z1);
|
||
Point3 p3 = Point3(wall.getP3().x, wall.getP3().y, z1);
|
||
Point3 p4 = Point3(wall.getP4().x, wall.getP4().y, z1);
|
||
|
||
Point3 p1u = Point3(wall.getP1().x, wall.getP1().y, z2);
|
||
Point3 p2u = Point3(wall.getP2().x, wall.getP2().y, z2);
|
||
Point3 p3u = Point3(wall.getP3().x, wall.getP3().y, z2);
|
||
Point3 p4u = Point3(wall.getP4().x, wall.getP4().y, z2);
|
||
|
||
Point3 o = p0;
|
||
float t = wall.line->thickness_m / 2;
|
||
|
||
const Point3 o1;// = p1;
|
||
const Point3 o2;// = p4;
|
||
const float a = std::atan2(wall.getP2().y - wall.getP1().y, wall.getP2().x - wall.getP1().x);
|
||
|
||
auto flatten = [a,o] (const Point3 p) {return (p - o).rotZ(-a).xz();};
|
||
//auto flatten2 = [a,o] (const Point3 p) {return (p - o).rotZ(-a).xz();};
|
||
|
||
auto unFlattenFront = [o,t,a] (const Point3 p) {return Point3(p.x, +t, p.y).rotZ(a)+o;};
|
||
auto unFlattenBack = [o,t,a] (const Point3 p) {return Point3(p.x, -t, p.y).rotZ(a)+o;};
|
||
|
||
auto unFlattenFront2 = [o,t,a] (const Point2 p) {return Point3(p.x, +t, p.y).rotZ(a)+o;};
|
||
auto unFlattenBack2 = [o,t,a] (const Point2 p) {return Point3(p.x, -t, p.y).rotZ(a)+o;};
|
||
|
||
const Point2 fp1 = flatten(p1);
|
||
const Point2 fp2 = flatten(p2);
|
||
const Point2 fp3 = flatten(p3);
|
||
const Point2 fp4 = flatten(p4);
|
||
const Point2 fp1u = flatten(p1u);
|
||
const Point2 fp2u = flatten(p2u);
|
||
const Point2 fp3u = flatten(p3u);
|
||
const Point2 fp4u = flatten(p4u);
|
||
|
||
|
||
Polygon2 front;
|
||
front.add({fp1, fp2, fp2u, fp1u});
|
||
|
||
GPCPolygon2 gpFront;
|
||
gpFront.add(front);
|
||
|
||
Polygon2 back;
|
||
back.add({fp3, fp4, fp4u, fp3u});
|
||
|
||
GPCPolygon2 gpBack;
|
||
gpBack.add(back);
|
||
|
||
// sort doors by their position within the wall (first comes first)
|
||
std::vector<Floorplan::FloorObstacleWallDoor*> doors = wall.line->doors;
|
||
auto compDoors = [] (const Floorplan::FloorObstacleWallDoor* d1, Floorplan::FloorObstacleWallDoor* d2) {
|
||
return d1->atLinePos < d2->atLinePos;
|
||
};
|
||
std::sort(doors.begin(), doors.end(), compDoors);
|
||
|
||
|
||
TriangleStrip strip;
|
||
|
||
strip.add(p1);
|
||
strip.add(p4);
|
||
|
||
for (const Floorplan::FloorObstacleWallDoor* door : doors) {
|
||
|
||
Point2 pds = door->getStart(wall.line);
|
||
Point2 pde = door->getEnd(wall.line);
|
||
|
||
// inverted door, swap start and end for correct triangle order
|
||
if (door->leftRight) {
|
||
std::swap(pds, pde);
|
||
}
|
||
|
||
const Point3 dp1(pds.x, pds.y, z1);
|
||
const Point3 dp2(pde.x, pde.y, z1);
|
||
const Point3 dp2u(pde.x, pde.y, z1+door->height);
|
||
const Point3 dp1u(pds.x, pds.y, z1+door->height);
|
||
|
||
Polygon2 pDoor;
|
||
pDoor.add(flatten(dp1));
|
||
pDoor.add(flatten(dp2));
|
||
pDoor.add(flatten(dp2u));
|
||
pDoor.add(flatten(dp1u));
|
||
|
||
// wall cutout (front/back)
|
||
gpFront.remove(pDoor);
|
||
gpBack.remove(pDoor);
|
||
|
||
// 3D framing
|
||
strip.add(unFlattenFront2(pDoor[0]));
|
||
strip.add(unFlattenBack2(pDoor[0]));
|
||
|
||
strip.add(unFlattenFront2(pDoor[3]));
|
||
strip.add(unFlattenBack2(pDoor[3]));
|
||
|
||
strip.add(unFlattenFront2(pDoor[2]));
|
||
strip.add(unFlattenBack2(pDoor[2]));
|
||
|
||
strip.add(unFlattenFront2(pDoor[1]));
|
||
strip.add(unFlattenBack2(pDoor[1]));
|
||
|
||
}
|
||
|
||
strip.add(p2);
|
||
strip.add(p3);
|
||
strip.add(p2u);
|
||
strip.add(p3u);
|
||
strip.add(p1u);
|
||
strip.add(p4u);
|
||
strip.add(p1);
|
||
strip.add(p4);
|
||
|
||
for (Triangle3 t : strip.toTriangles()) {
|
||
t.reverse();
|
||
obs.triangles.push_back(t);
|
||
}
|
||
|
||
// process all windows within the wall
|
||
|
||
for (const Floorplan::FloorObstacleWallWindow* win : wall.line->windows) {
|
||
|
||
const Point2 pws = win->getStart(wall.line);
|
||
const Point2 pwe = win->getEnd(wall.line);
|
||
|
||
const float wz1 = z1 + win->startsAtHeight;
|
||
const float wz2 = z1 + win->startsAtHeight + win->height;
|
||
|
||
const Point3 dp1(pws.x, pws.y, wz1);
|
||
const Point3 dp2(pwe.x, pwe.y, wz1);
|
||
const Point3 dp2u(pwe.x, pwe.y, wz2);
|
||
const Point3 dp1u(pws.x, pws.y, wz2);
|
||
|
||
Polygon2 pWindow;
|
||
pWindow.add(flatten(dp1));
|
||
pWindow.add(flatten(dp2));
|
||
pWindow.add(flatten(dp2u));
|
||
pWindow.add(flatten(dp1u));
|
||
|
||
// wall cutout (front/back)
|
||
gpFront.remove(pWindow);
|
||
gpBack.remove(pWindow);
|
||
|
||
// 3D framing
|
||
TriangleStrip strip;
|
||
|
||
strip.add(unFlattenFront2(pWindow[0]));
|
||
strip.add(unFlattenBack2(pWindow[0]));
|
||
|
||
strip.add(unFlattenFront2(pWindow[3]));
|
||
strip.add(unFlattenBack2(pWindow[3]));
|
||
|
||
strip.add(unFlattenFront2(pWindow[2]));
|
||
strip.add(unFlattenBack2(pWindow[2]));
|
||
|
||
strip.add(unFlattenFront2(pWindow[1]));
|
||
strip.add(unFlattenBack2(pWindow[1]));
|
||
|
||
strip.add(unFlattenFront2(pWindow[0]));
|
||
strip.add(unFlattenBack2(pWindow[0]));
|
||
|
||
for (Triangle3 t : strip.toTriangles()) {
|
||
t.reverse();
|
||
obs.triangles.push_back(t);
|
||
}
|
||
|
||
}
|
||
|
||
// Frontseite triangulieren
|
||
std::vector<Triangle3> triasFront = gpFront.getTriangles();
|
||
|
||
for (Triangle3 tria : triasFront) {
|
||
fixTria(tria, unFlattenFront);
|
||
tria.reverse();
|
||
obs.triangles.push_back(tria);
|
||
}
|
||
|
||
// Rückseite triangulieren
|
||
std::vector<Triangle3> triasBack = gpBack.getTriangles();
|
||
|
||
for (Triangle3 tria : triasBack) {
|
||
fixTria(tria, unFlattenBack);
|
||
obs.triangles.push_back(tria);
|
||
}
|
||
|
||
|
||
// for (const Floorplan::FloorObstacleWallDoor* door : wall.line->doors) {
|
||
// const Point2 p1 = door->getStart(wall.line);
|
||
// const Point2 p2 = door->getEnd(wall.line);
|
||
|
||
// }
|
||
|
||
return obs;
|
||
|
||
}
|
||
*/
|
||
|
||
void fixTria(Triangle3& t, std::function<Point3(Point3)> func) {
|
||
t.p1 = func(t.p1);
|
||
t.p2 = func(t.p2);
|
||
t.p3 = func(t.p3);
|
||
}
|
||
|
||
/** cut off walls ending within another wall */
|
||
std::vector<Wall> cutProtruding(std::vector<Wall> walls) {
|
||
|
||
// if one wall ends within another one cut it off
|
||
|
||
for (size_t i = 0; i < walls.size(); ++i) {
|
||
Wall& w1 = walls[i];
|
||
|
||
for (size_t j = i+1; j < walls.size(); ++j) {
|
||
Wall& w2 = walls[j];
|
||
|
||
if (i == j) {continue;}
|
||
|
||
// if the two walls are directly connected (share one node) -> ignore this case here!
|
||
if (w1.directlyConnectedTo(w2)) {continue;}
|
||
|
||
// not the case we are looking for?
|
||
if (!w1.endsWithin(w2) && !w2.endsWithin(w1)) {continue;}
|
||
|
||
// get all intersection points between the two walls
|
||
std::vector<Wall::CutRes> isects = w1.getIntersections(w2);
|
||
|
||
// this should be 0 (no intersections) or 2 (one for each outline)
|
||
if (!isects.empty() && isects.size() != 2) {
|
||
w1.error = true;
|
||
w2.error = true;
|
||
std::cout << "detected strange wall intersection" << std::endl;
|
||
}
|
||
|
||
int cut = 0;
|
||
|
||
// check the (2) detected intersections
|
||
for (const auto isect : isects) {
|
||
|
||
// if one of the line-ends p1/p2 from wall1 ends within wall2, crop it by setting it to the intersection
|
||
if (w2.containsPoint(isect.l1->p1)) {isect.l1->p1 = isect.p; ++cut;}
|
||
if (w2.containsPoint(isect.l1->p2)) {isect.l1->p2 = isect.p; ++cut;}
|
||
|
||
// if one of the line-ends p1/p2 from wall2 ends within wall1, crop it by setting it to the intersection
|
||
if (w1.containsPoint(isect.l2->p1)) {isect.l2->p1 = isect.p; ++cut;}
|
||
if (w1.containsPoint(isect.l2->p2)) {isect.l2->p2 = isect.p; ++cut;}
|
||
|
||
}
|
||
|
||
// 2 lines should have been cut. if not, potential issue!
|
||
if (cut != 2) {
|
||
w1.error = true;
|
||
w2.error = true;
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return walls;
|
||
|
||
}
|
||
|
||
|
||
/** if two walls share one node, cut both ends in the middle (like 45 degree) */
|
||
std::vector<Wall> cutConnected(std::vector<Wall> walls) {
|
||
|
||
for (size_t i = 0; i < walls.size(); ++i) {
|
||
Wall& w1 = walls[i];
|
||
|
||
for (size_t j = i+1; j < walls.size(); ++j) {
|
||
Wall& w2 = walls[j];
|
||
|
||
if (i == j) {continue;}
|
||
|
||
// if the two walls are note directly connected -> ignore
|
||
if (!w1.directlyConnectedTo(w2)) {continue;}
|
||
|
||
const float d = 0.001;
|
||
if (w1.line->to.eq(w2.line->from, d)) {
|
||
cutInMiddle(w1.getP1(), w1.getP2(), w2.getP1(), w2.getP2());
|
||
cutInMiddle(w1.getP4(), w1.getP3(), w2.getP4(), w2.getP3());
|
||
} else if (w1.line->to.eq(w2.line->to, d)) {
|
||
cutInMiddle(w1.getP1(), w1.getP2(), w2.getP3(), w2.getP4());
|
||
cutInMiddle(w1.getP4(), w1.getP3(), w2.getP2(), w2.getP1());
|
||
} else if (w1.line->from.eq(w2.line->to, d)) {
|
||
cutInMiddle(w1.getP3(), w1.getP4(), w2.getP3(), w2.getP4());
|
||
cutInMiddle(w1.getP2(), w1.getP1(), w2.getP2(), w2.getP1());
|
||
} else if (w1.line->from.eq(w2.line->from, d)) {
|
||
cutInMiddle(w1.getP3(), w1.getP4(), w2.getP1(), w2.getP2());
|
||
cutInMiddle(w1.getP2(), w1.getP1(), w2.getP4(), w2.getP3());
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
return walls;
|
||
|
||
}
|
||
|
||
};
|
||
|
||
}
|
||
|
||
#endif // FLOORPLAN_3D_WALLSVIACUTTEDQUADS_H
|