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/FloorplanWriter.h
2018-07-25 16:21:47 +02:00

424 lines
15 KiB
C++

#ifndef FLOORPLANWRITER_H
#define FLOORPLANWRITER_H
#include <iostream>
#include "Floorplan.h"
#include "../../Assertions.h"
#include "../../lib/tinyxml/tinyxml2.h"
namespace Floorplan {
using XMLAttr = tinyxml2::XMLAttribute;
using XMLElem = tinyxml2::XMLElement;
using XMLDoc = tinyxml2::XMLDocument;
/**
* write floorplans as XML
*/
class Writer {
public:
static void writeToFile(const IndoorMap* map, const std::string& file) {
XMLDoc doc;
construct(doc, map);
doc.SaveFile(file.c_str(), false);
}
static std::string writeToString(const IndoorMap* map) {
XMLDoc doc;
construct(doc, map);
tinyxml2::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 DoorType 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(XMLDoc& doc, const IndoorMap* map) {
XMLElem* root = doc.NewElement("map");
doc.InsertEndChild(root);
root->SetAttribute("width", map->width);
root->SetAttribute("depth", map->depth);
// add earth registration to the map
addEarthReg(doc, root, map);
// add all floors to the map
addFloors(doc, root, map);
}
/** add earth registration to the map */
static void addEarthReg(XMLDoc& doc, XMLElem* root, const IndoorMap* map) {
XMLElem* earthReg = doc.NewElement("earthReg"); {
XMLElem* correspondences = doc.NewElement("correspondences");
for (const Floorplan::EarthPosMapPos* reg : map->earthReg.correspondences) {
XMLElem* point = doc.NewElement("point");
point->SetAttribute("lat", reg->posOnEarth.lat);
point->SetAttribute("lon", reg->posOnEarth.lon);
point->SetAttribute("alt", reg->posOnEarth.height);
point->SetAttribute("mx", reg->posOnMap_m.x);
point->SetAttribute("my", reg->posOnMap_m.y);
point->SetAttribute("mz", reg->posOnMap_m.z);
correspondences->InsertEndChild(point);
}
earthReg->InsertEndChild(correspondences);
} root->InsertEndChild(earthReg);
}
/** add all floors to the map */
static void addFloors(XMLDoc& doc, XMLElem* root, const IndoorMap* map) {
XMLElem* 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(XMLDoc& doc, XMLElem* floors, const Floor* mf) {
XMLElem* 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);
addStairs(doc, floor, mf);
addElevators(doc, floor, mf);
}
/** add all elevators to the floor */
static void addElevators(XMLDoc& doc, XMLElem* floor, const Floor* mf) {
XMLElem* elevators = doc.NewElement("elevators");
for (const Elevator* elevator : mf->elevators) {
XMLElem* elem = doc.NewElement("elevator");
elem->SetAttribute("cx", elevator->center.x);
elem->SetAttribute("cy", elevator->center.y);
elem->SetAttribute("width", elevator->width);
elem->SetAttribute("depth", elevator->depth);
elem->SetAttribute("height", elevator->height_m);
elem->SetAttribute("rotation", elevator->rotation);
elevators->InsertEndChild(elem);
}
floor->InsertEndChild(elevators);
}
/** add all stairs to the floor */
static void addStairs(XMLDoc& doc, XMLElem* floor, const Floor* mf) {
XMLElem* stairs = doc.NewElement("stairs");
for (const Stair* _stair : mf->stairs) {
XMLElem* elem = doc.NewElement("stair");
addMetaElement(doc, elem, _stair->getMeta());
if (dynamic_cast<const StairFreeform*>(_stair)) {
const StairFreeform* stair = (StairFreeform*) _stair;
elem->SetAttribute("type", 0); // TODO: other types?
for (const StairPart& part : stair->parts) {
XMLElem* elemPart = doc.NewElement("part");
elemPart->SetAttribute("connect", part.connectWithPrev);
elemPart->SetAttribute("x1", part.start.x);
elemPart->SetAttribute("y1", part.start.y);
elemPart->SetAttribute("z1", part.start.z);
elemPart->SetAttribute("x2", part.end.x);
elemPart->SetAttribute("y2", part.end.y);
elemPart->SetAttribute("z2", part.end.z);
elemPart->SetAttribute("w", part.width);
elem->InsertEndChild(elemPart);
}
} else {
throw "not yet implemented";
}
stairs->InsertEndChild(elem);
}
floor->InsertEndChild(stairs);
}
/** add all sorts of POI to the floor */
static void addFloorPOI(XMLDoc& doc, XMLElem* floor, const Floor* mf) {
XMLElem* pois = doc.NewElement("pois");
for (const POI* poi : mf->pois) {
XMLElem* elem = doc.NewElement("poi");
elem->SetAttribute("name", poi->name.c_str());
elem->SetAttribute("type", (int) poi->type);
elem->SetAttribute("x", poi->pos.x);
elem->SetAttribute("y", poi->pos.y);
pois->InsertEndChild(elem);
}
floor->InsertEndChild(pois);
XMLElem* gtpoints = doc.NewElement("gtpoints");
for (const GroundTruthPoint* gtp : mf->gtpoints) {
XMLElem* elem = doc.NewElement("gtpoint");
elem->SetAttribute("id", gtp->id);
elem->SetAttribute("x", gtp->pos.x);
elem->SetAttribute("y", gtp->pos.y);
elem->SetAttribute("z", gtp->pos.z);
gtpoints->InsertEndChild(elem);
}
floor->InsertEndChild(gtpoints);
XMLElem* accesspoints = doc.NewElement("accesspoints");
for (const AccessPoint* ap : mf->accesspoints) {
XMLElem* 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);
accesspoint->SetAttribute("mdl_txp", ap->model.txp);
accesspoint->SetAttribute("mdl_exp", ap->model.exp);
accesspoint->SetAttribute("mdl_waf", ap->model.waf);
addMetaElement(doc, accesspoint, ap->getMeta());
accesspoints->InsertEndChild(accesspoint);
}
floor->InsertEndChild(accesspoints);
XMLElem* beacons = doc.NewElement("beacons");
for (const Beacon* b : mf->beacons) {
XMLElem* beacon = doc.NewElement("beacon");
beacon->SetAttribute("name", b->name.c_str());
beacon->SetAttribute("mac", b->mac.c_str());
beacon->SetAttribute("major", b->major.c_str());
beacon->SetAttribute("minor", b->minor.c_str());
beacon->SetAttribute("uuid", b->uuid.c_str());
beacon->SetAttribute("x", b->pos.x);
beacon->SetAttribute("y", b->pos.y);
beacon->SetAttribute("z", b->pos.z);
beacon->SetAttribute("mdl_txp", b->model.txp);
beacon->SetAttribute("mdl_exp", b->model.exp);
beacon->SetAttribute("mdl_waf", b->model.waf);
beacons->InsertEndChild(beacon);
}
floor->InsertEndChild(beacons);
XMLElem* fingerprints = doc.NewElement("fingerprints");
for (const FingerprintLocation* fpl : mf->fpLocations) {
XMLElem* efpl = doc.NewElement("location");
efpl->SetAttribute("name", fpl->name.c_str());
efpl->SetAttribute("x", fpl->posOnFloor.x);
efpl->SetAttribute("y", fpl->posOnFloor.y);
efpl->SetAttribute("dz", fpl->heightAboveFloor);
addMetaElement(doc, efpl, fpl->getMeta());
fingerprints->InsertEndChild(efpl);
}
floor->InsertEndChild(fingerprints);
}
static void addFloorOutline(XMLDoc& doc, XMLElem* floor, const Floor* mf) {
XMLElem* outline = doc.NewElement("outline");
floor->InsertEndChild(outline);
// XMLElem* add = doc.NewElement("add");
// outline->InsertEndChild(add);
for (const FloorOutlinePolygon* poly : mf->outline) { addFloorOutlinePolygon(doc, outline, poly); }
// XMLElem* remove = doc.NewElement("remove");
// outline->InsertEndChild(remove);
// for (const FloorOutlinePolygon& poly : mf.outline.remove) { addFloorOutlinePolygon(doc, remove, poly); }
}
static void addFloorOutlinePolygon(XMLDoc& doc, XMLElem* dst, const FloorOutlinePolygon* poly) {
std::string method = toString(poly->method);
XMLElem* polygon = doc.NewElement("polygon");
polygon->SetAttribute("name", poly->name.c_str());
polygon->SetAttribute("method", method.c_str());
polygon->SetAttribute("outdoor", poly->outdoor);
dst->InsertEndChild(polygon);
for (Point2 p : poly->poly.points) {
XMLElem* 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 <meta> element */
static void addMetaElement(XMLDoc& doc, XMLElem* other, const Meta* meta) {
if (meta == nullptr) {return;} // nothing to add
XMLElem* elem = doc.NewElement("meta");
// for (auto it : meta->params) {
// elem->Attribute(it.first.c_str(), it.second.c_str());
// }
for (const Meta::KeyVal& kv : meta->params) {
// <entry key="123">abc</entry>
XMLElem* subElem = doc.NewElement("entry");
subElem->SetAttribute("key", kv.key.c_str());
subElem->SetText(kv.val.c_str());
elem->InsertEndChild(subElem);
}
other->InsertEndChild(elem);
}
/** write the <underlays> tag */
static void addFloorUnderlays(XMLDoc& doc, XMLElem* floor, const Floor* mf) {
XMLElem* other = doc.NewElement("underlays");
for (const UnderlayImage* kv : mf->underlays) {
addFloorUnderlay(doc, other, kv);
}
floor->InsertEndChild(other);
}
/** write one underlay */
static void addFloorUnderlay(XMLDoc& doc, XMLElem* underlays, const UnderlayImage* img) {
XMLElem* 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);
}
static void addFloorObstacles(XMLDoc& doc, XMLElem* floor, const Floor* mf) {
XMLElem* obstacles = doc.NewElement("obstacles");
for (FloorObstacle* fo : mf->obstacles) {
if (dynamic_cast<FloorObstacleLine*>(fo)) {
addFloorObstacleLine(doc, obstacles, (FloorObstacleLine*)fo);
} else if (dynamic_cast<FloorObstacleWall*>(fo)) {
addFloorObstacleWall(doc, obstacles, (FloorObstacleWall*)fo);
} else if (dynamic_cast<FloorObstacleCircle*>(fo)) {
addFloorObstacleCircle(doc, obstacles, (FloorObstacleCircle*)fo);
} else if (dynamic_cast<FloorObstacleDoor*>(fo)) {
addFloorObstacleDoor(doc, obstacles, (FloorObstacleDoor*)fo);
} else if (dynamic_cast<FloorObstacleObject*>(fo)) {
addFloorObstacleObject(doc, obstacles, (FloorObstacleObject*)fo);
}
}
floor->InsertEndChild(obstacles);
}
/** write a wall obstacle (wall) */
static void addFloorObstacleWall(XMLDoc& doc, XMLElem* obstacles, FloorObstacleWall* wall) {
XMLElem* oWall = doc.NewElement("wall");
obstacles->InsertEndChild(oWall);
oWall->SetAttribute("material", toString(wall->material).c_str());
oWall->SetAttribute("type", toString(wall->type).c_str());
oWall->SetAttribute("x1", wall->from.x);
oWall->SetAttribute("y1", wall->from.y);
oWall->SetAttribute("x2", wall->to.x);
oWall->SetAttribute("y2", wall->to.y);
oWall->SetAttribute("thickness", wall->thickness_m);
if (wall->height_m != 0) {oWall->SetAttribute("height", wall->height_m);}
// doors?
for (const FloorObstacleWallDoor* door : wall->doors) {
XMLElem* oDoor = doc.NewElement("door");
oWall->InsertEndChild(oDoor);
oDoor->SetAttribute("type", toString(door->type).c_str());
oDoor->SetAttribute("material", toString(door->material).c_str());
oDoor->SetAttribute("at", door->atLinePos);
oDoor->SetAttribute("width", door->width);
oDoor->SetAttribute("height", door->height);
oDoor->SetAttribute("io", door->inOut);
oDoor->SetAttribute("lr", door->leftRight);
}
}
/** write a line obstacle (old walls, handrail, ..) */
static void addFloorObstacleLine(XMLDoc& doc, XMLElem* obstacles, FloorObstacleLine* line) {
XMLElem* obstacle = doc.NewElement("line");
obstacle->SetAttribute("material", toString(line->material).c_str());
obstacle->SetAttribute("type", toString(line->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);
obstacle->SetAttribute("thickness", line->thickness_m);
if (line->height_m != 0) {obstacle->SetAttribute("height", line->height_m);}
obstacles->InsertEndChild(obstacle);
}
/** write a circle obstacle (pillar, ..) */
static void addFloorObstacleCircle(XMLDoc& doc, XMLElem* obstacles, FloorObstacleCircle* circle) {
XMLElem* obstacle = doc.NewElement("circle");
obstacle->SetAttribute("material", toString(circle->material).c_str());
obstacle->SetAttribute("cx", circle->center.x);
obstacle->SetAttribute("cy", circle->center.y);
obstacle->SetAttribute("radius", circle->radius);
if (circle->height != 0) {obstacle->SetAttribute("height", circle->height);}
obstacles->InsertEndChild(obstacle);
}
/** write a door obstacle */
static void addFloorObstacleDoor(XMLDoc& doc, XMLElem* obstacles, FloorObstacleDoor* door) {
XMLElem* obstacle = doc.NewElement("door");
obstacle->SetAttribute("material", toString(door->material).c_str());
obstacle->SetAttribute("type", toString(door->type).c_str());
obstacle->SetAttribute("x1", door->from.x);
obstacle->SetAttribute("y1", door->from.y);
obstacle->SetAttribute("x2", door->to.x);
obstacle->SetAttribute("y2", door->to.y);
obstacle->SetAttribute("height", door->height);
obstacle->SetAttribute("swap", door->swap);
obstacles->InsertEndChild(obstacle);
}
/** write an object-obstacle */
static void addFloorObstacleObject(XMLDoc& doc, XMLElem* obstacles, FloorObstacleObject* obj) {
XMLElem* obstacle = doc.NewElement("object");
obstacle->SetAttribute("file", obj->file.c_str());
obstacle->SetAttribute("x", obj->pos.x);
obstacle->SetAttribute("y", obj->pos.y);
obstacle->SetAttribute("z", obj->pos.z);
if (obj->rot.x != 0) {obstacle->SetAttribute("rx", obj->rot.x);}
if (obj->rot.y != 0) {obstacle->SetAttribute("ry", obj->rot.y);}
if (obj->rot.z != 0) {obstacle->SetAttribute("rz", obj->rot.z);}
if (obj->scale.x != 1) {obstacle->SetAttribute("sx", obj->scale.x);}
if (obj->scale.y != 1) {obstacle->SetAttribute("sy", obj->scale.y);}
if (obj->scale.z != 1) {obstacle->SetAttribute("sz", obj->scale.z);}
obstacles->InsertEndChild(obstacle);
}
};
}
#endif // FLOORPLANWRITER_H