222 lines
4.7 KiB
C++
Executable File
222 lines
4.7 KiB
C++
Executable File
/*
|
||
* © Copyright 2014 – Urheberrechtshinweis
|
||
* Alle Rechte vorbehalten / All Rights Reserved
|
||
*
|
||
* Programmcode ist urheberrechtlich geschuetzt.
|
||
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
|
||
* Keine Verwendung ohne explizite Genehmigung.
|
||
* (vgl. § 106 ff UrhG / § 97 UrhG)
|
||
*/
|
||
|
||
#ifndef FLOORPLANFACTORYSVG_H
|
||
#define FLOORPLANFACTORYSVG_H
|
||
|
||
#include "Floor.h"
|
||
#include "Stairs.h"
|
||
|
||
#include <string>
|
||
#include "../Exception.h"
|
||
|
||
#include <KLib/gfx/svg/SVGLoader.h>
|
||
|
||
/**
|
||
* 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
|