#ifndef FLOORPLAN2_H #define FLOORPLAN2_H #include #include #include #include #include #include "../../geo/Point3.h" #include "../../geo/Point2.h" namespace Floorplan { /** convert string to upper case */ inline std::string toUpperCase(std::string str) { std::transform(str.begin(), str.end(), str.begin(), ::toupper); return str; } /** a free key-value meta element */ struct Meta { const std::string EMPTY = ""; std::unordered_map params; const std::string& getVal(const std::string& key) const { const auto it = params.find(key); return (it == params.end()) ? (EMPTY) : (it->second); } void setVal(const std::string& key, const std::string& val) {params[key] = val;} float getFloat(const std::string& key) const { return std::stof(getVal(key)); } void setFloat(const std::string& key, const float val) { params[key] = std::to_string(val); } int getInt(const std::string& key) const { return std::stoi(getVal(key)); } void setInt(const std::string& key, const int val) { params[key] = std::to_string(val); } }; /** 2D polygon */ struct Polygon2 { std::vector points; Polygon2() : points() {;} Polygon2(const std::initializer_list lst) : points(lst) {;} bool operator == (const Polygon2& o) const {return std::equal(o.points.begin(), o.points.end(), this->points.begin());} }; /** 3D quad */ struct Quad3 { Point3 p1; Point3 p2; Point3 p3; Point3 p4; Quad3(const Point3 p1, const Point3 p2, const Point3 p3, const Point3 p4) : p1(p1), p2(p2), p3(p3), p4(p4) {;} Quad3 operator * (const float v) const {return Quad3(p1*v, p2*v, p3*v, p4*v);} const Point3& operator [] (const int idx) const { switch (idx) { case 0: return p1; case 1: return p2; case 2: return p3; case 3: return p4; default: throw Exception("out of bounds"); } } }; /** additional type-info for obstacles */ enum class ObstacleType { UNKNOWN, WALL, WINDOW, HANDRAIL, PILLAR, _END, }; /** available door types */ enum class DoorType { UNKNOWN, SWING, // normal DOUBLE_SWING, SLIDE, // schiebetuer DOUBLE_SLIDE, REVOLVING, // drehtuer _END, }; /** all supported material types */ enum class Material { UNKNOWN, CONCRETE, WOOD, DRYWALL, GLASS, _END, }; enum class POIType { ROOM, }; /** types of outlines. either add or remove the selected region */ enum class OutlineMethod { ADD, REMOVE, _END, }; struct Floor; struct FloorOutlinePolygon; struct FloorObstacle; struct AccessPoint; struct Beacon; struct FloorRegion; struct UnderlayImage; struct POI; struct Stair; using FloorOutline = std::vector; using FloorObstacles = std::vector; using FloorAccessPoints = std::vector; using FloorBeacons = std::vector; using FloorRegions = std::vector; using FloorUnderlays = std::vector; using FloorPOIs = std::vector; using FloorStairs = std::vector; /** describes one floor within the map, starting at a given height */ struct Floor { float atHeight; // the floor's starting height float height; // the floor's total height (from start) std::string name; // the floor's name FloorOutline outline; // the floor's outline (ground) FloorObstacles obstacles; // all obstacles (wall, door, window, ..) within the floor FloorRegions regions; // all regions within the floor (rooms, ...) FloorAccessPoints accesspoints; FloorBeacons beacons; FloorUnderlays underlays; // underlay images (used for map-building) FloorPOIs pois; // POIs within the floor FloorStairs stairs; // all stairs within one floor //FloorKeyValue other; // other, free elements Floor() {;} Floor(const Floor& o) = delete; void operator = (const Floor& o) = delete; float getStartingZ() const {return atHeight;} float getEndingZ() const {return atHeight + height;} }; /** a POI located somewhere on a floor */ struct POI { POIType type; std::string name; Point2 pos; POI() : type(), name(), pos() {;} POI(const POIType type, const std::string& name, const Point2& pos) : type(type), name(name), pos(pos) {;} bool operator == (const POI& o) const {return (o.type == type) && (o.name == name) && (o.pos == pos);} }; /** an AccessPoint located somewhere on a floor */ struct AccessPoint { std::string name; std::string mac; Point3 pos; // z is relative to the floor's height AccessPoint() : name(), mac(), pos() {;} AccessPoint(const std::string& name, const std::string& mac, const Point3& pos) : name(name), mac(toUpperCase(mac)), pos(pos) {;} bool operator == (const AccessPoint& o) const {return (o.name == name) && (o.mac == mac) && (o.pos == pos);} Point3 getPos(const Floor* f) const {return pos + Point3(0,0,f->atHeight);} // relative to the floor's ground }; /** a beacon located somewhere on a floor */ struct Beacon { std::string name; std::string mac; Point3 pos; // z is relative to the floor's height Beacon() : name(), mac(), pos() {;} Beacon(const std::string& name, const std::string& mac, const Point3& pos) : name(name), mac(mac), pos(pos) {;} bool operator == (const Beacon& o) const {return (o.name == name) && (o.mac == mac) && (o.pos == pos);} }; /** a polygon denoting a floor's outline. is either added or removed */ struct FloorOutlinePolygon { OutlineMethod method; std::string name; Polygon2 poly; FloorOutlinePolygon() : method(OutlineMethod::ADD), name(), poly() {;} FloorOutlinePolygon(const OutlineMethod method, const std::string& name, const Polygon2& poly) : method(method), name(name), poly(poly) {;} bool operator == (const FloorOutlinePolygon& o) const {return (o.method == method) && (o.name == name) && (o.poly == poly);} }; /** base-class for one obstacle (wall, door, window, pillar, ..) within a floor */ struct FloorObstacle { Material material; FloorObstacle() : material() {;} FloorObstacle(const Material material) : material(material) {;} virtual ~FloorObstacle() {;} }; /** line obstacle */ struct FloorObstacleLine : public FloorObstacle { ObstacleType type; Point2 from; Point2 to; FloorObstacleLine(const ObstacleType type, const Material material, const Point2 from, const Point2 to) : FloorObstacle(material), type(type), from(from), to(to) {;} FloorObstacleLine(const ObstacleType type, const Material material, const float x1, const float y1, const float x2, const float y2) : FloorObstacle(material), type(type), from(x1,y1), to(x2,y2) {;} }; /** circle obstacle */ struct FloorObstacleCircle : public FloorObstacle { Point2 center; float radius; FloorObstacleCircle(const Material material, const Point2 center, const float radius) : FloorObstacle(material), center(center), radius(radius) {;} FloorObstacleCircle(const Material material, const float cx, const float cy, const float radius) : FloorObstacle(material), center(cx,cy), radius(radius) {;} }; /** door obstacle */ struct FloorObstacleDoor : public FloorObstacle { DoorType type; Point2 from; Point2 to; float height; bool swap; FloorObstacleDoor(const DoorType type, const Material material, const Point2 from, const Point2 to) : FloorObstacle(material), type(type), from(from), to(to), height(2.1), swap(false) {;} FloorObstacleDoor(const DoorType type, const Material material, const float x1, const float y1, const float x2, const float y2, const float height, const bool swap) : FloorObstacle(material), type(type), from(x1,y1), to(x2,y2), height(height), swap(swap) {;} float getSize() const {return (to-from).length();} }; /** one region (e.g. a room) within the floor, described using a polygon */ struct FloorRegion { std::string name; Polygon2 poly; FloorRegion() : name(), poly() {;} FloorRegion(const std::string& name, const Polygon2& poly) : name(name), poly(poly) {;} }; static Point3 xy0(const Point2 p) { return Point3(p.x, p.y, 0); } /** describes a plane as starting point, ending point and fixed width */ struct StairPart { /** z is relative to the floor's height */ Point3 start; /** z is relative to the floor's height */ Point3 end; /** the width for this element */ float width; /** whether to connect this element with the previous one */ bool connectWithPrev; StairPart() {;} StairPart(const Point3 start, const Point3 end, const float width) : start(start), end(end), width(width), connectWithPrev(false) {;} StairPart(Point3 center, float deg, float length, float width, float height) { this->start = Point3(-length/2, 0, -height/2); this->end = Point3(+length/2, 0, +height/2); this->width = width; rotate(deg/180.0*M_PI); move(center); } /** convenience method for array access [0:1] to start and end */ Point3& operator [] (const int idx) { switch (idx) { case 0: return start; case 1: return end; default: throw "error"; } } void rotate(const float rad) { const float ca = std::cos(rad); const float sa = std::sin(rad); start = Point3(ca*start.x - sa*start.y, sa*start.x + ca * start.y, start.z); end = Point3(ca*end.x - sa*end.y, sa*end.x + ca * end.y, end.z);; } void move(const Point3 p) { start += p; end += p; } }; static std::vector getQuads(const std::vector& parts, const Floor* floor) { std::vector vec; for (const StairPart& part : parts) { const float width = part.width; const Point3 start = part.start; const Point3 end = part.end; const Point3 dir = end - start; // direction vector const Point2 dir2(dir.x, dir.y); // direction without height (just 2D) const Point2 perp = dir2.perpendicular(); // perendicular vector const Point2 perpN = perp / perp.length(); // normalized perpendicular vector const Point3 p1 = start + xy0(perpN * width / 2) + Point3(0,0,floor->atHeight); const Point3 p2 = start - xy0(perpN * width / 2) + Point3(0,0,floor->atHeight); const Point3 p3 = end - xy0(perpN * width / 2) + Point3(0,0,floor->atHeight); const Point3 p4 = end + xy0(perpN * width / 2) + Point3(0,0,floor->atHeight); const Quad3 q(p1,p2,p3,p4); vec.push_back(q); // connect if (part.connectWithPrev) { if (vec.size() >= 2) { Quad3& a = vec[vec.size()-2]; Quad3& b = vec[vec.size()-1]; Point3 pa = (a.p3 + b.p2)/2; a.p3 = pa; b.p2 = pa; Point3 pb = (a.p4 + b.p1)/2; a.p4 = pb; b.p1 = pb; } } } return vec; } // /** // * get the ABSOLUTE quad for this stair-part // * (relative-height + floor-height = absolute-height // */ // Quad3 getQuad(const Floor* floor) const { // } /** base-class for stairs */ struct Stair { Meta* meta = nullptr; virtual std::vector getParts() const = 0; }; // /** just a normal, straigt stair */ // struct StairNormal : public Stair { // Point2 center; // float angleDeg; // float atHeight; // float height; // float width; // float length; // StairNormal(const Point2 center, const float atHeight, const float angleDeg, const float height, const float width, const float length) : // center(center), angleDeg(angleDeg), atHeight(atHeight), height(height), width(width), length(length) { // } // std::vector getParts() const { // std::vector parts; // Point3 cen(center.x, center.y, atHeight); // parts.push_back(StairPart(cen, angleDeg, length, width, height)); // return parts; // } // }; // /** OLD 3-part stair, up[left]->platform->up[right] */ // struct StairFreeformOLD : public Stair { // float width; // std::vector nodes; // StairFreeformOLD() {;} // std::vector getParts() const { // std::vector parts; // for (int i = 1; i < (int)nodes.size(); ++i) { // const Point3 p1 = nodes[i-1]; // const Point3 p2 = nodes[i ]; // parts.push_back(StairPart(p1, p2, width)); // } // return parts; // } // }; /** 3-part stair, up[left]->platform->up[right] */ struct StairFreeform : public Stair { std::vector parts; StairFreeform() {;} std::vector getParts() const {return parts;} }; /** an image file that can be added to the map */ struct UnderlayImage { std::string name; std::string filename; Point2 anchor; float scaleX; float scaleY; }; /** describes the whole indoor map */ struct IndoorMap { float width; float depth; std::vector floors; IndoorMap() {;} IndoorMap(const IndoorMap& o) = delete; void operator = (const IndoorMap& o) = delete; }; } #endif // FLOORPLAN2_H