#ifndef FLOORPLANREADER_H #define FLOORPLANREADER_H #include #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 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 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 node */ static std::vector parseFloors(const XMLElem* el) { std::vector floors; FOREACH_NODE(n, el) { if (std::string("floor") == n->Name()) {floors.push_back(parseFloor(n));} } return floors; } /** parse one 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 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 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 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 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 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 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 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 tag */ static GroundTruthPoint* parseFloorGroundTruthPoint(const XMLElem* el) { GroundTruthPoint* gtp = new GroundTruthPoint(); gtp->id = el->IntAttribute("id"); gtp->pos = parsePoint3(el); return gtp; } /** parse the 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 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 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 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) { // abc 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 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 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 */ 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 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("at"), n->FloatAttribute("width"), n->FloatAttribute("height"), n->BoolAttribute("lr"), n->BoolAttribute("io") ); wall->doors.push_back(door); } } 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 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 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