This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
IndoorMap/mapview/2D/MV2DElementFloorUnderlay.h
kazu 92e279aefc added option for underlay opacity change
adjusted interface [removed invalid const]
2017-03-20 15:25:54 +01:00

178 lines
4.5 KiB
C++

#ifndef MV2DELEMENTFLOORUNDERLAY_H
#define MV2DELEMENTFLOORUNDERLAY_H
#include "MV2DElement.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* 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;
float opacity = 0.5;
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 */
ClickDist getMinDistanceXY(const Point2 p) const override {
(void) p;
return ClickDist(CFG::SEL_THRESHOLD_SIZE_PX, ClickDistType::UNKNOWN); // we do not know the distance from the image
}
virtual void onFocus() override {
}
virtual void onUnfocus() override {
selPoint = -1; // clear selection
}
float getOpacity() const {return opacity;}
void setOpacity(const float o) {this->opacity = o;}
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*0.75) {
// 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();
}
// current opacity?
float _oldOpacity = p.p->opacity();
p.p->setOpacity(opacity);
// 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()));
}
// reset
p.p->setOpacity(_oldOpacity);
// 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