adjusted floorplan-lint for GUI integration

This commit is contained in:
2017-03-20 14:44:17 +01:00
parent 3868e42937
commit 4ac248d08e
2 changed files with 142 additions and 15 deletions

View File

@@ -4,59 +4,132 @@
#include "Floorplan.h"
#include "../../geo/BBox2.h"
#include <iostream>
#include <vector>
namespace Floorplan {
class LINT {
public:
static void check(IndoorMap* map) {
/** possible issue types */
enum class Type {
WARN,
ERROR,
};
/** type -> string */
static std::string getTypeStr(const Type t) {
switch(t) {
case Type::WARN: return "WARNING";
case Type::ERROR: return "ERROR";
default: throw Exception("code error. invalid type. todo!");
}
}
/** a detected issue */
struct Issue {
Type type;
const Floor* floor;
std::string desc;
Issue(const Type type, const Floor* floor, const std::string& desc) : type(type), floor(floor), desc(desc) {;}
/** issue to string */
std::string asString() const {
return getTypeStr(type) + ": " + "floor '" + floor->name + "': " + desc;
}
};
using Issues = std::vector<Issue>;
public:
/** throw in case of errors within the map */
static void assertOK(IndoorMap* map) {
const Issues issues = check(map);
int err = 0;
for (const Issue& i : issues) {
std::cout << i.asString() << std::endl;
if (i.type == Type::ERROR) {++err;}
}
if (err > 0) {
throw Exception("detected floorplan errors");
}
}
/** get all errors within the map */
static Issues check(IndoorMap* map) {
Issues res;
for (const Floor* floor : map->floors) {
// outline present?
if (floor->outline.empty()) {throw Exception("floor " + floor->name + " has no outline");}
if (floor->outline.empty()) {
res.push_back(Issue(Type::ERROR, floor, "has no outline"));
}
// check outline
for (FloorOutlinePolygon* poly : floor->outline) {
checkOutline(floor, poly);
for (const FloorOutlinePolygon* poly : floor->outline) {
checkOutline(res, floor, poly);
}
// check obstacles
for (FloorObstacle* obs : floor->obstacles) {
checkObstacle(floor, obs);
for (const FloorObstacle* obs : floor->obstacles) {
checkObstacle(res, floor, obs);
}
// check fingerprints
for (const FingerprintLocation* fpl : floor->fpLocations) {
checkFingerprintLoc(res, floor, fpl);
}
// check stairs
for (const Stair* s : floor->stairs) {
checkStair(res, floor, s);
}
}
// done
return res;
}
private:
/** check a floor's outline */
static void checkOutline(const Floor* floor, const FloorOutlinePolygon* poly) {
static void checkOutline(Issues& res, const Floor* floor, const FloorOutlinePolygon* poly) {
// number of points valid?
if (poly->poly.points.size() < 3) {throw Exception("floor '" + floor->name + "' outline '" + poly->name + "' needs at least 3 edges");}
if (poly->poly.points.size() > 1024) {throw Exception("floor '" + floor->name + "' outline '" + poly->name + "' has too many edges");}
if (poly->poly.points.size() < 3) {res.push_back(Issue(Type::ERROR, floor, "' outline '" + poly->name + "' needs at least 3 edges"));}
if (poly->poly.points.size() > 1024) {res.push_back(Issue(Type::ERROR, floor, "' outline '" + poly->name + "' has too many edges"));}
// outline size [bbox] valid?
BBox2 outline;
for (const Point2 pt : poly->poly.points) { outline.add(pt); }
const Point2 size = outline.getSize();
if (size.x < 1.0 || size.y < 1.0) {throw Exception("floor '" + floor->name + "' outline '" + poly->name + "' seems too small");}
if (size.x < 1.0 || size.y < 1.0) {res.push_back(Issue(Type::ERROR, floor, "' outline '" + poly->name + "' seems too small"));}
}
/** check walls, doors, ... */
static void checkObstacle(const Floor* floor, const FloorObstacle* fo) {
static void checkObstacle(Issues& res, const Floor* floor, const FloorObstacle* fo) {
// line? -> check
const FloorObstacleLine* line = dynamic_cast<const FloorObstacleLine*>(fo);
if (line) {
const float len_m = line->from.getDistance(line->to);
if (len_m < 0.15) {
throw Exception("floor '" + floor->name + "' line-obstacle is too short: " + std::to_string(len_m) + " meter from " + line->from.asString() + " to " + line->to.asString());
res.push_back(Issue(Type::WARN, floor, "' line-obstacle is too short: " + std::to_string(len_m) + " meter from " + line->from.asString() + " to " + line->to.asString()));
}
}
@@ -65,10 +138,66 @@ namespace Floorplan {
if (door) {
const float len_m = door->from.getDistance(door->to);
if (len_m < 0.40) {
throw Exception("floor '" + floor->name + "' door is too narrow: " + std::to_string(len_m) + " meter from " + door->from.asString() + " to " + door->to.asString());
res.push_back(Issue(Type::ERROR, floor, "' door is too narrow: " + std::to_string(len_m) + " meter from " + door->from.asString() + " to " + door->to.asString()));
}
}
// pillar? -> check
const FloorObstacleCircle* circle = dynamic_cast<const FloorObstacleCircle*>(fo);
if (circle) {
const float len_m = circle->radius;
if (len_m < 0.20) {
res.push_back(Issue(Type::ERROR, floor, "' pillar is too narrow: " + std::to_string(len_m) + " meter at " + circle->center.asString()));
}
}
}
static void checkFingerprintLoc(Issues& res, const Floor* floor, const FingerprintLocation* fpl) {
const std::string note = "does it belong to a stair? if so: fine! Note: fingerprints are currently measured using smartphones and smartphone are held by the pedestian. thus: fingerprints are ~1.3 meter above ground";
if (fpl->heightAboveFloor < 0.8) {
res.push_back(Issue(Type::ERROR, floor, std::string() + "fingerprint " + fpl->name + " @ " + fpl->getPosition(*floor).asString() + " is too near to the floor. " + note));
} else if (fpl->heightAboveFloor > 2.0) {
res.push_back(Issue(Type::WARN, floor, std::string() + "fingerprint " + fpl->name + " @ " + fpl->getPosition(*floor).asString() + " is too high above the floor. " + note));
}
}
static void checkStair(Issues& res, const Floor* floor, const Stair* stair) {
const std::vector<Floorplan::StairPart> parts = stair->getParts();
const std::vector<Floorplan::Quad3> quads = Floorplan::getQuads(parts, floor);
const Floorplan::Quad3& quadS = quads.front();
const Floorplan::Quad3& quadE = quads.back();
// disconnected start?
if (quadS.p1.z != floor->getStartingZ()) {
res.push_back(Issue(Type::ERROR, floor, "stair is not connected to the starting floor's ground! [open stair start]"));
}
// disconnected end?
if (quadE.p3.z != floor->getEndingZ()) {
res.push_back(Issue(Type::ERROR, floor, "stair is not connected to the ending floor's ground! [open stair end]"));
}
for (int i = 0; i < (int) parts.size(); ++i) {
const Floorplan::Quad3& quad = quads[i];
// disconnected within?
if (i > 0) {
if (quads[i-1].p4.z != quads[i-0].p1.z) {
res.push_back(Issue(Type::ERROR, floor, "stair is disconnected within!"));
}
}
}
}
};

View File

@@ -41,7 +41,6 @@ namespace Floorplan {
);
}
IndoorMap* map = parse(doc);
Floorplan::LINT::check(map);
return map;
}
@@ -59,7 +58,6 @@ namespace Floorplan {
);
}
IndoorMap* map = parse(doc);
Floorplan::LINT::check(map);
return map;
}