#ifndef FLOOR2D_H #define FLOOR2D_H #include #include "Renderable2D.h" #include /** * draw the floor itself (outline, obstacles) */ class Floor2D : public Renderable2D { private: Floorplan::Floor* floor; public: /** ctor */ Floor2D(Floorplan::Floor* floor) : floor(floor) { } protected: void doRender(QPainter& qp, const Scaler2D& s, const RenderParams2D& r) override { if (floor->atHeight < r.clip.belowHeight_m) {return;} if (floor->atHeight > r.clip.aboveHeight_m) {return;} for (const Floorplan::FloorObstacle* obs : floor->obstacles) { const Floorplan::FloorObstacleWall* line = dynamic_cast(obs); if (line) {drawObstacle(qp, s, line);} } for (const Floorplan::FloorOutlinePolygon* poly : floor->outline) { drawOutline(qp, s, poly); } for (const Floorplan::Stair* stair : floor->stairs) { const Floorplan::StairFreeform* sf = dynamic_cast(stair); if (sf) {drawStair(qp, s, sf);} } for (const Floorplan::Elevator* elevator : floor->elevators) { drawElevator(qp, s, elevator); } } private: static inline QPen getPen(Floorplan::Material mat, Floorplan::ObstacleType type, int thickness) { using namespace Floorplan; QPen pen; pen.setColor(Qt::darkGray); if (mat == Material::CONCRETE) {pen.setWidth(thickness);} if (mat == Material::DRYWALL) {pen.setWidth(thickness); pen.setColor(Qt::gray);} if (mat == Material::GLASS) {pen.setStyle(Qt::PenStyle::DotLine);} if (type == ObstacleType::HANDRAIL) {pen.setStyle(Qt::PenStyle::DashLine);} if (type == ObstacleType::UNKNOWN) {pen.setColor(Qt::red); pen.setWidth(5);} if (type == ObstacleType::PILLAR) {pen.setColor(Qt::red); pen.setWidth(5);} return pen; } void drawObstacle(QPainter& qp, const Scaler2D& s, const Floorplan::FloorObstacleWall* line) { const Point2 pt1 = s.mapToScreen(line->from); const Point2 pt2 = s.mapToScreen(line->to); qp.setPen(getPen(line->material, line->type, static_cast(s.mToPX(line->thickness_m)))); qp.drawLine(pt1.x, pt1.y, pt2.x, pt2.y); } void drawElevator(QPainter& qp, const Scaler2D& s, const Floorplan::Elevator* elevator) { const QPolygon qpoly = toQPolygon(elevator->getPoints(), s); qp.setBrush(Qt::gray); qp.setPen(Qt::black); qp.drawPolygon(qpoly); } void drawStair(QPainter& qp, const Scaler2D& s, const Floorplan::StairFreeform* stair) { std::vector parts = stair->getParts(); std::vector quads = Floorplan::getQuads(parts, floor); for (int i = 0; i < (int) parts.size(); ++i) { const Floorplan::StairPart& part = parts[i]; const Floorplan::Quad3& quad = quads[i]; const Point2 start = s.mapToScreen(part.start.xy()); const Point2 end = s.mapToScreen(part.end.xy()); // fill the polygon with a gradient corresponding with the stair's height relative to the floor's height QLinearGradient gradient(start.x, start.y, end.x, end.y); const float p1 = 0.1 + clamp01( part.start.z / floor->height) * 0.8; const float p2 = 0.1 + clamp01( part.end.z / floor->height) * 0.8; gradient.setColorAt(0, QColor(p1*255, p1*255, p1*255)); gradient.setColorAt(1, QColor(p2*255, p2*255, p2*255)); qp.setBrush(gradient); qp.setPen(QColor(0,0,0,128)); // polygon-construction QPolygon poly; poly.push_back(toQPoint(s.mapToScreen(quad.p1.xy()))); poly.push_back(toQPoint(s.mapToScreen(quad.p2.xy()))); poly.push_back(toQPoint(s.mapToScreen(quad.p3.xy()))); poly.push_back(toQPoint(s.mapToScreen(quad.p4.xy()))); qp.drawPolygon(poly); } } /** draw the given outline polygon */ void drawOutline(QPainter& qp, const Scaler2D& s, const Floorplan::FloorOutlinePolygon* poly) { // configure the drawing if (poly->method == Floorplan::OutlineMethod::ADD) { qp.setPen(Qt::gray); qp.setBrush(Qt::NoBrush); } else if (poly->method == Floorplan::OutlineMethod::REMOVE) { QBrush brush; brush.setStyle(Qt::BrushStyle::DiagCrossPattern); brush.setColor(QColor(0,0,0)); qp.setPen(Qt::gray); qp.setBrush(brush); } // construct the polygon const int num = poly->poly.points.size(); QPolygon qpoly; for (int i = 0; i < num; ++i) { qpoly.push_back(toQPoint(s.mapToScreen(poly->poly.points[(i+0)]))); } // draw the polygon qp.drawPolygon(qpoly); } /** convert floorplan polygon to QPolygon */ static inline QPolygon toQPolygon(const Floorplan::Polygon2& poly) { QPolygon qpoly; for (const Point2 p : poly.points) { qpoly.push_back(QPoint(p.x, p.y)); } return qpoly; } /** convert floorplan polygon to QPolygon */ static inline QPolygon toQPolygon(const Floorplan::Polygon2& poly, const Scaler2D& s) { QPolygon qpoly; for (const Point2 _p : poly.points) { const Point2 p = s.mapToScreen(_p); qpoly.push_back(QPoint(p.x, p.y)); } return qpoly; } /** convert Point2 to QPoint */ static inline QPoint toQPoint(const Point2 p) { return QPoint(p.x, p.y); } /** helper method. limit val to [0:1] */ static inline float clamp01(const float val) { if (val < 0) {return 0;} if (val > 1) {return 1;} return val; } }; #endif // FLOOR2D_H