#ifndef MV2DELEMENTFLOORUNDERLAY_H #define MV2DELEMENTFLOORUNDERLAY_H #include "MV2DElement.h" #include "MapViewElementHelper.h" #include /** * display e.g. a PNG-file below the map [as reference] */ class MV2DElementFloorUnderlay : public MV2DElement { private: QImage img; QImage imgScaled; std::string tmpFile; Floorplan::UnderlayImage* underlay; BBox2 bbox; int selPoint = -1; public: /** ctor */ MV2DElementFloorUnderlay(Floorplan::UnderlayImage* underlay) : underlay(underlay) { missing(); } void missing() { //img = QImage(QSize(64, 64), QImage::Format_ARGB32); //img.fill(0xFF000000); img = QImage("://res/icons/cross.png"); } /** get the element's 3D bounding box */ BBox2 getBoundingBox() const override { return bbox; } /** get the element's minimal distance (nearest whatsoever) to the given point */ float getMinDistanceXY(const Point2 p) const override { (void) p; return CFG::SEL_THRESHOLD_SIZE_PX; // we do not know the distance from the image } virtual void onFocus() override { } virtual void onUnfocus() override { selPoint = -1; // clear selection } void paint(Painter& p) override { (void) p; if (tmpFile != underlay->filename) { img = QImage(underlay->filename.c_str()); if (img.size().width() == 0) { missing(); } img = img.convertToFormat(QImage::Format_Grayscale8); // saves a huge amount of memory and should suffice tmpFile = underlay->filename; } // map coordinates float mx1 = underlay->anchor.x; float my1 = underlay->anchor.y; float mw = img.width() * underlay->scaleX; float mh = img.height() * underlay->scaleY; float mx2 = mx1+mw; float my2 = my1+mh; // screen coordinates float sx1 = p.s.xms(mx1); float sy1 = p.s.yms(my1); float sx2 = p.s.xms(mx2); float sy2 = p.s.yms(my2); float sw = std::round(std::abs(sx1-sx2)); float sh = std::round(std::abs(sy1-sy2)); const float origArea = img.width() * img.height(); const float scaledArea = sw*sh; bbox = BBox2(); bbox.add(Point2(mx1, my1)); bbox.add(Point2(mx2, my2)); // if the to-be-displayed image is smaller than the input-one, use a pre-computed downscaled version if (scaledArea < origArea) { // does the cached downscaled image needs rebuild? (size changed) if (imgScaled.width() != sw || imgScaled.height() != sh) { imgScaled = img.scaled(sw, sh, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); } } else { imgScaled = QImage(); } float opacity = p.p->opacity(); p.p->setOpacity(0.50f); // render downscaled image from cache? or use live-upscaling (faster, eats up less memory, ...) if (imgScaled.width() > 0) { p.p->drawImage(sx1, sy1-sh, imgScaled); } else { p.p->setRenderHint(QPainter::SmoothPixmapTransform, true); p.p->drawImage(QRectF(sx1, sy1-sh, sw, sh), img, QRectF(0,0,img.width(),img.height())); } p.p->setOpacity(opacity); // selected endpoint(s)? if (hasFocus()) { p.setPenBrush(Qt::NoPen, CFG::SEL_COLOR); if (selPoint == 0) {p.drawCircle(bbox.getMin());} } // just focused? if (hasFocus()) { p.setPenBrush(Qt::black, Qt::NoBrush); p.drawRect(mx1,my1,mx2,my2); p.drawCircle(bbox.getMin()); } } 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); if (selPoint == 0) {underlay->anchor = p;} } virtual void mouseReleased(MapView2D* v, const Point2 _p) override { // select a new point on mouse-release (more robust than on mouse-press) const float t = v->getScaler().sm(CFG::SEL_THRESHOLD_SIZE_PX); const float l1 = _p.getDistance(bbox.getMin()); if (l1 <= t) {selPoint = 0;} else {selPoint = -1;} } virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override { (void) v; const float s = (e->modifiers() & Qt::ShiftModifier) ? (1.0f) : (0.1f); if (e->key() == Qt::Key_Up) {underlay->anchor += Point2(0, +s); return true;} if (e->key() == Qt::Key_Down) {underlay->anchor += Point2(0, -s); return true;} if (e->key() == Qt::Key_Left) {underlay->anchor += Point2(-s, 0); return true;} if (e->key() == Qt::Key_Right) {underlay->anchor += Point2(+s, 0); return true;} return false; } }; #endif // MV2DELEMENTFLOORUNDERLAY_H