#ifndef FLOORPLANWRITER_H #define FLOORPLANWRITER_H #include #include "Floorplan.h" #include "../../Assertions.h" #include "../../lib/tinyxml/tinyxml2.h" namespace Floorplan { using namespace tinyxml2; /** * write floorplans as XML */ class Writer { public: static void writeToFile(const IndoorMap* map, const std::string& file) { XMLDocument doc; construct(doc, map); doc.SaveFile(file.c_str(), false); } static std::string writeToString(const IndoorMap* map) { XMLDocument doc; construct(doc, map); XMLPrinter printer; doc.Accept( &printer ); return printer.CStr(); } private: static std::string toString(const ObstacleType t) { return std::to_string((int)t); } static std::string toString(const Material m) { return std::to_string((int)m); } static std::string toString(const OutlineMethod m) { return std::to_string((int)m); } static void construct(XMLDocument& doc, const IndoorMap* map) { XMLElement* root = doc.NewElement("map"); doc.InsertEndChild(root); root->SetAttribute("width", map->width); root->SetAttribute("depth", map->depth); // add all floors to the map addFloors(doc, root, map); } /** add all floors to the map */ static void addFloors(XMLDocument& doc, XMLElement* root, const IndoorMap* map) { XMLElement* floors = doc.NewElement("floors"); for(const Floor* mf : map->floors) {addFloor(doc, floors, mf);} root->InsertEndChild(floors); } /** add one floor to the floors-node */ static void addFloor(XMLDocument& doc, XMLElement* floors, const Floor* mf) { XMLElement* floor = doc.NewElement("floor"); floor->SetAttribute("atHeight", mf->atHeight); floor->SetAttribute("height", mf->height); floor->SetAttribute("name", mf->name.c_str()); floors->InsertEndChild(floor); addFloorOutline(doc, floor, mf); addFloorObstacles(doc, floor, mf); addFloorUnderlays(doc, floor, mf); // add all sorts of POI addFloorPOI(doc, floor, mf); } /** add all sorts of POI to the floor */ static void addFloorPOI(XMLDocument& doc, XMLElement* floor, const Floor* mf) { XMLElement* accesspoints = doc.NewElement("accesspoints"); for (const AccessPoint* ap : mf->accesspoints) { XMLElement* accesspoint = doc.NewElement("accesspoint"); accesspoint->SetAttribute("name", ap->name.c_str()); accesspoint->SetAttribute("mac", ap->mac.c_str()); accesspoint->SetAttribute("x", ap->pos.x); accesspoint->SetAttribute("y", ap->pos.y); accesspoint->SetAttribute("z", ap->pos.z); accesspoints->InsertEndChild(accesspoint); } floor->InsertEndChild(accesspoints); XMLElement* beacons = doc.NewElement("beacons"); for (const Beacon* b : mf->beacons) { XMLElement* beacon = doc.NewElement("beacon"); beacon->SetAttribute("name", b->name.c_str()); beacon->SetAttribute("mac", b->mac.c_str()); beacon->SetAttribute("x", b->pos.x); beacon->SetAttribute("y", b->pos.y); beacon->SetAttribute("z", b->pos.z); beacons->InsertEndChild(beacon); } floor->InsertEndChild(beacons); } static void addFloorOutline(XMLDocument& doc, XMLElement* floor, const Floor* mf) { XMLElement* outline = doc.NewElement("outline"); floor->InsertEndChild(outline); // XMLElement* add = doc.NewElement("add"); // outline->InsertEndChild(add); for (const FloorOutlinePolygon* poly : mf->outline) { addFloorOutlinePolygon(doc, outline, poly); } // XMLElement* remove = doc.NewElement("remove"); // outline->InsertEndChild(remove); // for (const FloorOutlinePolygon& poly : mf.outline.remove) { addFloorOutlinePolygon(doc, remove, poly); } } static void addFloorOutlinePolygon(XMLDocument& doc, XMLElement* dst, const FloorOutlinePolygon* poly) { std::string method = toString(poly->method); XMLElement* polygon = doc.NewElement("polygon"); polygon->SetAttribute("name", poly->name.c_str()); polygon->SetAttribute("method", method.c_str()); dst->InsertEndChild(polygon); for (Point2 p : poly->poly.points) { XMLElement* point = doc.NewElement("point"); point->SetAttribute("x", p.x); point->SetAttribute("y", p.y); // skip the z-attribute as the value is also given by the polygons floor: floor.atHeight polygon->InsertEndChild(point); } } /** write one element */ static void addKeyValueElement(XMLDocument& doc, XMLElement* other, const KeyValueElement* kv) { XMLElement* elem = doc.NewElement("keyval"); for (auto it : kv->params) { elem->Attribute(it.first.c_str(), it.second.c_str()); } other->InsertEndChild(elem); } /** write the tag */ static void addFloorUnderlays(XMLDocument& doc, XMLElement* floor, const Floor* mf) { XMLElement* other = doc.NewElement("underlays"); for (const UnderlayImage* kv : mf->underlays) { addFloorUnderlay(doc, other, kv); } floor->InsertEndChild(other); } /** write one underlay */ static void addFloorUnderlay(XMLDocument& doc, XMLElement* underlays, const UnderlayImage* img) { XMLElement* underlay = doc.NewElement("underlay"); underlay->SetAttribute("x", img->anchor.x); underlay->SetAttribute("y", img->anchor.y); underlay->SetAttribute("sx", img->scaleX); underlay->SetAttribute("sy", img->scaleY); underlay->SetAttribute("name", img->name.c_str()); underlay->SetAttribute("file", img->filename.c_str()); underlays->InsertEndChild(underlay); } // /** write the tag */ // static void addFloorKeyValue(XMLDocument& doc, XMLElement* floor, const Floor* mf) { // XMLElement* other = doc.NewElement("other"); // for (const KeyValueElement* kv : mf->other.elements) { // addKeyValueElement(doc, other, kv); // } // floor->InsertEndChild(other); // } static void addFloorObstacles(XMLDocument& doc, XMLElement* floor, const Floor* mf) { XMLElement* obstacles = doc.NewElement("obstacles"); for (FloorObstacle* fo : mf->obstacles) { if (dynamic_cast(fo)) { addFloorObstacleLine(doc, obstacles, (FloorObstacleLine*)fo); } else if (dynamic_cast(fo)) { addFloorObstacleCircle(doc, obstacles, (FloorObstacleCircle*)fo); } } floor->InsertEndChild(obstacles); } static void addFloorObstacleLine(XMLDocument& doc, XMLElement* obstacles, FloorObstacleLine* line) { XMLElement* obstacle = doc.NewElement("line"); const std::string type = toString(line->type); const std::string material = toString(line->material); obstacle->SetAttribute("material", material.c_str()); obstacle->SetAttribute("type", type.c_str()); obstacle->SetAttribute("x1", line->from.x); obstacle->SetAttribute("y1", line->from.y); obstacle->SetAttribute("x2", line->to.x); obstacle->SetAttribute("y2", line->to.y); obstacles->InsertEndChild(obstacle); } static void addFloorObstacleCircle(XMLDocument& doc, XMLElement* obstacles, FloorObstacleCircle* circle) { XMLElement* obstacle = doc.NewElement("line"); const std::string type = toString(circle->type); const std::string material = toString(circle->material); obstacle->SetAttribute("material", material.c_str()); obstacle->SetAttribute("type", type.c_str()); obstacle->SetAttribute("cx", circle->center.x); obstacle->SetAttribute("cy", circle->center.y); obstacle->SetAttribute("radius", circle->radius); obstacles->InsertEndChild(obstacle); } }; } #endif // FLOORPLANWRITER_H