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:
2016-09-10 15:12:39 +02:00
parent 7baeecb3f9
commit 82f8828a04
26 changed files with 996 additions and 198 deletions

View File

@@ -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) {;}
};

View File

@@ -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;

View File

@@ -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);
}