From 423fbfc545ba57884c48d47d2e04df0e13cb7a56 Mon Sep 17 00:00:00 2001 From: kazu Date: Sun, 22 Jul 2018 17:33:55 +0200 Subject: [PATCH] focused elements always on top indicate connected walls fixes int/float issues refactoring --- mapview/2D/MV2DElementFloorObstacleLine.cpp | 51 +++++++++----- mapview/2D/MV2DElementFloorObstacleLine.h | 3 +- mapview/2D/MapView2D.cpp | 37 +++++++--- mapview/2D/Painter.cpp | 69 ++++++++++++------- .../3D/floorplan/FloorplanRendererModel.cpp | 28 ++++---- mapview/model/MMFloorObstacleLine.h | 2 +- 6 files changed, 121 insertions(+), 69 deletions(-) diff --git a/mapview/2D/MV2DElementFloorObstacleLine.cpp b/mapview/2D/MV2DElementFloorObstacleLine.cpp index 1f5f5ce..502d4f5 100644 --- a/mapview/2D/MV2DElementFloorObstacleLine.cpp +++ b/mapview/2D/MV2DElementFloorObstacleLine.cpp @@ -7,7 +7,7 @@ #include #include -MV2DElementFloorObstacleLine::MV2DElementFloorObstacleLine(Floorplan::FloorObstacleLine* fo) : fo(fo) { +MV2DElementFloorObstacleLine::MV2DElementFloorObstacleLine(Floorplan::Floor* f, Floorplan::FloorObstacleLine* fo) : f(f), fo(fo) { ; } @@ -22,29 +22,47 @@ ClickDist MV2DElementFloorObstacleLine::getMinDistanceXY(const Point2 p) const { return MapElementHelper::getLineDistanceXY(fo->from, fo->to, p); } -void MV2DElementFloorObstacleLine::paint(Painter& p) { +bool isConnected(const Point2 p, const Floorplan::Floor* f, const Floorplan::FloorObstacleLine* fo) { + const float delta = 0.001; + for (const Floorplan::FloorObstacle* fo1 : f->obstacles) { + if (fo1 == fo) {continue;} + const Floorplan::FloorObstacleLine* line = dynamic_cast(fo1); + if (line) { + if (line->from.eq(p, delta)) {return true;} + if (line->to.eq(p, delta)) {return true;} + } + } + return false; +} - // DEPRECATED -// // selected endpoints? -// if (hasFocus()) { -// p.setPenBrush(Qt::NoPen, CFG::SEL_COLOR); -// if (selectedUserIdx == 0) {p.drawCircle(fo->from);} -// if (selectedUserIdx == 1) {p.drawCircle(fo->to);} -// } +void MV2DElementFloorObstacleLine::paint(Painter& p) { // convert wall's thickness from meter to pixels const float thickness_px = p.s.ms(fo->thickness_m); - // remember the old pen - //QPen pen = p.getPen(); - // see notes within MapElementHelper! // lines only get thicker, but not longer! p.setPenBrush(MapElementHelper::getPen(fo->material, fo->type, hasFocus(), thickness_px), Qt::NoBrush); + + // draw the wall itself p.drawLine(fo->from, fo->to); - // reset the old pen3 - //p.setPen(pen); + const bool c1 = isConnected(fo->from, f, fo); + const bool c2 = isConnected(fo->to, f, fo); + + // wall conencted to other walls? + if (c1 || c2) { + + // QPen change is costly! + QPen pp = p.getPen(); + pp.setCapStyle(Qt::RoundCap); + p.setPen(pp); + + // indicate connection with other wall + if (c1) {p.drawDot(fo->from);} + if (c2) {p.drawDot(fo->to);} + + } // length info if (hasFocus()) { @@ -55,11 +73,6 @@ void MV2DElementFloorObstacleLine::paint(Painter& p) { } - // DEPRECATED -// // available endpoints -// p.drawNode(fo->from, hasFocus(), hasFocus() && selectedUserIdx == 0); -// p.drawNode(fo->to, hasFocus(), hasFocus() && selectedUserIdx == 1); - } void MV2DElementFloorObstacleLine::onFocus() { diff --git a/mapview/2D/MV2DElementFloorObstacleLine.h b/mapview/2D/MV2DElementFloorObstacleLine.h index 1b9c74a..1df0221 100644 --- a/mapview/2D/MV2DElementFloorObstacleLine.h +++ b/mapview/2D/MV2DElementFloorObstacleLine.h @@ -10,12 +10,13 @@ class MV2DElementFloorObstacleLine : public MV2DElement, public HasMoveableNodes private: + Floorplan::Floor* f; Floorplan::FloorObstacleLine* fo; public: /** ctor */ - MV2DElementFloorObstacleLine(Floorplan::FloorObstacleLine* fo); + MV2DElementFloorObstacleLine(Floorplan::Floor* f, Floorplan::FloorObstacleLine* fo); /** get the element's 3D bounding box */ BBox2 getBoundingBox() const override; diff --git a/mapview/2D/MapView2D.cpp b/mapview/2D/MapView2D.cpp index 4a35c5e..c3cc943 100644 --- a/mapview/2D/MapView2D.cpp +++ b/mapview/2D/MapView2D.cpp @@ -39,8 +39,8 @@ MapView2D::MapView2D(QWidget* parent) : QOpenGLWidget(parent) { void MapView2D::paintGL() { - QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); - f->glClear(GL_COLOR_BUFFER_BIT); +// QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); +// f->glClear(GL_COLOR_BUFFER_BIT); QPainter qp(this); Painter p(s, &qp, width(), height()); @@ -50,19 +50,34 @@ void MapView2D::paintGL() { tools.paintBefore(this, p); + + + std::vector normal; + std::vector focused; + + // get all visible elements that can be rendered + // group them whether they currently have focus or not + for (MapModelElement* el : getModel()->getVisibleElements()) { + if (el->getMV2D()) { + if (el->getMV2D()->hasFocus()) { + focused.push_back(el->getMV2D()); + } else { + normal.push_back(el->getMV2D()); + } + } + } + qp.setRenderHint( QPainter::Antialiasing, true ); - // render all visible elements. 1st run - for (MapModelElement* el : getModel()->getVisibleElements()) { - if (el->getMV2D()) {el->getMV2D()->paint(p);} - } + // 2 layer rendering (paint, paintAfter), only UNFOCUSED elements + for (MV2DElement* e : normal) {e->paint(p);} + for (MV2DElement* e : normal) {e->paintAfter(p);} - // render all visible elements. 2nd run - for (MapModelElement* el : getModel()->getVisibleElements()) { - if (el->getMV2D()) {el->getMV2D()->paintAfter(p);} - } + // 2 layer rendering (paint, paintAfter), only FOCUSED elements + for (MV2DElement* e : focused) {e->paint(p);} + for (MV2DElement* e : focused) {e->paintAfter(p);} - qp.setRenderHint( QPainter::Antialiasing, false ); + //qp.setRenderHint( QPainter::Antialiasing, false ); // foreground tools tools.paintAfter(this, p); diff --git a/mapview/2D/Painter.cpp b/mapview/2D/Painter.cpp index 7663323..f52f69d 100644 --- a/mapview/2D/Painter.cpp +++ b/mapview/2D/Painter.cpp @@ -18,6 +18,12 @@ int Painter::width() {return w;} int Painter::height() {return h;} +float Painter::radToDeg(const float rad) const { + return rad * 180 / M_PI; +} + + + bool Painter::isVisible(const Point2 p) { const float x = s.xms(p.x); const float y = s.yms(p.y); @@ -36,69 +42,82 @@ void Painter::drawLine(const Point2 p1, const Point2 p2) { //p->drawLine(s.xms(p1.x), s.yms(p1.y), s.xms(p2.x), s.yms(p2.y)); p->drawLine(QPointF(s.xms(p1.x), s.yms(p1.y)), QPointF(s.xms(p2.x), s.yms(p2.y))); } + void Painter::drawLine(const Point3 p1, const Point3 p2) { //p->drawLine(s.xms(p1.x), s.yms(p1.y), s.xms(p2.x), s.yms(p2.y)); p->drawLine(QPointF(s.xms(p1.x), s.yms(p1.y)), QPointF(s.xms(p2.x), s.yms(p2.y))); } -float Painter::radToDeg(const float rad) const { - return rad * 180 / M_PI; +void Painter::drawLine(const float x1, const float y1, const float x2, const float y2) { + p->drawLine(QPointF(s.xms(x1), s.yms(y1)), QPointF(s.xms(x2), s.yms(y2))); } + void Painter::drawArc(const Point2 center, const float radius, const float startAngleRad, const float spanAngleRad) { const float wh = s.ms(radius) * 2; const float x1 = s.xms(center.x) - wh/2; const float y1 = s.yms(center.y) - wh/2; - p->drawArc(x1, y1, wh, wh, radToDeg(startAngleRad)*16, radToDeg(spanAngleRad)*16); + const QRectF rect(x1, y1, wh, wh); + p->drawArc(rect, radToDeg(startAngleRad)*16, radToDeg(spanAngleRad)*16); + //p->drawArc(x1, y1, wh, wh, radToDeg(startAngleRad)*16, radToDeg(spanAngleRad)*16); } + +/** draw a dot at the given map coordinates */ +void Painter::drawDot(const Point2 center) { + //int r = 1; + //p->drawEllipse(QPointF(s.xms(center.x)-r, s.yms(center.y)-r), 2*r, 2*r); + p->drawPoint(QPointF(s.xms(center.x), s.yms(center.y))); +} + + + void Painter::drawCircle(const Point3 center) { int r = 5; - p->drawEllipse(s.xms(center.x)-r, s.yms(center.y)-r, 2*r, 2*r); + p->drawEllipse(QPointF(s.xms(center.x), s.yms(center.y)), r, r); } void Painter::drawCircle(const Point2 center) { int r = 5; - p->drawEllipse(s.xms(center.x)-r, s.yms(center.y)-r, 2*r, 2*r); -} - -/** draw a dot at the given map coordinates */ -void Painter::drawDot(const Point2 center) { - int r = 1; - p->drawEllipse(s.xms(center.x)-r, s.yms(center.y)-r, 2*r, 2*r); + p->drawEllipse(QPointF(s.xms(center.x), s.yms(center.y)), r, r); } void Painter::drawCircle(const Point2 center, const float size_m) { int r = s.ms(size_m); - p->drawEllipse(s.xms(center.x)-r, s.yms(center.y)-r, 2*r, 2*r); + p->drawEllipse(QPointF(s.xms(center.x), s.yms(center.y)), r, r); } void Painter::drawCircle_px(const Point2 center, const float size_px) { int r = size_px; - p->drawEllipse(s.xms(center.x)-r, s.yms(center.y)-r, 2*r, 2*r); + p->drawEllipse(QPointF(s.xms(center.x), s.yms(center.y)), r, r); } + + + + void Painter::drawNode(Point2 pt, bool focused, bool selected) { - float rs = 0.05; - if (selected) {setPenBrush(Qt::black, Qt::gray); rs = 0.08;} - else if (focused) {setPenBrush(Qt::black, Qt::white); rs = 0.08;} - else {setPenBrush(Qt::black, Qt::NoBrush); rs = 0.04;} + float rs = 4; + if (selected) {setPenBrush(Qt::black, Qt::gray); rs*=2;} + else if (focused) {setPenBrush(Qt::black, Qt::white); rs*=2;} + else {setPenBrush(Qt::black, Qt::NoBrush); rs*=1;} const float s = this->s.getScale(); - if (s > 10) {drawCircle(pt, rs);} // only at a certain zoom level + if (s > 25) {drawCircle_px(pt, rs);} // only at a certain zoom level + else if (s > 10) {drawCircle_px(pt, 1);} // only at a certain zoom level } -void Painter::drawLine(const float x1, const float y1, const float x2, const float y2) { - p->drawLine(s.xms(x1), s.yms(y1), s.xms(x2), s.yms(y2)); -} + void Painter::drawRect(const Point2 p1, const Point2 p2) { drawRect(p1.x, p1.y, p2.x, p2.y); } void Painter::drawRect(const float x1, const float y1, const float x2, const float y2) { - float w = x2-x1; - float h = y1-y2; - p->drawRect(s.xms(x1), s.yms(y1), s.ms(w), s.ms(h)); + const float w = x2-x1; + const float h = y1-y2; + const QRectF rect(s.xms(x1), s.yms(y1), s.ms(w), s.ms(h)); + p->drawRect(rect); + //p->drawRect(s.xms(x1), s.yms(y1), s.ms(w), s.ms(h)); } void Painter::drawRect(const Point2 center) { @@ -107,7 +126,7 @@ void Painter::drawRect(const Point2 center) { } void Painter::drawText(const Point2 pos, const std::string& text) { - p->drawText(s.xms(pos.x), s.yms(pos.y), text.c_str()); + p->drawText(QPointF(s.xms(pos.x), s.yms(pos.y)), text.c_str()); } void Painter::drawPolygon(const std::vector& points) { diff --git a/mapview/3D/floorplan/FloorplanRendererModel.cpp b/mapview/3D/floorplan/FloorplanRendererModel.cpp index 3266e7a..da26f0f 100644 --- a/mapview/3D/floorplan/FloorplanRendererModel.cpp +++ b/mapview/3D/floorplan/FloorplanRendererModel.cpp @@ -15,6 +15,8 @@ struct Material { const std::vector mats = { + Material(255,0,0,255), // error + Material(0,128,0,255), // ground outdoor Material(64,64,64,255), // ground outdoor Material(105,105,105,255), // stair @@ -37,21 +39,23 @@ const std::vector mats = { int FloorplanRendererModel::getMaterial(const Ray3D::Obstacle3D& o) const { - if (o.type == Ray3D::Obstacle3D::Type::GROUND_OUTDOOR) {return 0;} - if (o.type == Ray3D::Obstacle3D::Type::GROUND_INDOOR) {return 1;} - if (o.type == Ray3D::Obstacle3D::Type::STAIR) {return 2;} - if (o.type == Ray3D::Obstacle3D::Type::HANDRAIL) {return 3;} - if (o.type == Ray3D::Obstacle3D::Type::OBJECT) {return 11;} + if (o.type == Ray3D::Obstacle3D::Type::ERROR) {return 0;} - if (o.type == Ray3D::Obstacle3D::Type::DOOR && o.mat == Floorplan::Material::GLASS) {return 4;} - if (o.type == Ray3D::Obstacle3D::Type::DOOR) {return 5;} + if (o.type == Ray3D::Obstacle3D::Type::GROUND_OUTDOOR) {return 1;} + if (o.type == Ray3D::Obstacle3D::Type::GROUND_INDOOR) {return 2;} + if (o.type == Ray3D::Obstacle3D::Type::STAIR) {return 3;} + if (o.type == Ray3D::Obstacle3D::Type::HANDRAIL) {return 4;} + if (o.type == Ray3D::Obstacle3D::Type::OBJECT) {return 12;} - if (o.mat == Floorplan::Material::CONCRETE) {return 6;} - if (o.mat == Floorplan::Material::GLASS) {return 7;} - if (o.mat == Floorplan::Material::METALLIZED_GLAS) {return 8;} + if (o.type == Ray3D::Obstacle3D::Type::DOOR && o.mat == Floorplan::Material::GLASS) {return 5;} + if (o.type == Ray3D::Obstacle3D::Type::DOOR) {return 6;} - if (o.mat == Floorplan::Material::WOOD) {return 9;} - if (o.mat == Floorplan::Material::DRYWALL) {return 10;} + if (o.mat == Floorplan::Material::CONCRETE) {return 7;} + if (o.mat == Floorplan::Material::GLASS) {return 8;} + if (o.mat == Floorplan::Material::METALLIZED_GLAS) {return 9;} + + if (o.mat == Floorplan::Material::WOOD) {return 10;} + if (o.mat == Floorplan::Material::DRYWALL) {return 11;} return 12; diff --git a/mapview/model/MMFloorObstacleLine.h b/mapview/model/MMFloorObstacleLine.h index 4e93943..e10aedf 100644 --- a/mapview/model/MMFloorObstacleLine.h +++ b/mapview/model/MMFloorObstacleLine.h @@ -26,7 +26,7 @@ public: public: MMFloorObstacleLine(MapLayer* parent, Floorplan::Floor* mf, Floorplan::FloorObstacleLine* fo) : - MapModelElement(parent), mf(mf), fo(fo), mv2d(fo) {//, mv3d(mf,fo) { + MapModelElement(parent), mf(mf), fo(fo), mv2d(mf, fo) {//, mv3d(mf,fo) { }