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/FloorplanReader.h
2018-10-25 11:50:12 +02:00

589 lines
19 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* © Copyright 2014 Urheberrechtshinweis
* Alle Rechte vorbehalten / All Rights Reserved
*
* Programmcode ist urheberrechtlich geschuetzt.
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
* Einige Aenderungen beigetragen von Toni Fetzer
* Keine Verwendung ohne explizite Genehmigung.
* (vgl. § 106 ff UrhG / § 97 UrhG)
*/
#ifndef FLOORPLANREADER_H
#define FLOORPLANREADER_H
#include <iostream>
#include "Floorplan.h"
#include "FloorplanLINT.h"
#include "../../misc/Debug.h"
#include "../../Assertions.h"
#include "../../lib/tinyxml/tinyxml2.h"
namespace Floorplan {
using XMLAttr = tinyxml2::XMLAttribute;
using XMLElem = tinyxml2::XMLElement;
using XMLNode = tinyxml2::XMLNode;
/**
* read an IndoorMaps from XML-data
*/
class Reader {
private:
static constexpr const char* name = "FPReader";
public:
/** read an IndoorMap from the given XML-file */
static IndoorMap* readFromFile(const std::string& file) {
Log::add(name, "reading floorplan from file: " + file);
setlocale(LC_NUMERIC, "C");
tinyxml2::XMLDocument doc;
const tinyxml2::XMLError res = doc.LoadFile(file.c_str());
if (res != tinyxml2::XMLError::XML_SUCCESS) {
throw Exception(
std::string() + "error while loading XML " + file + "\n" +
((doc.GetErrorStr1()) ? (doc.GetErrorStr1()) : ("")) + "\n" +
((doc.GetErrorStr2()) ? (doc.GetErrorStr2()) : ("")));
}
IndoorMap* map = parse(doc);
return map;
}
/** read an IndoorMap from the given XMl-string */
static IndoorMap* readFromString(const std::string& str) {
Log::add(name, "reading floorplan from string");
setlocale(LC_NUMERIC, "C");
tinyxml2::XMLDocument doc;
const tinyxml2::XMLError res = doc.Parse(str.c_str(), str.length());
if (res != tinyxml2::XMLError::XML_SUCCESS) {
throw Exception(
std::string() + "error while parsing XML\n" +
((doc.GetErrorStr1()) ? (doc.GetErrorStr1()) : ("")) + "\n" +
((doc.GetErrorStr2()) ? (doc.GetErrorStr2()) : (""))
);
}
IndoorMap* map = parse(doc);
return map;
}
private:
#define FOREACH_NODE(out, in) for( const XMLElem* out = in->FirstChildElement(); out; out = out->NextSiblingElement() )
static void assertNode(const std::string& node, const XMLElem* el) {
std::string err = std::string("unexpected node '") + el->Name() + "' expected '" + node + "'";
Assert::equal(node, std::string(el->Name()), err);
}
/** parse the complete document */
static IndoorMap* parse(tinyxml2::XMLDocument& doc) {
return parseMap(doc.FirstChildElement());
}
/** parse the <map> node */
static IndoorMap* parseMap(const XMLElem* el) {
Log::add(name, "parsing the map");
IndoorMap* map = new IndoorMap();
map->width = el->FloatAttribute("width");
map->depth = el->FloatAttribute("depth");
FOREACH_NODE(n, el) {
if (std::string("floors") == n->Name()) {map->floors = parseFloors(n);}
if (std::string("earthReg") == n->Name()) {map->earthReg = parseEarthReg(n);}
}
return map;
}
/** parse the <earthReg> node */
static EarthRegistration parseEarthReg(const XMLElem* el) {
EarthRegistration reg;
FOREACH_NODE(n, el) {
if (std::string("correspondences") == n->Name()) {
FOREACH_NODE(n2, n) {
if (std::string("point") == n2->Name()) {
Floorplan::EarthPosMapPos* pos = new Floorplan::EarthPosMapPos();
pos->posOnMap_m.x = n2->FloatAttribute("mx");
pos->posOnMap_m.y = n2->FloatAttribute("my");
pos->posOnMap_m.z = n2->FloatAttribute("mz");
pos->posOnEarth.lat = n2->FloatAttribute("lat");
pos->posOnEarth.lon = n2->FloatAttribute("lon");
pos->posOnEarth.height = n2->FloatAttribute("alt");
reg.correspondences.push_back(pos);
}
}
}
}
return reg;
}
/** parse the <floors> node */
static std::vector<Floor*> parseFloors(const XMLElem* el) {
std::vector<Floor*> floors;
FOREACH_NODE(n, el) {
if (std::string("floor") == n->Name()) {floors.push_back(parseFloor(n));}
}
return floors;
}
/** parse one <floor> node */
static Floor* parseFloor(const XMLElem* el) {
Floor* floor = new Floor();
Log::add(name, std::string("parsing floor ") + el->Attribute("name"));
floor->atHeight = el->FloatAttribute("atHeight");
floor->height = el->FloatAttribute("height");
floor->name = el->Attribute("name");
FOREACH_NODE(n, el) {
if (std::string("outline") == n->Name()) {floor->outline = parseFloorOutline(n);}
if (std::string("obstacles") == n->Name()) {floor->obstacles = parseFloorObstacles(n);}
if (std::string("accesspoints") == n->Name()) {floor->accesspoints = parseFloorAccessPoints(n);}
if (std::string("beacons") == n->Name()) {floor->beacons = parseFloorBeacons(n);}
if (std::string("fingerprints") == n->Name()) {floor->fpLocations = parseFingerprintLocations(n);}
if (std::string("regions") == n->Name()) {floor->regions = parseFloorRegions(n);}
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);}
if (std::string("gtpoints") == n->Name()) {floor->gtpoints = parseFloorGroundTruthPoints(n);}
}
return floor;
}
/** parse the <elevators> tag */
static FloorElevators parseFloorElevators(const XMLElem* el) {
FloorElevators vec;
FOREACH_NODE(n, el) {
if (std::string("elevator") == n->Name()) { vec.push_back(parseFloorElevator(n)); }
}
return vec;
}
/** parse the <stairs> tag */
static FloorStairs parseFloorStairs(const XMLElem* el) {
FloorStairs vec;
FOREACH_NODE(n, el) {
if (std::string("stair") == n->Name()) { vec.push_back(parseFloorStair(n)); }
}
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->height_m = el->FloatAttribute("height");
elev->rotation = el->FloatAttribute("rotation");
return elev;
}
/** parse a <stair> tag */
static Stair* parseFloorStair(const XMLElem* el) {
Stair* stair = nullptr;
if (el->IntAttribute("type") == 0) {
stair = new StairFreeform();
FOREACH_NODE(n, el) {
if (std::string("part") == n->Name()) {
StairPart part;
part.connectWithPrev = n->BoolAttribute("connect");
part.start.x = n->FloatAttribute("x1");
part.start.y = n->FloatAttribute("y1");
part.start.z = n->FloatAttribute("z1");
part.end.x = n->FloatAttribute("x2");
part.end.y = n->FloatAttribute("y2");
part.end.z = n->FloatAttribute("z2");
part.width = n->FloatAttribute("w");
((StairFreeform*)stair)->parts.push_back(part);
} else {
throw "not yet implemented";
}
}
} else {
throw "not yet implemented";
}
// stair meta information?
const XMLElem* meta = el->FirstChildElement("meta");
if (meta) {stair->setMeta(parseMetaElement(meta));}
return stair;
}
/** parse the <pois> tag */
static FloorPOIs parseFloorPOIs(const XMLElem* el) {
FloorPOIs vec;
FOREACH_NODE(n, el) {
if (std::string("poi") == n->Name()) { vec.push_back(parseFloorPOI(n)); }
}
return vec;
}
/** parse a <poi> tag */
static POI* parseFloorPOI(const XMLElem* el) {
POI* poi = new POI();
poi->name = el->Attribute("name");
poi->type = (POIType) el->IntAttribute("type");
poi->pos = parsePoint2(el);
return poi;
}
/** parse the <gtpoints> tag */
static FloorGroundTruthPoints parseFloorGroundTruthPoints(const XMLElem* el) {
FloorGroundTruthPoints vec;
FOREACH_NODE(n, el) {
if (std::string("gtpoint") == n->Name()) { vec.push_back(parseFloorGroundTruthPoint(n)); }
}
return vec;
}
/** parse a <gtpoint> tag */
static GroundTruthPoint* parseFloorGroundTruthPoint(const XMLElem* el) {
GroundTruthPoint* gtp = new GroundTruthPoint();
gtp->id = el->IntAttribute("id");
gtp->pos = parsePoint3(el);
return gtp;
}
/** parse the <accesspoints> tag */
static FloorAccessPoints parseFloorAccessPoints(const XMLElem* el) {
FloorAccessPoints vec;
FOREACH_NODE(n, el) {
if (std::string("accesspoint") == n->Name()) { vec.push_back(parseAccessPoint(n)); }
}
return vec;
}
/** parse the <underlays> tag */
static FloorUnderlays parseFloorUnderlays(const XMLElem* el) {
FloorUnderlays res;
FOREACH_NODE(n, el) {
if (std::string("underlay") == n->Name()) { res.push_back(parseFloorUnderlay(n)); }
}
return res;
}
/** parse an underlay image */
static UnderlayImage* parseFloorUnderlay(const XMLElem* el) {
UnderlayImage* img = new UnderlayImage();
img->anchor.x = el->FloatAttribute("x");
img->anchor.y = el->FloatAttribute("y");
img->scaleX = el->FloatAttribute("sx");
img->scaleY = el->FloatAttribute("sy");
img->name = el->Attribute("name");
img->filename = el->Attribute("file");
return img;
}
// /** parse the <other> tag */
// static FloorKeyValue parseFloorKeyValue(const XMLElem* el) {
// FloorKeyValue res;
// FOREACH_NODE(n, el) {
// if (std::string("keyval") == n->Name()) { res.elements.push_back(parseKeyValueElement(n)); }
// }
// return res;
// }
/** parse one <meta> element */
static Meta* parseMetaElement(const XMLElem* n) {
Meta* elem = new Meta();
// const XMLAttr* attr = n->FirstAttribute();
// while (attr) {
// elem->setVal(attr->Name(), attr->Value());
// attr = attr->Next();
// }
const XMLElem* sub = n->FirstChildElement();
while(sub) {
// <entry key="123">abc</entry>
const std::string key = sub->Attribute("key");
const std::string val = sub->GetText();
elem->add(key, val);
sub = sub->NextSiblingElement();
}
return elem;
}
static AccessPoint* parseAccessPoint(const XMLElem* n) {
assertNode("accesspoint", n);
AccessPoint* ap = new AccessPoint();
ap->mac = n->Attribute("mac");
ap->name = n->Attribute("name");
ap->pos = parsePoint3(n);
ap->model.txp = n->FloatAttribute("mdl_txp");
ap->model.exp = n->FloatAttribute("mdl_exp");
ap->model.waf = n->FloatAttribute("mdl_waf");
const XMLElem* meta = n->FirstChildElement("meta");
if (meta) {ap->setMeta(parseMetaElement(meta));}
return ap;
}
/** parse the <beacons> tag */
static FloorBeacons parseFloorBeacons(const XMLElem* el) {
FloorBeacons vec;
FOREACH_NODE(n, el) {
if (std::string("beacon") == n->Name()) { vec.push_back(parseBeacon(n)); }
}
return vec;
}
static Beacon* parseBeacon(const XMLElem* n) {
assertNode("beacon", n);
Beacon* b = new Beacon();
b->mac = n->Attribute("mac");
b->name = n->Attribute("name");
b->major = n->Attribute("major") ? n->Attribute("major") : "";
b->minor = n->Attribute("minor") ? n->Attribute("minor") : "";
b->uuid = n->Attribute("uuid") ? n->Attribute("uuid") : "";
b->model.txp = n->FloatAttribute("mdl_txp");
b->model.exp = n->FloatAttribute("mdl_exp");
b->model.waf = n->FloatAttribute("mdl_waf");
b->pos = parsePoint3(n);
return b;
}
/** parse <fingerprints> <location>s */
static FloorFingerprintLocations parseFingerprintLocations(const XMLElem* el) {
assertNode("fingerprints", el);
FloorFingerprintLocations vec;
FOREACH_NODE(n, el) {
if (std::string("location") == n->Name()) { vec.push_back(parseFingerprintLocation(n)); }
}
return vec;
}
/** parse one fingerprint <location> */
static FingerprintLocation* parseFingerprintLocation(const XMLElem* n) {
assertNode("location", n);
FingerprintLocation* fpl = new FingerprintLocation();
fpl->name = n->Attribute("name");
fpl->posOnFloor.x = n->FloatAttribute("x");
fpl->posOnFloor.y = n->FloatAttribute("y");
fpl->heightAboveFloor = n->FloatAttribute("dz");
const XMLElem* meta = n->FirstChildElement("meta");
if (meta) {fpl->setMeta(parseMetaElement(meta));}
return fpl;
}
static FloorRegions parseFloorRegions(const XMLElem* el) {
FloorRegions vec;
FOREACH_NODE(n, el) {
if (std::string("region") == n->Name()) { vec.push_back(parseFloorRegion(n)); }
}
return vec;
}
static FloorRegion* parseFloorRegion(const XMLElem* n) {
assertNode("region", n);
FloorRegion* reg = new FloorRegion();
reg->name = n->Attribute("name");
reg->poly = parsePoly2(n);
return reg;
}
/** parse the <obstacles> tag */
static FloorObstacles parseFloorObstacles(const XMLElem* el) {
assertNode("obstacles", el);
FloorObstacles obstacles;
FOREACH_NODE(n, el) {
// if (std::string("wall") == n->Name()) {obstacles.push_back(parseFloorObstacleWall(n));}
// if (std::string("door") == n->Name()) {obstacles.push_back(parseFloorObstacleDoor(n));}
// if (std::string("window") == n->Name()) {obstacles.push_back(parseFloorObstacleWindow(n));}
// if (std::string("pillar") == n->Name()) {obstacles.push_back(parseFloorObstaclePillar(n));}
//if (std::string("obstacle") == n->Name()) {obstacles.push_back(parseFloorObstacleLine(n));} // OLD
if (std::string("wall") == n->Name()) {obstacles.push_back(parseFloorObstacleWall(n));}
if (std::string("line") == n->Name()) {obstacles.push_back(parseFloorObstacleLine(n));}
if (std::string("circle") == n->Name()) {obstacles.push_back(parseFloorObstacleCircle(n));}
if (std::string("door") == n->Name()) {obstacles.push_back(parseFloorObstacleDoor(n));}
if (std::string("object") == n->Name()) {obstacles.push_back(parseFloorObstacleObject(n));}
}
return obstacles;
}
/** parse one wall */
static FloorObstacleWall* parseFloorObstacleWall(const XMLElem* el) {
FloorObstacleWall* wall = new FloorObstacleWall(
parseObstacleType(el->Attribute("type")),
parseMaterial(el->Attribute("material")),
el->FloatAttribute("x1"), el->FloatAttribute("y1"),
el->FloatAttribute("x2"), el->FloatAttribute("y2"),
(el->FloatAttribute("thickness") > 0) ? (el->FloatAttribute("thickness")) : (0.15), // default wall thickness in m
el->FloatAttribute("height")
);
// doors
FOREACH_NODE(n, el) {
if (std::string("door") == n->Name()) {
FloorObstacleWallDoor* door = new FloorObstacleWallDoor(
parseDoorType(n->Attribute("type")),
parseMaterial(n->Attribute("material")),
n->FloatAttribute("x01"),
n->FloatAttribute("width"),
n->FloatAttribute("height"),
n->BoolAttribute("lr"),
n->BoolAttribute("io")
);
wall->doors.push_back(door);
}
}
// windows
FOREACH_NODE(n, el) {
if (std::string("window") == n->Name()) {
FloorObstacleWallWindow* win = new FloorObstacleWallWindow(
parseWindowType(n->Attribute("type")),
parseMaterial(n->Attribute("material")),
n->FloatAttribute("x01"),
n->FloatAttribute("y"),
n->FloatAttribute("width"),
n->FloatAttribute("height"),
n->BoolAttribute("io")
);
wall->windows.push_back(win);
}
}
return wall;
}
/** parse one line */
static FloorObstacleLine* parseFloorObstacleLine(const XMLElem* el) {
return new FloorObstacleLine(
parseObstacleType(el->Attribute("type")),
parseMaterial(el->Attribute("material")),
el->FloatAttribute("x1"), el->FloatAttribute("y1"),
el->FloatAttribute("x2"), el->FloatAttribute("y2"),
(el->FloatAttribute("thickness") > 0) ? (el->FloatAttribute("thickness")) : (0.15), // default wall thickness in m
el->FloatAttribute("height")
);
}
/** parse one cirlce */
static FloorObstacleCircle* parseFloorObstacleCircle(const XMLElem* el) {
return new FloorObstacleCircle(
parseMaterial(el->Attribute("material")),
el->FloatAttribute("cx"), el->FloatAttribute("cy"),
el->FloatAttribute("radius"),
el->FloatAttribute("height")
);
}
/** parse one door */
static FloorObstacleDoor* parseFloorObstacleDoor(const XMLElem* el) {
return new FloorObstacleDoor(
parseDoorType(el->Attribute("type")),
parseMaterial(el->Attribute("material")),
el->FloatAttribute("x1"), el->FloatAttribute("y1"),
el->FloatAttribute("x2"), el->FloatAttribute("y2"),
el->FloatAttribute("height"), el->BoolAttribute("swap")
);
}
/** parse one object */
static FloorObstacleObject* parseFloorObstacleObject(const XMLElem* el) {
return new FloorObstacleObject(
el->Attribute("file"),
Point3(el->FloatAttribute("x"), el->FloatAttribute("y"), el->FloatAttribute("z")),
Point3(el->FloatAttribute("rx", 0), el->FloatAttribute("ry", 0), el->FloatAttribute("rz", 0)),
Point3(el->FloatAttribute("sx", 1), el->FloatAttribute("sy", 1), el->FloatAttribute("sz", 1))
);
}
/** parse a floor's <outline> tag */
static FloorOutline parseFloorOutline(const XMLElem* el) {
FloorOutline outline;
FOREACH_NODE(n, el) {
if (std::string("polygon") == n->Name()) {
outline.push_back(parseFloorPolygon(n));
}
}
return outline;
}
/** parse one polygon */
static FloorOutlinePolygon* parseFloorPolygon(const XMLElem* el) {
FloorOutlinePolygon* poly = new FloorOutlinePolygon();
poly->name = el->Attribute("name");
poly->outdoor = el->BoolAttribute("outdoor");
poly->method = parseOutlineMethod(el->Attribute("method"));
poly->poly = parsePoly2(el);
return poly;
}
/** parse a 2d-polygon denoted by several points */
static Polygon2 parsePoly2(const XMLElem* el) {
Polygon2 poly;
FOREACH_NODE(n, el) {
if (std::string("point") == n->Name()) {
const Point2 p2 = parsePoint2(n);
poly.points.push_back(p2);
}
}
return poly;
}
/** parse a 2D point (x,y) using the given tag's attributes. missing attributes are set to 0 */
static Point2 parsePoint2(const XMLElem* el) {
Point2 point;
point.x = el->FloatAttribute("x");
point.y = el->FloatAttribute("y");
return point;
}
/** parse a 3D point (x,y,z) using the given tag's attributes. missing attributes are set to 0 */
static Point3 parsePoint3(const XMLElem* el) {
Point3 point;
point.x = el->FloatAttribute("x");
point.y = el->FloatAttribute("y");
point.z = el->FloatAttribute("z");
return point;
}
static ObstacleType parseObstacleType(const std::string type) {
try {
return (ObstacleType) std::stoi(type);
} catch (...) {
return ObstacleType::UNKNOWN;
}
}
static DoorType parseDoorType(const std::string type) {
try { return (DoorType) std::stoi(type); } catch (...) { return DoorType::UNKNOWN; }
}
static WindowType parseWindowType(const std::string type) {
try { return (WindowType) std::stoi(type); } catch (...) { return WindowType::UNKNOWN; }
}
static Material parseMaterial(const std::string material) {
try {
return (Material) std::stoi(material);
} catch (...) {
return Material::UNKNOWN;
}
}
static OutlineMethod parseOutlineMethod(const std::string method) {
try {
return (OutlineMethod) std::stoi(method);
} catch (...) {
return OutlineMethod::ADD;
}
}
};
}
#endif // FLOORPLANREADER_H