added new sanity checks and compile-time assertions to prevent errors
fixed stair-building issue new test-cases added elevator support fixed/improved some walker modules
This commit is contained in:
@@ -116,6 +116,7 @@ namespace Floorplan {
|
||||
struct UnderlayImage;
|
||||
struct POI;
|
||||
struct Stair;
|
||||
struct Elevator;
|
||||
|
||||
using FloorOutline = std::vector<FloorOutlinePolygon*>;
|
||||
using FloorObstacles = std::vector<FloorObstacle*>;
|
||||
@@ -125,6 +126,7 @@ namespace Floorplan {
|
||||
using FloorUnderlays = std::vector<UnderlayImage*>;
|
||||
using FloorPOIs = std::vector<POI*>;
|
||||
using FloorStairs = std::vector<Stair*>;
|
||||
using FloorElevators = std::vector<Elevator*>;
|
||||
|
||||
/** describes one floor within the map, starting at a given height */
|
||||
struct Floor {
|
||||
@@ -140,6 +142,7 @@ namespace Floorplan {
|
||||
FloorUnderlays underlays; // underlay images (used for map-building)
|
||||
FloorPOIs pois; // POIs within the floor
|
||||
FloorStairs stairs; // all stairs within one floor
|
||||
FloorElevators elevators; // all elevators within one floor
|
||||
//FloorKeyValue other; // other, free elements
|
||||
|
||||
Floor() {;}
|
||||
@@ -249,8 +252,6 @@ namespace Floorplan {
|
||||
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);
|
||||
}
|
||||
@@ -305,7 +306,36 @@ namespace Floorplan {
|
||||
|
||||
};
|
||||
|
||||
static std::vector<Quad3> getQuads(const std::vector<StairPart>& parts, const Floor* floor) {
|
||||
|
||||
/** snap quad-edges together if their distance is below the given maximum. is used to close minor gaps */
|
||||
static void snapQuads(std::vector<Floorplan::Quad3>& quads, const float maxDist) {
|
||||
|
||||
for (Floorplan::Quad3& quad1 : quads) {
|
||||
for (int i1 = 0; i1 < 4; ++i1) {
|
||||
Point3& p1 = (Point3&) quad1[i1];
|
||||
for (const Floorplan::Quad3& quad2 : quads) {
|
||||
|
||||
if (&quad1 == &quad2) {continue;}
|
||||
for (int i1 = 0; i1 < 4; ++i1) {
|
||||
Point3& p2 = (Point3&) quad2[i1];
|
||||
|
||||
if (p1.getDistance(p2) < maxDist) {
|
||||
const Point3 p3 = (p1+p2) / 2;
|
||||
p1 = p3;
|
||||
p2 = p3;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** convert stair-parts to quads. the scaling factor may be used to slightly grow each quad. e.g. needed to ensure that the quads overlap */
|
||||
static std::vector<Quad3> getQuads(const std::vector<StairPart>& parts, const Floor* floor, const float s = 1.0f) {
|
||||
|
||||
std::vector<Quad3> vec;
|
||||
|
||||
@@ -318,10 +348,10 @@ namespace Floorplan {
|
||||
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 Point3 p1 = start + xy0(perpN * width*s / 2) + Point3(0,0,floor->atHeight);
|
||||
const Point3 p2 = start - xy0(perpN * width*s / 2) + Point3(0,0,floor->atHeight);
|
||||
const Point3 p3 = end - xy0(perpN * width*s / 2) + Point3(0,0,floor->atHeight);
|
||||
const Point3 p4 = end + xy0(perpN * width*s / 2) + Point3(0,0,floor->atHeight);
|
||||
const Quad3 q(p1,p2,p3,p4);
|
||||
vec.push_back(q);
|
||||
|
||||
@@ -337,17 +367,12 @@ namespace Floorplan {
|
||||
|
||||
}
|
||||
|
||||
snapQuads(vec, 0.05);
|
||||
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 {
|
||||
@@ -355,43 +380,6 @@ namespace Floorplan {
|
||||
virtual std::vector<StairPart> 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<StairPart> getParts() const {
|
||||
// std::vector<StairPart> 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<Point3> nodes;
|
||||
// StairFreeformOLD() {;}
|
||||
// std::vector<StairPart> getParts() const {
|
||||
// std::vector<StairPart> 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<StairPart> parts;
|
||||
@@ -399,7 +387,42 @@ namespace Floorplan {
|
||||
std::vector<StairPart> getParts() const {return parts;}
|
||||
};
|
||||
|
||||
/**
|
||||
* describes an elevator between two floors
|
||||
* so: the height depends on the height of the floor!
|
||||
*/
|
||||
struct Elevator {
|
||||
|
||||
/** the elevator's center */
|
||||
Point2 center;
|
||||
|
||||
/** the elevator's width (in meter) */
|
||||
float width;
|
||||
|
||||
/** the elevator's depth (in meter) */
|
||||
float depth;
|
||||
|
||||
/** the elevator's rotation (in radians) */
|
||||
float rotation;
|
||||
|
||||
/** get the 4 corner points for the elevator */
|
||||
Polygon2 getPoints() const {
|
||||
const Point2 p1 = Point2(+width/2, +depth/2).rotated(rotation) + center;
|
||||
const Point2 p2 = Point2(-width/2, +depth/2).rotated(rotation) + center;
|
||||
const Point2 p3 = Point2(-width/2, -depth/2).rotated(rotation) + center;
|
||||
const Point2 p4 = Point2(+width/2, -depth/2).rotated(rotation) + center;
|
||||
Polygon2 poly;
|
||||
poly.points = {p1, p2, p3, p4};
|
||||
return poly;
|
||||
}
|
||||
|
||||
/** empty ctor */
|
||||
Elevator() : center(), width(2), depth(2), rotation(0) {;}
|
||||
|
||||
/** ctor */
|
||||
Elevator(const Point2 center) : center(center), width(2), depth(2), rotation(0) {;}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -88,11 +88,21 @@ namespace Floorplan {
|
||||
if (std::string("underlays") == n->Name()) {floor->underlays = parseFloorUnderlays(n);}
|
||||
if (std::string("pois") == n->Name()) {floor->pois = parseFloorPOIs(n);}
|
||||
if (std::string("stairs") == n->Name()) {floor->stairs = parseFloorStairs(n);}
|
||||
if (std::string("elevators") == n->Name()) {floor->elevators = parseFloorElevators(n);}
|
||||
}
|
||||
return floor;
|
||||
}
|
||||
|
||||
|
||||
/** parse the <elevators> tag */
|
||||
static std::vector<Elevator*> parseFloorElevators(const XMLElem* el) {
|
||||
std::vector<Elevator*> vec;
|
||||
FOREACH_NODE(n, el) {
|
||||
if (std::string("elevator") == n->Name()) { vec.push_back(parseFloorElevator(n)); }
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
/** parse the <stairs> tag */
|
||||
static std::vector<Stair*> parseFloorStairs(const XMLElem* el) {
|
||||
std::vector<Stair*> vec;
|
||||
@@ -102,6 +112,16 @@ namespace Floorplan {
|
||||
return vec;
|
||||
}
|
||||
|
||||
/** parse an <elevator> tag */
|
||||
static Elevator* parseFloorElevator(const XMLElem* el) {
|
||||
Elevator* elev = new Elevator();
|
||||
elev->center = Point2(el->FloatAttribute("cx"), el->FloatAttribute("cy"));
|
||||
elev->depth = el->FloatAttribute("depth");
|
||||
elev->width = el->FloatAttribute("width");
|
||||
elev->rotation = el->FloatAttribute("rotation");
|
||||
return elev;
|
||||
}
|
||||
|
||||
/** parse a <stair> tag */
|
||||
static Stair* parseFloorStair(const XMLElem* el) {
|
||||
Stair* stair = nullptr;
|
||||
|
||||
@@ -78,6 +78,24 @@ namespace Floorplan {
|
||||
addFloorPOI(doc, floor, mf);
|
||||
|
||||
addStairs(doc, floor, mf);
|
||||
addElevators(doc, floor, mf);
|
||||
|
||||
}
|
||||
|
||||
/** add all elevators to the floor */
|
||||
static void addElevators(XMLDoc& doc, XMLElem* floor, const Floor* mf) {
|
||||
|
||||
XMLElem* elevators = doc.NewElement("elevators");
|
||||
for (const Elevator* elevator : mf->elevators) {
|
||||
XMLElem* elem = doc.NewElement("elevator");
|
||||
elem->SetAttribute("cx", elevator->center.x);
|
||||
elem->SetAttribute("cy", elevator->center.y);
|
||||
elem->SetAttribute("width", elevator->width);
|
||||
elem->SetAttribute("depth", elevator->depth);
|
||||
elem->SetAttribute("rotation", elevator->rotation);
|
||||
elevators->InsertEndChild(elem);
|
||||
}
|
||||
floor->InsertEndChild(elevators);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user