This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
Indoor/floorplan/v2/FloorplanLINT.h
kazu d40032ca74 interface changes
added new data-strcutures for new sensors
new helper methods
fixed some issues
2017-05-24 09:23:27 +02:00

229 lines
6.4 KiB
C++

#ifndef FLOORPLANLINT_H
#define FLOORPLANLINT_H
#include "Floorplan.h"
#include "../../geo/BBox2.h"
#include <iostream>
#include <vector>
namespace Floorplan {
class LINT {
public:
/** 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()) {
res.push_back(Issue(Type::ERROR, floor, "has no outline"));
}
// check outline
for (const FloorOutlinePolygon* poly : floor->outline) {
checkOutline(res, floor, poly);
}
// check obstacles
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);
}
// check elevators
for (const Elevator* e : floor->elevators) {
checkElevator(res, floor, e);
}
}
// done
return res;
}
private:
/** check a floor's outline */
static void checkOutline(Issues& res, const Floor* floor, const FloorOutlinePolygon* poly) {
// number of points valid?
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) {res.push_back(Issue(Type::ERROR, floor, "' outline '" + poly->name + "' seems too small"));}
}
/** check walls, doors, ... */
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) {
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()));
}
}
// door? -> check
const FloorObstacleDoor* door = dynamic_cast<const FloorObstacleDoor*>(fo);
if (door) {
const float len_m = door->from.getDistance(door->to);
if (len_m < 0.40) {
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) {
if (stair->getParts().empty()) {
res.push_back(Issue(Type::ERROR, floor, "stair does not contain any parts! [empty stair]"));
return;
}
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!"));
}
}
}
}
static void checkElevator(Issues& res, const Floor* floor, const Elevator* e) {
if (e->depth < 0.5) {
res.push_back(Issue(Type::ERROR, floor, "elevator's depth @" + e->center.asString() + " is too small: " + std::to_string(e->depth) + "m"));
}
if (e->width < 0.5) {
res.push_back(Issue(Type::ERROR, floor, "elevator's width @" + e->center.asString() + " is too small: " + std::to_string(e->width) + "m"));
}
}
};
}
#endif // FLOORPLANLINT_H