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
2018-10-25 12:23:40 +02:00

188 lines
4.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* © Copyright 2014 Urheberrechtshinweis
* Alle Rechte vorbehalten / All Rights Reserved
*
* Programmcode ist urheberrechtlich geschuetzt.
* Das Urheberrecht liegt, soweit nicht ausdruecklich anders gekennzeichnet, bei Frank Ebner.
* Keine Verwendung ohne explizite Genehmigung.
* (vgl. § 106 ff UrhG / § 97 UrhG)
*/
#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