#ifndef FLOORPLANFACTORYSVG_H #define FLOORPLANFACTORYSVG_H #include "Floor.h" #include "Stairs.h" #include #include "../Exception.h" #include /** * load floorplans from SVG files */ class FloorplanFactorySVG { /** * helper class for SVG floorplans. * * converts between the SVG's scale and real-world scale */ class SVGScaler { private: /** the scaling factor to apply to the svg data */ const double scalingFactor; public: /** ctor */ SVGScaler(const double scalingFactor) : scalingFactor(scalingFactor) { ; } /** scale (x, y) into (_x, _y) */ void scale(const double x, const double y, float& _x, float& _y) const { _x = x * scalingFactor; _y = y * scalingFactor; } // /** scale the given point into a new output point */ // K::Point scale(const K::Point p) const { // K::Point ret; // scale (p.x, p.y, ret.x, ret.y); // return ret; // } /** scale the given line into a new output line */ Line2 scale(const K::Line l) const { Line2 ret; scale (l.p1.x, l.p1.y, ret.p1.x, ret.p1.y); scale (l.p2.x, l.p2.y, ret.p2.x, ret.p2.y); return ret; } }; private: K::SVGFile svg; SVGScaler scaler; float width; float depth; public: /** ctor with svg filename and scaling factor */ FloorplanFactorySVG(const std::string& file, const float scaling) : scaler(scaling) { // load the SVG K::SVGLoader::load(K::File(file), &svg); scaler.scale(svg.getWidth(), svg.getHeight(), width, depth); } /** get the width of the building */ float getWidth() const {return width;} /** get the depth of the building */ float getDepth() const {return depth;} /** get the floor identified by the given layer name */ Floor getFloor(const std::string layerName) { // get the requested SVG layer K::SVGComposite* sc = svg.getLayers(); K::SVGLayer* layer = sc->getContainedLayerNamed(layerName); if (!layer) {throw Exception("SVG has no layer named '" + layerName + "'");} // create and parse the new floor Floor floor(width, depth); loadFloor(layer, floor); return floor; } /** get all stairs within the given layer */ Stairs getStairs(const std::string& layerName) { // get the requested SVG layer K::SVGComposite* sc = svg.getLayers(); K::SVGLayer* layer = sc->getContainedLayerNamed(layerName); if (!layer) {throw Exception("SVG has no layer named '" + layerName + "'");} // create and parse the new floor Stairs stairs; loadStairs(layer, stairs); return stairs; } private: /** recursive loading/parsing of nested SVG elements */ void loadFloor(K::SVGElement* el, Floor& floor) { switch (el->getType()) { case SVGElementType::COMPOSITE: { for (K::SVGElement* sub : ((K::SVGComposite*)el)->getChilds()) { loadFloor(sub, floor); } break; } case SVGElementType::LAYER: { K::SVGLayer* layer = (K::SVGLayer*) el; for (K::SVGElement* sub : layer->getChilds()) { loadFloor(sub, floor); } break; } case SVGElementType::PATH: { for (const K::Line& line : ((K::SVGPath*)el)->getLines()) { floor.addObstacle( scaler.scale(line) ); } break; } case SVGElementType::TEXT: { break; } default: throw "should not happen!"; } } /** recursive loading/parsing of nested SVG elements */ void loadStairs(K::SVGElement* el, Stairs& stairs) { switch (el->getType()) { case SVGElementType::COMPOSITE: { for (K::SVGElement* sub : ((K::SVGComposite*)el)->getChilds()) { loadStairs(sub, stairs); } break; } case SVGElementType::LAYER: { K::SVGLayer* layer = (K::SVGLayer*) el; for (K::SVGElement* sub : layer->getChilds()) { loadStairs(sub, stairs); } break; } case SVGElementType::PATH: { int i = 0; Line2 start; Line2 dir; for (const K::Line& line : ((K::SVGPath*)el)->getLines()) { if (++i == 1) { start = scaler.scale(line); } else { Stair s; Line2 dir = scaler.scale(line); s.dir = (dir.p2 - dir.p1); // const float d = 50; s.start = start; // s.from.add(start.p1 + Point2(-d,-d)); // s.from.add(start.p1 + Point2(+d,+d)); // s.from.add(start.p2 + Point2(-d,-d)); // s.from.add(start.p2 + Point2(+d,+d)); stairs.push_back(s); } } break; } case SVGElementType::TEXT: { break; } default: throw "should not happen!"; } } }; #endif // FLOORPLANFACTORYSVG_H