#ifndef MV2DELEMENTFLOOROUTLINEPOLYGON_H #define MV2DELEMENTFLOOROUTLINEPOLYGON_H #include "MV2DElement.h" #include "HasMoveableNodes.h" #include "MapViewElementHelper.h" #include class MV2DElementFloorOutlinePolygon : public MV2DElement, public HasMoveableNodes { private: 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 */ ClickDist getMinDistanceXY(const Point2 p) const override { ClickDist min = ClickDist::max(); 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 ClickDist dst = MapElementHelper::getLineDistanceXY(p1, p2, p); if (dst < min) {min = dst;} } return min; } virtual void onFocus() override { } virtual void onUnfocus() override { selectedUserIdx = -1; // clear selection } void paint(Painter& p) override { QBrush brush; QPen pen; // fill-style (depends on the mode) switch (fo.method) { case Floorplan::OutlineMethod::ADD: brush.setStyle(Qt::BrushStyle::SolidPattern); brush.setColor( fo.outdoor ? QColor(0,255,0,32) : QColor(0,0,0,24) ); // outdoor = green break; case Floorplan::OutlineMethod::REMOVE: brush.setStyle(Qt::BrushStyle::DiagCrossPattern); brush.setColor(QColor(0,0,0)); break; default: // should not happen brush.setStyle(Qt::BrushStyle::SolidPattern); brush.setColor(QColor(255,0,0)); } if (hasFocus()) { brush.setStyle(Qt::BrushStyle::FDiagPattern); } // outline + filled area pen.setColor(Qt::black); pen.setWidth( hasFocus() ? 2 : 1 ); p.setPenBrush(pen, brush); p.drawPolygon(fo.poly.points); // selected endpoints? if (hasFocus() && selectedUserIdx != -1) { p.setPenBrush(Qt::NoPen, CFG::SEL_COLOR); p.drawCircle(fo.poly.points[selectedUserIdx]); } // available endpoints if (hasFocus()) { p.setPenBrush(Qt::black, Qt::NoBrush); for (const Point2 pt : fo.poly.points) { p.drawCircle(pt); } } } /** get a list of all nodes that are selectable / moveable */ virtual std::vector getMoveableNodes() const override { std::vector nodes; for (int i = 0; i < (int) fo.poly.points.size(); ++i) { nodes.push_back(MoveableNode(i, fo.poly.points[i])); } return nodes; } /** the given node was moved */ virtual void onNodeMove(MapView2D* v, const int userIdx, const Point2 newPos) override { (void) v; fo.poly.points[userIdx].x = newPos.x; fo.poly.points[userIdx].y = newPos.y; } // 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 = v->getScaler().snap(_p); // 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 (selectedUserIdx != -1) { fo.poly.points.erase(fo.poly.points.begin() + selectedUserIdx); selectedUserIdx = -1; return true; } } else if (e->key() == Qt::Key_Plus && selectedUserIdx != -1) { int idx1 = selectedUserIdx; int idx2 = (selectedUserIdx + 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); selectedUserIdx = idxNew; return true; } // not consumed return false; } }; #endif // MV2DELEMENTFLOOROUTLINEPOLYGON_H