Merge branch 'master' of https://git.frank-ebner.de/FHWS/Indoor
This commit is contained in:
208
floorplan/v2/FloorplanLINT.h
Normal file
208
floorplan/v2/FloorplanLINT.h
Normal file
@@ -0,0 +1,208 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
||||
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!"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // FLOORPLANLINT_H
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "Floorplan.h"
|
||||
#include "FloorplanLINT.h"
|
||||
|
||||
#include "../../misc/Debug.h"
|
||||
#include "../../Assertions.h"
|
||||
@@ -431,9 +432,6 @@ namespace Floorplan {
|
||||
poly.points.push_back(p2);
|
||||
}
|
||||
}
|
||||
if (poly.points.size() < 4 || poly.points.size() > 1024) {
|
||||
throw Exception("detected invalid outline-polygon during XML parsing");
|
||||
}
|
||||
return poly;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
}
|
||||
|
||||
/** returns true if the bbox is not yet configured */
|
||||
const bool isInvalid() const {
|
||||
bool isInvalid() const {
|
||||
return p1.x == MAX || p1.y == MAX || p2.x == MIN || p2.y == MIN;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@ public:
|
||||
/** get the bbox's maximum */
|
||||
const Point2& getMax() const {return p2;}
|
||||
|
||||
/** get the bbox's size [max-min] */
|
||||
const Point2 getSize() const {return p2-p1;}
|
||||
|
||||
/** get the bbox's center point */
|
||||
Point2 getCenter() const { return (p1+p2) / 2; }
|
||||
|
||||
|
||||
@@ -61,6 +61,10 @@ struct Point2 {
|
||||
return std::sqrt(dx*dx + dy*dy);
|
||||
}
|
||||
|
||||
std::string asString() const {
|
||||
return "(" + std::to_string(x) + "," + std::to_string(y) + ")";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline void swap(Point2& p1, Point2& p2) {
|
||||
|
||||
Reference in New Issue
Block a user