#ifndef MV2DELEMENTFLOOROUTLINEPOLYGON_H #define MV2DELEMENTFLOOROUTLINEPOLYGON_H #include "MV2DElement.h" #include "MapViewElementHelper.h" #include class MV2DElementFloorOutlinePolygon : public MV2DElement { private: int selPoint = -1; Floorplan::FloorOutlinePolygon& fo; public: /** ctor */ MV2DElementFloorOutlinePolygon(Floorplan::FloorOutlinePolygon& fo) : fo(fo) {;} /** get the element's 3D bounding box */ BBox2 getBoundingBox() const override { BBox2 bbox; for (const Point2 p : fo.poly.points) { bbox.add(p); } return bbox; } /** get the element's minimal distance (nearest whatsoever) to the given point */ float getMinDistanceXY(const Point2 p) const override { float min = 999999; for (int i = 0; i < (int)fo.poly.points.size()-1; ++i) { const Point2 p1 = fo.poly.points[i]; const Point2 p2 = fo.poly.points[i+1]; const float dst = MapElementHelper::getLineDistanceXY(p1, p2, p); if (dst < min) {min = dst;} } return min; } virtual void onFocus() override { } virtual void onUnfocus() override { selPoint = -1; // clear selection } void paint(Painter& p) override { QBrush brush; // fill-style (depends on the mode) switch (fo.method) { case Floorplan::OutlineMethod::ADD: brush.setStyle(Qt::BrushStyle::SolidPattern); brush.setColor(QColor(0,0,0,24)); break; case Floorplan::OutlineMethod::REMOVE: brush.setStyle(Qt::BrushStyle::DiagCrossPattern); brush.setColor(QColor(0,0,0)); break; default: brush.setStyle(Qt::BrushStyle::SolidPattern); brush.setColor(QColor(255,0,0)); } // outline + filled area p.setPenBrush(Qt::black, brush); p.drawPolygon(fo.poly.points); // selected endpoints? if (hasFocus() && selPoint != -1) { p.setPenBrush(Qt::NoPen, CFG::SEL_COLOR); p.drawCircle(fo.poly.points[selPoint]); } // available endpoints if (hasFocus()) { p.setPenBrush(Qt::black, Qt::NoBrush); for (const Point2 pt : fo.poly.points) { p.drawCircle(pt); } } } virtual void mousePressed(MapView2D* v, const Point2 p) override { (void) v; (void) p; } virtual void mouseMove(MapView2D* v, const Point2 _p) override { (void) v; if (selPoint == -1) {return;} const Point2 p = Scaler::snap(_p, CFG::MOVE_SNAP_SIZE_M); fo.poly.points[selPoint].x = p.x; fo.poly.points[selPoint].y = p.y; } virtual void mouseReleased(MapView2D* v, const Point2 _p) override { (void) v; // if (selPoint != -1) { // const Point3 p = Scaler::snap(_p, CFG::MOVE_SNAP_SIZE_M); // fo.poly.points[selPoint].x = p.x; // fo.poly.points[selPoint].y = p.y; // } // select a new point on mouse-release (more robust than on mouse-press) const float t = v->getScaler().sm(CFG::SEL_THRESHOLD_SIZE_PX); auto comp = [&] (const Point2 a, const Point2 b) {return a.getDistance(_p) < b.getDistance(_p);}; auto it = std::min_element(fo.poly.points.begin(), fo.poly.points.end(), comp); if (it == fo.poly.points.end()) {selPoint = -1;} // none found -> skip else if ((*it).getDistance(_p) > t) {selPoint = -1;} // nearest distance is above threshold -> skip else {selPoint = it - fo.poly.points.begin();} } virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override { (void) v; if (e->key() == Qt::Key_Delete) { // delete the currently selected vertex? if (selPoint != -1) { fo.poly.points.erase(fo.poly.points.begin() + selPoint); selPoint = -1; return true; } } else if (e->key() == Qt::Key_Plus && selPoint != -1) { int idx1 = selPoint; int idx2 = (selPoint + 1) % fo.poly.points.size(); int idxNew = idx2; Point2 pNew = (fo.poly.points[idx1] + fo.poly.points[idx2]) / 2.0f; fo.poly.points.insert(fo.poly.points.begin() + idxNew, pNew); selPoint = idxNew; return true; } // not consumed return false; } }; #endif // MV2DELEMENTFLOOROUTLINEPOLYGON_H