initial commit

This commit is contained in:
kazu
2016-05-24 16:55:19 +02:00
commit 13a89df8d6
77 changed files with 7454 additions and 0 deletions

90
mapview/MapView2D.cpp Normal file
View File

@@ -0,0 +1,90 @@
#include "MapView2D.h"
#include <QPainter>
#include <QOpenGLFunctions>
#include <QMouseEvent>
#include <QKeyEvent>
#include <iostream>
#include "model/MapModelElement.h"
#include "model/MapModel.h"
MapView2D::MapView2D(QWidget* parent) : QOpenGLWidget(parent) {
// openGL params
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setSamples(1);
// format.setVersion(3, 2);
format.setProfile(QSurfaceFormat::CoreProfile);
setFormat(format);
// receive mouse-move even when mouse is not down
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
// defaults
s.setScale(5);
}
void MapView2D::paintGL() {
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClear(GL_COLOR_BUFFER_BIT);
QPainter qp(this);
Painter p(s, &qp, width(), height());
s.setScreenSize(width(), height());
// background tools
tools.paintBefore(this, p);
// render all visible elements
qp.setRenderHint( QPainter::Antialiasing, true );
for (MapModelElement* el : getModel()->getVisibleElements()) {el->getMV2D()->paint(p);}
qp.setRenderHint( QPainter::Antialiasing, false );
// foreground tools
tools.paintAfter(this, p);
}
void MapView2D::initializeGL() {
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
f->glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
void MapView2D::resizeGL() {
// TODO ?
}
void MapView2D::keyPressEvent(QKeyEvent *e) {
tools.keyPressEvent(this, e);
update();
}
void MapView2D::wheelEvent(QWheelEvent* e) {
tools.wheelEvent(this, e);
update();
}
void MapView2D::mousePressEvent(QMouseEvent* e) {
tools.mousePressEvent(this, e);
update();
}
void MapView2D::mouseMoveEvent(QMouseEvent* e) {
tools.mouseMoveEvent(this, e);
update();
}
void MapView2D::mouseReleaseEvent(QMouseEvent* e) {
tools.mouseReleaseEvent(this, e);
update();
}

76
mapview/MapView2D.h Normal file
View File

@@ -0,0 +1,76 @@
#ifndef MAP2D_H
#define MAP2D_H
#include <QWidget>
#include <QOpenGLWidget>
#include "Scaler.h"
class MapModel;
#include "mapview/tools/Tools.h"
/**
* view to render (and edit) MapElements
*/
class MapView2D : public QOpenGLWidget {
Q_OBJECT
private:
/** scaling within the map */
Scaler s;
/** the currently active tool (if any) */
Tools tools;
/** the underlying data-model */
MapModel* model = nullptr;
public:
/** ctor */
MapView2D(QWidget* parent = nullptr);
void layerChange() {
update();
tools.layerChange(this);
}
public:
void paintGL();
void initializeGL();
void resizeGL();
Tools& getTools() {return tools;}
/** get the underlying data-model */
MapModel* getModel() {return model;}
/** set the underlying data-model */
void setModel(MapModel* mdl) {
this->model = mdl;
update();
}
/** get the underlying scaling device */
Scaler& getScaler() {return s;}
protected:
void mousePressEvent(QMouseEvent* e);
void mouseMoveEvent(QMouseEvent* e);
void mouseReleaseEvent(QMouseEvent* e);
void wheelEvent(QWheelEvent* e);
void keyPressEvent(QKeyEvent* e);
};
#endif // MAP2D_H

102
mapview/Painter.h Normal file
View File

@@ -0,0 +1,102 @@
#ifndef PAINTER_H
#define PAINTER_H
#include <QPainter>
#include <Indoor/geo/Point2.h>
#include <Indoor/geo/Point3.h>
#include "Scaler.h"
class Painter {
public:
Scaler& s;
QPainter* p;
int w;
int h;
public:
/** ctor */
Painter(Scaler& s, QPainter* p, int w, int h) : s(s), p(p), w(w), h(h) {
p->setPen(Qt::black);
p->setBrush(Qt::NoBrush);
}
int width() {return w;}
int height() {return h;}
void drawLine(const Point2 p1, const Point2 p2) {
p->drawLine(s.xms(p1.x), s.yms(p1.y), s.xms(p2.x), s.yms(p2.y));
}
void drawLine(const Point3 p1, const Point3 p2) {
p->drawLine(s.xms(p1.x), s.yms(p1.y), s.xms(p2.x), s.yms(p2.y));
}
void drawCircle(const Point3 center) {
int r = 5;
p->drawEllipse(s.xms(center.x)-r, s.yms(center.y)-r, 2*r, 2*r);
}
void drawCircle(const Point2 center) {
int r = 5;
p->drawEllipse(s.xms(center.x)-r, s.yms(center.y)-r, 2*r, 2*r);
}
void drawCircle(const Point2 center, const float size_m) {
int r = s.ms(size_m);
p->drawEllipse(s.xms(center.x)-r, s.yms(center.y)-r, 2*r, 2*r);
}
void drawLine(const float x1, const float y1, const float x2, const float y2) {
p->drawLine(s.xms(x1), s.yms(y1), s.xms(x2), s.yms(y2));
}
void drawRect(const float x1, const float y1, const float x2, const float y2) {
float w = x2-x1;
float h = y1-y2;
p->drawRect(s.xms(x1), s.yms(y1), s.ms(w), s.ms(h));
}
void drawText(const Point2 pos, const std::string& text) {
p->drawText(s.xms(pos.x), s.xms(pos.y), text.c_str());
}
void drawPolygon(const std::vector<Point2>& points) {
std::vector<QPointF> vec;
for (const Point2 p : points) {
vec.push_back(QPointF(s.xms(p.x), s.yms(p.y)));
}
p->drawPolygon(vec.data(), vec.size());
}
void drawPolygon(const std::vector<Point3>& points) {
std::vector<QPointF> vec;
for (const Point3 p : points) {
vec.push_back(QPointF(s.xms(p.x), s.yms(p.y)));
}
p->drawPolygon(vec.data(), vec.size());
}
void setBrush(const QBrush& brush) { p->setBrush(brush); }
void setBrush(const Qt::BrushStyle& brush) { p->setBrush(brush); }
void setPen(const QPen& pen) {p->setPen(pen); }
void setPen(const QColor& pen) {p->setPen(pen); }
void setPen(const Qt::PenStyle& pen) {p->setPen(pen); }
template <typename Pen, typename Brush> void setPenBrush(const Pen& pen, const Brush& brush) {setPen(pen); setBrush(brush);}
const Scaler& getScaler() {return s;}
private:
};
#endif // PAINTER_H

104
mapview/Scaler.h Normal file
View File

@@ -0,0 +1,104 @@
#ifndef SCALER_H
#define SCALER_H
#include <Indoor/geo/Point3.h>
#include <QRectF>
struct Rect {
float x0;
float y0;
float x1;
float y1;
};
/**
* - scale between map- and screen-space.
* - inverts y-axis (for openGL)
*/
class Scaler {
private:
int w;
int h;
float _scale = 50;
float _snap = 0.1;
Point3 _offset;
public:
/** map->screen (no offset) */
float ms(const float m) const {return m*_scale;}
/** x map->screen */
float xms(const float x) const {return w/2+(x+_offset.x)*_scale;}
/** x map->screen */
float yms(const float y) const {return h/2-(y-_offset.y)*_scale;}
/** screen->map (no offset) */
float sm(const float s) const {return (s/_scale);}
/** x screen->map */
float xsm(const float x) const {return ((x-w/2)/_scale)-_offset.x;}
/** y screen->map */
float ysm(const float y) const {return ((h/2-y)/_scale)+_offset.y;}
void setScale(const float s) {_scale = s;}
float getScale() const {return _scale;}
void setOffset(Point3 p) {_offset = p;}
Point3 getOffset() const {return _offset;}
void addOffset(int px, int py) {_offset.x += sm(px); _offset.y += sm(py);}
float getLODstep() const {
float step = 0.01;
if (_scale <= 1000) {step = 0.1;}
if (_scale <= 500) {step = 0.5;}
if (_scale <= 100) {step = 1.0;}
if (_scale <= 50) {step = 5.0;}
if (_scale <= 10) {step = 10.0;}
if (_scale <= 1) {step = 100.0;}
return step;
}
/** get the currently visible map-region given the provided screen-size */
Rect getMapVisible(const int screenW, const int screenH) const {
Rect r;
r.x0 = xsm(0);
r.x1 = xsm(screenW);
r.y0 = ysm(screenH);
r.y1 = ysm(0);
return r;
}
/** get the currently visible map-region given the provided screen-size, SNAPED to the given grid-size */
Rect getMapVisible(const int screenW, const int screenH, const float mapGridSize) const {
Rect r = getMapVisible(screenW, screenH);
r.x0 = snapFloor(r.x0, mapGridSize);
r.y0 = snapFloor(r.y0, mapGridSize);
r.x1 = snapCeil(r.x1, mapGridSize);
r.y1 = snapCeil(r.y1, mapGridSize);
return r;
}
//Point2 getOffset() const {return _offset.xy();}
Point2 getCenter() const {return Point2(-_offset.x, _offset.y);}
void setScreenSize(const int w, const int h) {this->w = w; this->h = h;}
public:
static float snap(const float v, const float grid) { return std::round(v/grid)*grid; }
static Point2 snap(const Point2 p, const float grid) { return Point2(snap(p.x, grid), snap(p.y, grid)); }
static Point3 snap(const Point3 p, const float grid) { return Point3(snap(p.x, grid), snap(p.y, grid), snap(p.z, grid)); }
static float snapCeil(const float v, const float grid) { return std::ceil(v/grid) * grid; }
static float snapFloor(const float v, const float grid) { return std::floor(v/grid) * grid; }
//float snap(const float v) const { return v; }
};
#endif // SCALER_H

View File

@@ -0,0 +1,74 @@
#ifndef MV2DELEMENT_H
#define MV2DELEMENT_H
#include <QKeyEvent>
#include "../MapView2D.h"
#include "../Painter.h"
#include <Indoor/geo/BBox2.h>
#include <Indoor/geo/Line2.h>
/**
* represents one drawable, selectable, editable, ...
* element shown within the MapView2D
*/
class MV2DElement {
private:
bool _focused = false;
public:
/** dtor */
virtual ~MV2DElement() {;}
/** get the element's 2D bounding box */
virtual BBox2 getBoundingBox() const = 0;
/** get the element's minimal distance (nearest whatsoever) to the given point */
virtual float getMinDistanceXY(const Point2 p) const = 0;
/** repaint me */
virtual void paint(Painter& p) = 0;
/** got focus */
void focus() {
_focused = true;
onFocus();
}
/** lost focus */
void unfocus() {
_focused = false;
onUnfocus();
}
bool hasFocus() {return _focused;}
/** mouse pressed at the given point */
virtual void mousePressed(MapView2D* v, const Point2 p) = 0;
/** mouse moved to the given point */
virtual void mouseMove(MapView2D* v, const Point2 p) = 0;
/** mouse released */
virtual void mouseReleased(MapView2D* v, const Point2 p) = 0;
/** key pressed. return true when consumed. */
virtual bool keyPressEvent(MapView2D* v, QKeyEvent* e) = 0;
protected:
virtual void onFocus() = 0;
virtual void onUnfocus() = 0;
};
#endif // MV2DELEMENT_H

View File

@@ -0,0 +1,97 @@
#ifndef MV2DELEMENTACCESSPOINT_H
#define MV2DELEMENTACCESSPOINT_H
#include "MV2DElement.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementAccessPoint : public MV2DElement {
private:
bool sel = false;
Floorplan::AccessPoint* ap;
public:
/** ctor with the AP to render/edit */
MV2DElementAccessPoint(Floorplan::AccessPoint* ap) : ap(ap) {;}
/** get the element's 3D bounding box */
BBox2 getBoundingBox() const override {
BBox2 bbox;
bbox.add(Point2(ap->pos.x, ap->pos.y));
bbox.grow(Point2(0.1, 0.1));
return bbox;
}
/** get the element's minimal distance (nearest whatsoever) to the given point */
float getMinDistanceXY(const Point2 p) const override {
return p.getDistance(ap->pos.xy());
}
/** repaint me */
void paint(Painter& p) override {
if (sel) {
p.setPenBrush(Qt::black, CFG::SEL_COLOR);
p.drawCircle(ap->pos.xy());
} else if (hasFocus()) {
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawCircle(ap->pos.xy());
} else {
p.setPenBrush(Qt::gray, Qt::NoBrush);
p.drawCircle(ap->pos.xy());
}
// label
if (p.getScaler().getScale() >= 25) {
p.p->drawText(p.getScaler().xms(ap->pos.x) + 10, p.getScaler().yms(ap->pos.y) + 5, ap->mac.c_str());
}
}
/** mouse pressed at the given point */
virtual void mousePressed(MapView2D* v, const Point2 p) override {
(void) v;
(void) p;
}
/** mouse moved to the given point */
virtual void mouseMove(MapView2D* v, const Point2 _p) override {
(void) v;
if (sel) {
const Point2 p = Scaler::snap(_p, CFG::MOVE_SNAP_SIZE_M);
ap->pos.x = p.x;
ap->pos.y = p.y;
}
}
/** mouse released */
virtual void mouseReleased(MapView2D* v, const Point2 _p) override {
(void) v;
(void) _p;
sel = true;
}
virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override {
(void) v;
(void) e;
return false;
}
virtual void onFocus() override {
}
virtual void onUnfocus() override {
sel = false;
}
};
#endif // MV2DELEMENTACCESSPOINT_H

View File

@@ -0,0 +1,94 @@
#ifndef MV2DELEMENTBEACON_H
#define MV2DELEMENTBEACON_H
#include "MV2DElement.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementBeacon : public MV2DElement {
private:
bool sel = false;
Floorplan::Beacon* b;
public:
/** ctor with the Beacon to render/edit */
MV2DElementBeacon(Floorplan::Beacon* b) : b(b) {;}
/** get the element's 3D bounding box */
BBox2 getBoundingBox() const override {
BBox2 bbox;
bbox.add(Point2(b->pos.x, b->pos.y));
bbox.grow(Point2(0.1, 0.1));
return bbox;
}
/** get the element's minimal distance (nearest whatsoever) to the given point */
float getMinDistanceXY(const Point2 p) const override {
return p.getDistance(b->pos.xy());
}
/** repaint me */
void paint(Painter& p) override {
if (sel) {
p.setPenBrush(Qt::black, CFG::SEL_COLOR);
p.drawCircle(b->pos.xy());
} else if (hasFocus()) {
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawCircle(b->pos.xy());
} else {
p.setPenBrush(Qt::gray, Qt::NoBrush);
p.drawCircle(b->pos.xy());
}
// label
if (p.getScaler().getScale() >= 25) {
p.p->drawText(p.getScaler().xms(b->pos.x) + 10, p.getScaler().yms(b->pos.y) + 5, b->mac.c_str());
}
}
virtual void onFocus() override {
;
}
virtual void onUnfocus() override {
sel = false;
}
/** mouse pressed at the given point */
virtual void mousePressed(MapView2D* v, const Point2 p) override {
(void) v;
(void) p;
}
/** mouse moved to the given point */
virtual void mouseMove(MapView2D* v, const Point2 _p) override {
(void) v;
if (sel) {
const Point2 p = Scaler::snap(_p, CFG::MOVE_SNAP_SIZE_M);
b->pos.x = p.x;
b->pos.y = p.y;
}
}
/** mouse released */
virtual void mouseReleased(MapView2D* v, const Point2 p) override {
(void) v;
(void) p;
sel = true;
}
virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override {
(void) v;
(void) e;
return false;
}
};
#endif // MV2DELEMENTBEACON_H

View File

@@ -0,0 +1,108 @@
#ifndef MV2DELEMENTFLOOROBSTACLECIRCLE_H
#define MV2DELEMENTFLOOROBSTACLECIRCLE_H
#include "MV2DElement.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementFloorObstacleCircle : public MV2DElement {
private:
int selPoint = -1;
Floorplan::FloorObstacleCircle* c;
public:
/** ctor */
MV2DElementFloorObstacleCircle(Floorplan::FloorObstacleCircle* c) : c(c) {;}
/** get the element's 3D bounding box */
BBox2 getBoundingBox() const override {
BBox2 bbox;
bbox.add(c->center);
bbox.grow(Point2(c->radius, c->radius));
return bbox;
}
/** get the element's minimal distance (nearest whatsoever) to the given point */
float getMinDistanceXY(const Point2 p) const override {
return std::min(p.getDistance(getSelPoints()[0]), p.getDistance(getSelPoints()[1]));
}
/** repaint me */
void paint(Painter& p) override {
QPen pen = MapElementHelper::getPen(c->material, c->type, hasFocus());
p.setPenBrush(pen, Qt::NoBrush);
p.drawCircle(c->center, c->radius);
//QBrush brush = MapElementHelper::getBru(c->material, c->type, _focused);
// selected endpoints?
if (hasFocus()) {
p.setPenBrush(Qt::NoPen, CFG::SEL_COLOR);
if (selPoint == 0) {p.drawCircle(getSelPoints()[0]);}
if (selPoint == 1) {p.drawCircle(getSelPoints()[1]);}
}
// available endpoints
if (hasFocus()) {
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawCircle(getSelPoints()[0]);
p.drawCircle(getSelPoints()[1]);
}
}
std::vector<Point2> getSelPoints() const {
return {c->center, (c->center + Point2(c->radius,0))};
}
virtual void onFocus() override {
;
}
virtual void onUnfocus() override {
selPoint = -1;
}
/** mouse pressed at the given point */
virtual void mousePressed(MapView2D* v, const Point2 p) override {
(void) v;
(void) p;
}
/** mouse moved to the given point */
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);
if (selPoint == 0) {c->center = p;}
if (selPoint == 1) {c->radius = p.getDistance(c->center);}
}
/** mouse released */
virtual void mouseReleased(MapView2D* v, const Point2 _p) override {
const float t = v->getScaler().sm(CFG::SEL_THRESHOLD_SIZE_PX);
const float l1 = _p.getDistance(getSelPoints()[0]);
const float l2 = _p.getDistance(getSelPoints()[1]);
if (l1 < l2 && l1 <= t) {selPoint = 0;}
else if (l2 < l1 && l2 <= t) {selPoint = 1;}
else {selPoint = -1;}
}
virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override {
(void) v;
(void) e;
return false;
}
};
#endif // MV2DELEMENTFLOOROBSTACLECIRCLE_H

View File

@@ -0,0 +1,108 @@
#ifndef MV2DELEMENTFLOOROBSTACLELINE_H
#define MV2DELEMENTFLOOROBSTACLELINE_H
#include "MV2DElement.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementFloorObstacleLine : public MV2DElement {
private:
int selPoint = -1;
Floorplan::FloorObstacleLine* fo;
public:
/** ctor */
MV2DElementFloorObstacleLine(Floorplan::FloorObstacleLine* fo) : fo(fo) {;}
/** get the element's 3D bounding box */
BBox2 getBoundingBox() const override {
BBox2 bbox;
bbox.add(fo->from);
bbox.add(fo->to);
return bbox;
}
/** get the element's minimal distance (nearest whatsoever) to the given point */
float getMinDistanceXY(const Point2 p) const override {
return MapElementHelper::getLineDistanceXY(fo->from, fo->to, p);
}
/** repaint me */
void paint(Painter& p) override {
// selected endpoints?
if (hasFocus()) {
p.setPenBrush(Qt::NoPen, CFG::SEL_COLOR);
if (selPoint == 0) {p.drawCircle(fo->from);}
if (selPoint == 1) {p.drawCircle(fo->to);}
}
// line
p.setPenBrush(MapElementHelper::getPen(fo->material, fo->type, hasFocus()), Qt::NoBrush);
p.drawLine(fo->from, fo->to);
// available endpoints
if (hasFocus()) {
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawCircle(fo->from);
p.drawCircle(fo->to);
}
}
virtual void onFocus() override {
;
}
virtual void onUnfocus() override {
selPoint = -1; // clear selection
}
/** mouse pressed at the given point */
virtual void mousePressed(MapView2D* v, const Point2 p) override {
(void) v;
(void) p;
}
/** mouse moved to the given point */
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);
if (selPoint == 0) {fo->from.x = p.x; fo->from.y = p.y;}
if (selPoint == 1) {fo->to.x = p.x; fo->to.y = p.y;}
}
/** mouse released */
virtual void mouseReleased(MapView2D* v, const Point2 _p) override {
// (void) v;
// if (selPoint == -1) {return;}
// const Point3 p = Scaler::snap(_p, CFG::MOVE_SNAP_SIZE_M);
// if (selPoint == 0) {fo.from.x = p.x; fo.from.y = p.y;}
// if (selPoint == 1) {fo.to.x = p.x; fo.to.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);
const float l1 = _p.getDistance(fo->from);
const float l2 = _p.getDistance(fo->to);
if (l1 < l2 && l1 <= t) {selPoint = 0;}
else if (l2 < l1 && l2 <= t) {selPoint = 1;}
else {selPoint = -1;}
}
virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override {
(void) v;
(void) e;
return false;
}
};
#endif // MV2DELEMENTFLOOROBSTACLELINE_H

View File

@@ -0,0 +1,152 @@
#ifndef MV2DELEMENTFLOOROUTLINEPOLYGON_H
#define MV2DELEMENTFLOOROUTLINEPOLYGON_H
#include "MV2DElement.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
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

View File

@@ -0,0 +1,136 @@
#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;
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();
}
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 = abs(sx1-sx2);
float sh = abs(sy1-sy2);
bbox = BBox2();
bbox.add(Point2(mx1, my1));
bbox.add(Point2(mx2, my2));
p.p->drawImage(QRectF(sx1, sy1-sh, sw, sh), img, QRectF(0,0,img.width(),img.height()));
// 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 = Scaler::snap(_p, CFG::MOVE_SNAP_SIZE_M);
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;
(void) e;
return false;
}
};
#endif // MV2DELEMENTFLOORUNDERLAY_H

View File

@@ -0,0 +1,74 @@
#ifndef MAPELEMENTHELPER_H
#define MAPELEMENTHELPER_H
#include <Indoor/geo/Point2.h>
#include <Indoor/geo/Point3.h>
#include <Indoor/geo/Line2.h>
#include <QColor>
#include <QPen>
#include <QBrush>
#include <Indoor/floorplan/v2/Floorplan.h>
/** configuration */
namespace CFG {
const float MOVE_SNAP_SIZE_M = 0.1f; // in meter (= map-space)
const int SEL_THRESHOLD_SIZE_PX = 15; // in screen-pixels (-> should depend on the current zoom)
const QColor SEL_COLOR = Qt::blue;
}
/**
* contains some common helper-methods
*/
class MapElementHelper {
public:
/**
* get the minimal distance of dst to the line denoted by (p1, p2).
* this will generate line l perpendicular to (p1, p2)
* move l into dst
* and calculate the cut-point between l and (p1, p2)
*/
static float getLineDistanceXY(Point2 p1, Point2 p2, Point2 dst) {
// the line (p1, p2)
const Line2 line(p1, p2);
// 90 degree rotation L of the line (p1, p2)
const Point2 vec = (p1 - p2).perpendicular();
// the line L
const Line2 perb(dst-vec*100, dst+vec*100);
// calculate the cut betwen L and (p1,p2) (if any)
Point2 cut(0,0);
if (line.getSegmentIntersection(perb, cut)) {
// distance between cut-point and mouse
return cut.getDistance(dst);
} else {
// no cut detected
return 9999999;
}
}
static QPen getPen(Floorplan::Material mat, Floorplan::ObstacleType type, bool focus) {
using namespace Floorplan;
QPen pen; pen.setColor(Qt::darkGray);
if (focus) {pen.setColor(Qt::black);}
if (mat == Material::CONCRETE) {pen.setWidth(3);}
if (mat == Material::GLASS) {pen.setStyle(Qt::PenStyle::DotLine);}
if (type == ObstacleType::HANDRAIL) {pen.setStyle(Qt::PenStyle::DashLine);}
return pen;
}
};
#endif // MAPELEMENTHELPER_H

View File

@@ -0,0 +1,21 @@
#ifndef IHASATTRIBUTES_H
#define IHASATTRIBUTES_H
#include <string>
class IHasAttributes {
public:
/** set the value for the given key */
virtual void setAttribute(const std::string& key, const std::string& val) = 0;
/** get the value for the given key */
virtual const std::string& getAttribute(const std::string& key) const = 0;
/** get all attributes as map */
virtual const std::unordered_map<std::string, std::string> getAttributes() const = 0;
};
#endif // IHASATTRIBUTES_H

17
mapview/model/IHasFile.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef IHASFILE_H
#define IHASFILE_H
#include <string>
class IHasFile {
public:
virtual void setFileName(const std::string& file) = 0;
virtual const std::string& getFileName() const = 0;
};
#endif // IHASFILE_H

15
mapview/model/IHasMAC.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef IHASMAC_H
#define IHASMAC_H
#include <string>
class IHasMAC {
public:
virtual void setMAC(const std::string& mac) = 0;
virtual const std::string& getMAC() const = 0;
};
#endif // IHASMAC_H

View File

@@ -0,0 +1,15 @@
#ifndef IHASMATERIAL_H
#define IHASMATERIAL_H
#include <Indoor/floorplan/v2/Floorplan.h>
class IHasMaterial {
public:
virtual void setMaterial(const Floorplan::Material m) = 0;
virtual Floorplan::Material getMaterial() const = 0;
};
#endif // IHASMATERIAL_H

15
mapview/model/IHasName.h Normal file
View File

@@ -0,0 +1,15 @@
#ifndef IHASNAME_H
#define IHASNAME_H
#include <string>
class IHasName {
public:
virtual void setName(const std::string& name) = 0;
virtual const std::string& getName() const = 0;
};
#endif // IHASNAME_H

View File

@@ -0,0 +1,16 @@
#ifndef IHASOBSTACLETYPE_H
#define IHASOBSTACLETYPE_H
#include <Indoor/floorplan/v2/Floorplan.h>
class IHasObstacleType {
public:
virtual void setObstacleType(const Floorplan::ObstacleType t) = 0;
virtual Floorplan::ObstacleType getObatcleType() const = 0;
};
#endif // IHASOBSTACLETYPE_H

View File

@@ -0,0 +1,84 @@
#ifndef IHASPARAMS_H
#define IHASPARAMS_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include <QVariant>
enum class ParamType {
INT,
FLOAT,
STRING,
FILE,
};
class ParamValue {
private:
union {
int _int;
float _float;
};
std::string _str;
public:
template <typename T> ParamValue(const T val) {
setValue(val);
}
void setValue(const std::string& val) {_str = val;}
void setValue(float val) {_float = val;}
void setValue(int val) {_int = val;}
std::string toString() const {return _str;}
float toFloat() const {return _float;}
int toInt() const {return _int;}
};
//union ParamValue {
// int _int;
// float _float;
// std::string _string;
// template <typename T> ParamValue(const T val) {
// setValue(val);
// }
// int toInt() const {return _int;}
// float toFloat() const {return _float;}
// const std::string& toString() const {return _string;}
// void setValue(const float val) {_float = val;}
// void setValue(const int val) {_int = val;}
// void setValue(const std::string& val) {_string = val;}
//};
struct Param {
std::string name;
ParamType type;
Param(const std::string& name, const ParamType type) : name(name), type(type) {;}
};
/** free parameters */
class IHasParams {
public:
/** get the number of parameters */
virtual int getNumParams() const = 0;
/** get the description of the idx-th parameter */
virtual Param getParamDesc(const int idx) const = 0;
/** get the idx-th param's value */
virtual ParamValue getParamValue(const int idx) const = 0;
/** set the idx-th param's value */
virtual void setParamValue(const int idx, const ParamValue& val) const = 0;
};
#endif // IHASPARAMS_H

View File

@@ -0,0 +1,19 @@
#ifndef IHASPOSITION3D_H
#define IHASPOSITION3D_H
#include <Indoor/geo/Point3.h>
class IHasPosition3D {
public:
/** set the element's 3D position */
virtual void setPosition3D(const Point3& p) = 0;
/** get the element's 3D position */
virtual Point3 getPosition3D() const = 0;
};
#endif // IHASPOSITION3D_H

56
mapview/model/MMFloor.h Normal file
View File

@@ -0,0 +1,56 @@
#ifndef MMFLOOR_H
#define MMFLOOR_H
#include "MapLayer.h"
#include "MMFloorOutline.h"
#include "MMFloorObstacles.h"
#include "MMFloorAccessPoints.h"
#include "MMFloorBeacons.h"
#include "MMFloorUnderlay.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* floor-layer containing one floor
* and its outline, obstacles, access-points, ...
*/
class MMFloor : public MapLayer, public IHasName {
private:
/** the underlying data-structure */
Floorplan::Floor* floor;
public:
/** ctor. existing floor */
MMFloor(MapLayer* parent, Floorplan::Floor* floor) : MapLayer(parent, MapLayerType::FLOOR), floor(floor) {
new MMFloorOutline(this, floor);
new MMFloorObstacles(this, floor);
new MMFloorAccessPoints(this, floor);
new MMFloorBeacons(this, floor);
new MMFloorUnderlay(this, floor);
}
/** ctor. new floor. */
MMFloor(MapLayer* parent) : MapLayer(parent), floor(nullptr) {
throw "not yet implemented";
}
/** get the underlying model */
Floorplan::Floor& getFloor() {return *floor;}
std::string getLayerName() const override {return floor->name;}
virtual void setName(const std::string& name) {this->floor->name = name;}
virtual const std::string& getName() const {return this->floor->name;}
};
#endif // MMFLOOR_H

View File

@@ -0,0 +1,42 @@
#ifndef MAPVIEWELEMENTACCESSPOINT_H
#define MAPVIEWELEMENTACCESSPOINT_H
#include "MapModelElement.h"
#include "IHasMAC.h"
#include "IHasName.h"
#include "../elements/MV2DElementAccessPoint.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MMFloorAccessPoint : public MapModelElement, public IHasMAC, public IHasName {
private:
Floorplan::Floor* floor;
Floorplan::AccessPoint* ap;
MV2DElementAccessPoint mv2d;
public:
MMFloorAccessPoint(MapLayer* parent, Floorplan::Floor* floor, Floorplan::AccessPoint* ap) :
MapModelElement(parent), floor(floor), ap(ap), mv2d(ap) {
}
virtual void setMAC(const std::string& mac) override {ap->mac = mac;}
virtual const std::string& getMAC() const override {return ap->mac;}
virtual void setName(const std::string& name) override {ap->name = name;}
virtual const std::string& getName() const override {return ap->name;}
MV2DElement* getMV2D() const override {return (MV2DElement*) &mv2d;}
void deleteMe() const override {
parent->removeElement(this);
floor->accesspoints.erase(std::remove(floor->accesspoints.begin(), floor->accesspoints.end(), ap), floor->accesspoints.end());
}
};
#endif // MAPVIEWELEMENTACCESSPOINT_H

View File

@@ -0,0 +1,45 @@
#ifndef MMFLOORACCESSPOINTS_H
#define MMFLOORACCESSPOINTS_H
#include "MapLayer.h"
#include "MMFloorAccessPoint.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* layer containing all of the map's floors
*/
class MMFloorAccessPoints : public MapLayer {
private:
Floorplan::Floor* floor;
public:
/** ctor with the underlying model */
MMFloorAccessPoints(MapLayer* parent, Floorplan::Floor* floor) : MapLayer(parent, MapLayerType::FLOOR_ACCESS_POINTS), floor(floor) {
// add all APs
for (Floorplan::AccessPoint* ap : floor->accesspoints) {
new MMFloorAccessPoint(this, floor, ap);
}
}
std::string getLayerName() const override {return "APs";}
//TODO: check
void createAP(Floorplan::AccessPoint* ap) {
// add to underlying model
floor->accesspoints.push_back(ap);
// add to myself as element
elements.push_back(new MMFloorAccessPoint(this, floor, ap));
}
};
#endif // MMFLOORACCESSPOINTS_H

View File

@@ -0,0 +1,41 @@
#ifndef MAPVIEWELEMENTIBEACON_H
#define MAPVIEWELEMENTIBEACON_H
#include "MapModelElement.h"
#include "IHasMAC.h"
#include "IHasName.h"
#include "../elements/MV2DElementBeacon.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MMFloorBeacon : public MapModelElement, public IHasMAC, public IHasName {
private:
Floorplan::Floor* floor;
Floorplan::Beacon* b;
MV2DElementBeacon mv2d;
public:
MMFloorBeacon(MapLayer* parent, Floorplan::Floor* floor, Floorplan::Beacon* b) : MapModelElement(parent), floor(floor), b(b), mv2d(b) {
}
virtual void setMAC(const std::string& mac) override {b->mac = mac;}
virtual const std::string& getMAC() const override {return b->mac;}
virtual void setName(const std::string& name) override {b->name = name;}
virtual const std::string& getName() const override {return b->name;}
MV2DElement* getMV2D() const override {return (MV2DElement*) &mv2d;}
void deleteMe() const override {
parent->removeElement(this);
floor->beacons.erase(std::remove(floor->beacons.begin(), floor->beacons.end(), b), floor->beacons.end());
}
};
#endif // MAPVIEWELEMENTIBEACON_H

View File

@@ -0,0 +1,44 @@
#ifndef MMFLOORBEACONS_H
#define MMFLOORBEACONS_H
#include "MapLayer.h"
#include "MMFloorBeacon.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* layer containing all of the floor's beaconss
*/
class MMFloorBeacons : public MapLayer {
private:
Floorplan::Floor* floor;
public:
/** ctor with the underlying model */
MMFloorBeacons(MapLayer* parent, Floorplan::Floor* floor) : MapLayer(parent, MapLayerType::FLOOR_BEACONS), floor(floor) {
// add all Beacons
for (Floorplan::Beacon* b : floor->beacons) {
new MMFloorBeacon(this, floor, b);
}
}
std::string getLayerName() const override {return "Beacons";}
//TODO: check
void createBeacon(Floorplan::Beacon* b) {
// add to underlying model
floor->beacons.push_back(b);
// add to myself as element
elements.push_back(new MMFloorBeacon(this, floor, b));
}
};
#endif // MMFLOORBEACONS_H

View File

@@ -0,0 +1,46 @@
#ifndef MAPMODELELEMENTFLOOROBSTACLECIRCLE_H
#define MAPMODELELEMENTFLOOROBSTACLECIRCLE_H
#include "MapModelElement.h"
#include "../elements/MapViewElementHelper.h"
#include "IHasMaterial.h"
#include "IHasObstacleType.h"
#include "../elements/MV2DElementFloorObstacleCircle.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MMFloorObstacleCircle : public MapModelElement, public IHasMaterial, public IHasObstacleType {
private:
Floorplan::Floor* mf;
Floorplan::FloorObstacleCircle* c;
MV2DElementFloorObstacleCircle mv2d;
public:
MMFloorObstacleCircle(MapLayer* parent, Floorplan::Floor* mf, Floorplan::FloorObstacleCircle* c) :
MapModelElement(parent), mf(mf), c(c), mv2d(c) {
}
void setMaterial(const Floorplan::Material m) override {c->material = m;}
Floorplan::Material getMaterial() const override {return c->material;}
void setObstacleType(const Floorplan::ObstacleType t) override {c->type = t;}
Floorplan::ObstacleType getObatcleType() const override {return c->type;}
MV2DElement* getMV2D() const override {return (MV2DElement*) &mv2d;}
void deleteMe() const override {
parent->removeElement(this);
mf->obstacles.erase(std::remove(mf->obstacles.begin(), mf->obstacles.end(), c), mf->obstacles.end());
}
};
#endif // MAPMODELELEMENTFLOOROBSTACLECIRCLE_H

View File

@@ -0,0 +1,45 @@
#ifndef MAPELEMENTOBSTACLE_H
#define MAPELEMENTOBSTACLE_H
#include "MapModelElement.h"
#include "../elements/MapViewElementHelper.h"
#include "IHasMaterial.h"
#include "IHasObstacleType.h"
#include "../elements/MV2DElementFloorObstacleLine.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MMFloorObstacleLine : public MapModelElement, public IHasMaterial, public IHasObstacleType {
public:
Floorplan::Floor* mf;
Floorplan::FloorObstacleLine* fo;
MV2DElementFloorObstacleLine mv2d;
public:
MMFloorObstacleLine(MapLayer* parent, Floorplan::Floor* mf, Floorplan::FloorObstacleLine* fo) :
MapModelElement(parent), mf(mf), fo(fo), mv2d(fo) {
}
void setMaterial(const Floorplan::Material m) override {fo->material = m;}
Floorplan::Material getMaterial() const override {return fo->material;}
void setObstacleType(const Floorplan::ObstacleType t) override {fo->type = t;}
Floorplan::ObstacleType getObatcleType() const override {return fo->type;}
MV2DElement* getMV2D() const override {return (MV2DElement*) &mv2d;}
void deleteMe() const override {
parent->removeElement(this);
mf->obstacles.erase(std::remove(mf->obstacles.begin(), mf->obstacles.end(), fo), mf->obstacles.end());
}
};
#endif // MAPELEMENTOBSTACLE_H

View File

@@ -0,0 +1,63 @@
#ifndef MMFLOOROBSTACLES_H
#define MMFLOOROBSTACLES_H
#include "MapLayer.h"
#include "MMFloorObstacleCircle.h"
#include "MMFloorObstacleLine.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* layer that contains all of one floor's obstacles
*/
class MMFloorObstacles : public MapLayer {
Floorplan::Floor* floor;
public:
/** ctor with the floor */
MMFloorObstacles(MapLayer* parent, Floorplan::Floor* floor) : MapLayer(parent, MapLayerType::FLOOR_OBSTACLES), floor(floor) {
// the obstacles
for (Floorplan::FloorObstacle* o : floor->obstacles) {
if (dynamic_cast<Floorplan::FloorObstacleLine*>(o)) {
elements.push_back(new MMFloorObstacleLine(this, floor, (Floorplan::FloorObstacleLine*)o));
} else if (dynamic_cast<Floorplan::FloorObstacleCircle*>(o)) {
elements.push_back(new MMFloorObstacleCircle(this, floor, (Floorplan::FloorObstacleCircle*)o));
}
}
}
/** get the corresponding floor from the underlying model */
Floorplan::Floor* getFloor() {return floor;}
//TODO: check
void createLine(Floorplan::FloorObstacleLine* obs) {
// add to underlying model
floor->obstacles.push_back(obs);
// add to myself as element
elements.push_back(new MMFloorObstacleLine(this, floor, obs));
}
//TODO: check
void createCircle(Floorplan::FloorObstacleCircle* obs) {
// add to underlying model
floor->obstacles.push_back(obs);
// add to myself as element
elements.push_back(new MMFloorObstacleCircle(this, floor, obs));
}
std::string getLayerName() const override {return "obstacles";}
};
#endif // MMFLOOROBSTACLES_H

View File

@@ -0,0 +1,52 @@
#ifndef MMFLOOROUTLINE_H
#define MMFLOOROUTLINE_H
#include "MapLayer.h"
#include "MMFloorOutlinePolygon.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* layer containing all elements describing a floor's outline
*/
class MMFloorOutline : public MapLayer {
private:
/** the underlying model */
Floorplan::Floor* floor;
public:
/** ctor with the underlying model */
MMFloorOutline(MapLayer* parent, Floorplan::Floor* floor) : MapLayer(parent, MapLayerType::FLOOR_GROUND), floor(floor) {
// the outline
for (Floorplan::FloorOutlinePolygon* poly : floor->outline) {
elements.push_back(new MMFloorOutlinePolygon(this, floor, poly));
}
}
/** get the corresponding floor from the underlying model */
Floorplan::Floor* getFloor() {return floor;}
//TODO: check
void create(Floorplan::FloorOutlinePolygon* poly) {
// add to underlying model
floor->outline.push_back(poly);
// add to myself as element
elements.push_back(new MMFloorOutlinePolygon(this, floor, poly));
}
std::string getLayerName() const override {return "outline";}
};
#endif // MMFLOOROUTLINE_H

View File

@@ -0,0 +1,53 @@
#ifndef MAPELEMENTFLOORGROUND_H
#define MAPELEMENTFLOORGROUND_H
#include "IHasName.h"
#include "MapModelElement.h"
#include "../elements/MV2DElementFloorOutlinePolygon.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* describes one polygon within a floor's outline
*/
class MMFloorOutlinePolygon : public MapModelElement, public IHasName {
private:
Floorplan::Floor* mf;
Floorplan::FloorOutlinePolygon* fo;
MV2DElementFloorOutlinePolygon mv2d;
public:
/** ctor */
MMFloorOutlinePolygon(MapLayer* parent, Floorplan::Floor* mf, Floorplan::FloorOutlinePolygon* fo) : MapModelElement(parent), mf(mf), fo(fo), mv2d(*fo) {
;
}
Floorplan::FloorOutlinePolygon* getPolygon() {return fo;}
Floorplan::OutlineMethod getMethod() const {return fo->method;}
void setMethod(const Floorplan::OutlineMethod m) {this->fo->method = m;}
void setName(const std::string& name) override {fo->name = name;}
const std::string& getName() const override {return fo->name;}
MV2DElement* getMV2D() const override {return (MV2DElement*) &mv2d;}
void deleteMe() const override {
// delete from the parent
parent->removeElement(this);
// delete from the underlying model
mf->outline.erase(std::remove(mf->outline.begin(), mf->outline.end(), fo), mf->outline.end());
}
};
#endif // MAPELEMENTFLOORGROUND_H

View File

@@ -0,0 +1,52 @@
#ifndef MMFLOORUNDERLAY_H
#define MMFLOORUNDERLAY_H
#include "MMFloorUnderlayImage.h"
#include "../elements/MV2DElementFloorUnderlay.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* add an external file as underlay (to copy it onto the map)
*/
class MMFloorUnderlay : public MapLayer {
private:
Floorplan::Floor* floor;
public:
/** ctor */
MMFloorUnderlay(MapLayer* parent, Floorplan::Floor* floor) : MapLayer(parent, MapLayerType::FLOOR_UNDERLAY), floor(floor) {
// the underlays
for (Floorplan::UnderlayImage* img : floor->underlays) {
elements.push_back(new MMFloorUnderlayImage(this, floor, img));
}
}
//TODO: check
void createImage(const Point2 center) {
Floorplan::UnderlayImage* elem = new Floorplan::UnderlayImage();
// add to underlying model
floor->underlays.push_back(elem);
// add to myself as element
MMFloorUnderlayImage* img = new MMFloorUnderlayImage(this, floor, elem);
elements.push_back(img);
img->setAnchor(center);
img->setScale(0.1, 0.1);
}
virtual std::string getLayerName() const override {return "underlay";}
};
#endif // MMFLOORUNDERLAY_H

View File

@@ -0,0 +1,78 @@
#ifndef MMFLOORUNDERLAYIMAGE_H
#define MMFLOORUNDERLAYIMAGE_H
#include "IHasFile.h"
#include "IHasParams.h"
#include "MapModelElement.h"
#include "../elements/MV2DElementFloorUnderlay.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* add an external image file as underlay (to copy it onto the map)
*/
class MMFloorUnderlayImage : public MapModelElement, public MapLayer, public IHasFile, public IHasParams {
private:
Floorplan::Floor* floor;
Floorplan::UnderlayImage* img;
MV2DElementFloorUnderlay mv2d;
std::string fileName;
public:
/** ctor */
MMFloorUnderlayImage(MapLayer* parent, Floorplan::Floor* floor, Floorplan::UnderlayImage* img) : MapModelElement(parent), MapLayer(parent, MapLayerType::FLOOR_UNDERLAY), floor(floor), img(img), mv2d(img) {
setFileName(img->filename);
}
virtual void setFileName(const std::string& file) {img->filename = file;}
virtual const std::string& getFileName() const {return img->filename;}
void setAnchor(const Point2 anchor) {img->anchor = anchor;}
Point2 getAnchor() const {return img->anchor;}
void setScale(const float x, const float y) {img->scaleX = x; img->scaleY = y;}
virtual std::string getLayerName() const override {return "underlay";}
MV2DElement* getMV2D() const override {return (MV2DElement*) &mv2d;}
void deleteMe() const override {
;
}
int getNumParams() const override {return 3;}
virtual Param getParamDesc(const int idx) const override {
switch (idx) {
case 0: return Param("file", ParamType::FILE);
case 1: return Param("scale X", ParamType::FLOAT);
case 2: return Param("scale Y", ParamType::FLOAT);
default: throw 1;
}
}
virtual ParamValue getParamValue(const int idx) const override {
switch(idx) {
case 0: return ParamValue(img->filename);
case 1: return ParamValue(img->scaleX);
case 2: return ParamValue(img->scaleY);
default: throw 1;
}
}
virtual void setParamValue(const int idx, const ParamValue& val) const override {
switch (idx) {
case 0: img->filename = val.toString();
case 1: img->scaleX = val.toFloat();
case 2: img->scaleY = val.toFloat();
default: throw 1;
}
}
};
#endif // MMFLOORUNDERLAYIMAGE_H

37
mapview/model/MMFloors.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef MMFLOORS_H
#define MMFLOORS_H
#include "MapLayer.h"
#include "MMFloor.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* layer containing all of the map's floors
*/
class MMFloors : public MapLayer {
private:
Floorplan::IndoorMap* map;
public:
/** ctor with the underlying model */
MMFloors(MapLayer* parent, Floorplan::IndoorMap* map) : MapLayer(parent, MapLayerType::FLOORS), map(map) {
// add all floors
for (Floorplan::Floor* floor : map->floors) {
new MMFloor(this, floor);
}
}
std::string getLayerName() const override {return "floors";}
/** get the underlying model */
Floorplan::IndoorMap* getMap() {return map;}
};
#endif // MMFLOORS_H

38
mapview/model/MMRoot.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef MMROOT_H
#define MMROOT_H
#include "MapLayer.h"
#include "MMFloors.h"
#include <Indoor/floorplan/v2/Floorplan.h>
/**
* floor-layer containing one floor
* and its outline, obstacles, access-points, ...
*/
class MMRoot : public MapLayer {
private:
/** the underlying data-structure */
Floorplan::IndoorMap* map;
public:
/** ctor. existing floor */
MMRoot(MapLayer* parent, Floorplan::IndoorMap* map) : MapLayer(parent), map(map) {
// all floors
new MMFloors(this, map);
}
/** get the underlying model */
Floorplan::IndoorMap* getMap() {return map;}
std::string getLayerName() const override {return "root";}
};
#endif // MMROOT_H

127
mapview/model/MapLayer.h Normal file
View File

@@ -0,0 +1,127 @@
#ifndef MAPLAYER_H
#define MAPLAYER_H
#include <string>
#include <vector>
#include <algorithm>
class MapModelElement;
enum class MapLayerType {
UNKNOWN,
ROOT,
FLOORS,
FLOOR,
FLOOR_GROUND,
FLOOR_OBSTACLES,
FLOOR_BEACONS,
FLOOR_ACCESS_POINTS,
FLOOR_UNDERLAY,
};
class MapLayer {
protected:
/** this layer's parent */
MapLayer* parent;
/** this layer's elements */
std::vector<MapModelElement*> elements;
/** this layer's sublayers */
std::vector<MapLayer*> sublayers;
/** this layer's type */
MapLayerType type;
/** whether this layer is visible */
bool visible;
public:
/** ctor */
MapLayer(MapLayer* parent) : parent(parent), type(MapLayerType::UNKNOWN), visible(true) {
if (parent) {parent->addSublayer(this);} // attach myself as child of my parent
}
/** ctor */
MapLayer(MapLayer* parent, MapLayerType type) : parent(parent), type(type), visible(true) {
if (parent) {parent->addSublayer(this);} // attach myself as child of my parent
}
/** dtor */
virtual ~MapLayer() {;}
/** get the layer's parent */
MapLayer* getParent() const {return parent;}
/** get the layer's name */
virtual std::string getLayerName() const = 0;
/** get the layer's type */
MapLayerType getLayerType() const {return type;}
/** get all elements within this layer */
const std::vector<MapModelElement*>& getElements() const {return elements;}
/** get all elements within this layer */
size_t getNumElements() const {return elements.size();}
/** remove the given element from the elements list */
void removeElement(const MapModelElement* elem) { elements.erase(std::remove(elements.begin(), elements.end(), elem), elements.end()); }
/** is this layer currently visible? */
bool isVisible() const {return visible;}
/** make this layer visible */
void setVisible(const bool visible) {this->visible = visible;}
/** get all sub-layers within this layer */
const std::vector<MapLayer*>& getSubLayers() const {return sublayers;}
/** helper method to get all elements and those of all sub-layers */
void getVisibleElementsRecursive(std::vector<MapModelElement*>& el) {
if (isVisible()) {
std::vector<MapModelElement*> local = getElements();
el.insert(el.end(), local.begin(), local.end());
for (MapLayer* sub : getSubLayers()) {
sub->getVisibleElementsRecursive(el);
}
}
}
protected:
/** add a new sublayer to this layer */
void addSublayer(MapLayer* ml) {
// sanity check before adding
if (std::find(sublayers.begin(), sublayers.end(), ml) != sublayers.end()) {throw "layer already present!";}
sublayers.push_back(ml);
}
};
class MapLayerRoot : public MapLayer {
public:
MapLayerRoot(MapLayer* parent) : MapLayer(parent, MapLayerType::ROOT) {;}
std::string getLayerName() const override {return "root";}
};
#endif // MAPLAYER_H

72
mapview/model/MapLayers.h Normal file
View File

@@ -0,0 +1,72 @@
#ifndef MAPLAYERFLOOR_H
#define MAPLAYERFLOOR_H
#include "MapLayer.h"
#include <Indoor/floorplan/v2/Floorplan.h>
#include "../model/MMFloorObstacleLine.h"
#include "../model/MMFloorObstacleCircle.h"
#include "../model/MMFloorOutlinePolygon.h"
#include "../model/MMFloorBeacon.h"
/*
class MapLayerFloorOutlineAdd : public TypedMapLayer {
private:
Floorplan::Floor& floor;
public:
MapLayerFloorOutlineAdd(MapLayer* parent, Floorplan::Floor& floor) : TypedMapLayer(parent, MapLayerType::FLOOR_GROUND_ADD), floor(floor) {;}
std::string getLayerName() const override {return "add";}
Floorplan::Floor& getFloor() {return floor;}
std::vector<MapModelElement*> getElements() const override {
std::vector<MapModelElement*> vec;
for (Floorplan::FloorOutlinePolygon& p : floor.outline.add) {vec.push_back(new MapViewElementFloorOutlinePolygon(floor, p, MapViewElementFloorOutlinePolygon::Type::ADD));}
return vec;
}
void create(const Floorplan::FloorOutlinePolygon& poly) {
floor.outline.add.push_back(poly);
}
virtual size_t getNumElements() const override {return floor.outline.add.size();}
};
class MapLayerFloorOutlineRemove : public TypedMapLayer {
private:
Floorplan::Floor& floor;
public:
MapLayerFloorOutlineRemove(MapLayer* parent, Floorplan::Floor& floor) : TypedMapLayer(parent, MapLayerType::FLOOR_GROUND_REMOVE), floor(floor) {;}
std::string getLayerName() const override {return "remove";}
Floorplan::Floor& getFloor() {return floor;}
std::vector<MapModelElement*> getElements() const override {
std::vector<MapModelElement*> vec;
for (Floorplan::FloorOutlinePolygon& p : floor.outline.remove) {vec.push_back(new MapViewElementFloorOutlinePolygon(floor, p, MapViewElementFloorOutlinePolygon::Type::REMOVE));}
return vec;
}
void create(const Floorplan::FloorOutlinePolygon& poly) {
floor.outline.remove.push_back(poly);
}
virtual size_t getNumElements() const override {return floor.outline.remove.size();}
};
class MapLayerFloorOutlinePolygon : public TypedMapLayer {
private:
Floorplan::Floor& floor;
public:
MapLayerFloorOutlinePolygon(MapLayer* parent, Floorplan::Floor& floor) : TypedMapLayer(parent, MapLayerType::FLOOR_GROUND), floor(floor) {
new MapLayerFloorOutlineAdd(this, floor);
new MapLayerFloorOutlineRemove(this, floor);
}
std::string getLayerName() const override {return "ground";}
Floorplan::Floor& getFloor() {return floor;}
};
*/
#endif // MAPLAYERFLOOR_H

View File

112
mapview/model/MapModel.h Normal file
View File

@@ -0,0 +1,112 @@
#ifndef MAPMODEL_H
#define MAPMODEL_H
#include <QObject>
#include "MapLayer.h"
#include "MapModelElement.h"
#include "MMRoot.h"
#include <Indoor/floorplan/v2/Floorplan.h>
#include <Indoor/floorplan/v2/FloorplanReader.h>
#include <Indoor/floorplan/v2/FloorplanWriter.h>
class MapModel : public QObject {
Q_OBJECT
private:
///** wrapper-classes for all elements */
//std::vector<MapModelElement*> selElements;
/** the map's root-layer containing all other layers */
MapLayer* root = nullptr;
/** the currently selected layer (if any) */
MapLayer* selLayer = nullptr;
/** the loaded floorplan */
Floorplan::IndoorMap* im;
public:
/** ctor */
MapModel() {
root = new MapLayerRoot(nullptr);
}
virtual ~MapModel() {
cleanup();
}
void cleanup() {
selLayer = nullptr;
//selElements.clear();
if (root) {delete root; root = nullptr;}
}
void load(const std::string& file) {
emit aboutToReset();
cleanup();
// load the indoor-map using the given XML-file
im = Floorplan::Reader::readFromFile(file);
root = new MMRoot(nullptr, im);
emit reset();
}
void save(const std::string& file) {
Floorplan::Writer::writeToFile(im, file);
}
/** get the map's root-layer containing all other layers */
MapLayer* getRootLayer() { return root; }
/** get all elements within the currently selected layer */
std::vector<MapModelElement*> getSelectedLayerElements() {
//return selElements;
//return (selLayer) ? (selLayer->getElementsRecursive()) : (std::vector<MapModelElement*>());
std::vector<MapModelElement*> elements;
root->getVisibleElementsRecursive(elements);
return elements;
}
/** get all currently visible elements */
std::vector<MapModelElement*> getVisibleElements() {
return getSelectedLayerElements();
}
/** set the currently selected layer */
void setSelectedLayer(MapLayer* ml) {
//selElements.clear();
//for (MapModelElement* el : ml->getElementsRecursive()) {selElements.push_back(el);}
selLayer = ml;
}
/** get the currently selected layer */
MapLayer* getSelectedLayer() const {
return selLayer;
}
void reselect() {
setSelectedLayer(selLayer);
emit reset();
}
signals:
void aboutToReset();
void reset();
};
#endif // MAPMODEL_H

View File

@@ -0,0 +1,34 @@
#ifndef MAPMODELELEMENT_H
#define MAPMODELELEMENT_H
#include "MapLayer.h"
class MV2DElement;
class MapModelElement {
protected:
MapLayer* parent;
public:
/** ctor */
MapModelElement(MapLayer* parent) : parent(parent) {;}
/** dtor */
virtual ~MapModelElement() {;}
/** get the 2D interaction class for this element */
virtual MV2DElement* getMV2D() const = 0;
/** delete this element from the model */
virtual void deleteMe() const = 0;
/** get the parent element */
MapLayer* getParent() const {return parent;}
};
#endif // MAPMODELELEMENT_H

0
mapview/tools/Tool.cpp Normal file
View File

35
mapview/tools/Tool.h Normal file
View File

@@ -0,0 +1,35 @@
#ifndef TOOL_H
#define TOOL_H
#include <QKeyEvent>
#include <QMouseEvent>
#include <QObject>
#include "../Painter.h"
class MapView2D;
class Tool : public QObject {
Q_OBJECT
public:
virtual ~Tool() {;}
virtual void mousePressEvent(MapView2D* m, QMouseEvent* e) { (void) m; (void) e; }
virtual void mouseMoveEvent(MapView2D* m, QMouseEvent* e) { (void) m; (void) e; }
virtual void mouseReleaseEvent(MapView2D* m, QMouseEvent* e) { (void) m; (void) e; }
virtual void wheelEvent(MapView2D* m, QWheelEvent* e) { (void) m; (void) e; }
virtual void keyPressEvent(MapView2D* m, QKeyEvent* e) { (void) m; (void) e; }
virtual void paintBefore(MapView2D* m, Painter& p) { (void) m; (void) p; }
virtual void paintAfter(MapView2D* m, Painter& p) { (void) m; (void) p; }
virtual void layerChange(MapView2D* m) { (void) m; }
};
#endif // TOOL_H

View File

@@ -0,0 +1,71 @@
#ifndef TOOLMAPGRID_H
#define TOOLMAPGRID_H
#include "Tool.h"
class ToolMapGrid : public Tool {
public:
void paintBefore(MapView2D* m, Painter& p) override {
(void) m;
static const QColor cB(250,250,250);
static const QColor cN(235,235,235);
static const QColor c0(128,128,128);
int w = p.width();
int h = p.height();
// grid-size
const float step = p.getScaler().getLODstep();
const float sStep = step/5;
// map-region visible on the screen
const Rect r = p.getScaler().getMapVisible(w, h, step);
// x-lines
for (float x = r.x0; x < r.x1; x += step) {
// major-lines (without center)
if (std::abs(x) > 0.001) {
p.setPenBrush(cN, Qt::NoBrush);
p.drawLine(x, r.y0, x, r.y1);
}
// minor-lines
p.setPenBrush(cB, Qt::NoBrush);
for (float x1 = x+sStep; x1 < x+step; x1 += sStep) {
p.drawLine(x1, r.y0, x1, r.y1);
}
}
// y-lines
for (float y = r.y0; y < r.y1; y += step) {
// major-lines (without center)
if (std::abs(y) > 0.001) {
p.setPenBrush(cN, Qt::NoBrush);
p.drawLine(r.x0, y, r.x1, y);
}
// minor-lines
p.setPenBrush(cB, Qt::NoBrush);
for (float y1 = y+sStep; y1 < y+step; y1 += sStep) {
p.drawLine(r.x0, y1, r.x1, y1);
}
}
// thick center lines
p.setPenBrush(c0, Qt::NoBrush);
p.drawLine(0, r.y0, 0, r.y1);
p.drawLine(r.x0, 0, r.x1, 0);
}
};
#endif // TOOLMAPGRID_H

View File

@@ -0,0 +1,28 @@
#ifndef TOOLMAPZOOM_H
#define TOOLMAPZOOM_H
#include "Tool.h"
#include "../MapView2D.h"
class ToolMapZoom : public Tool {
public:
virtual void wheelEvent(MapView2D* m, QWheelEvent* e) override {
Scaler& s = m->getScaler();
if (e->delta() < 0) {
s.setScale(s.getScale() * 0.5);
} else {
s.setScale(s.getScale() / 0.5);
}
if (s.getScale() > 1000) {s.setScale(1000);}
if (s.getScale() < 5) {s.setScale(5);}
}
};
#endif // TOOLMAPZOOM_H

View File

@@ -0,0 +1,49 @@
#ifndef TOOLMOVEMAP_H
#define TOOLMOVEMAP_H
#include "Tool.h"
#include "../MapView2D.h"
/**
*
*/
class ToolMoveMap : public Tool {
private:
bool mouseIsDown = false;
Point3 startOffset;
int sx;
int sy;
virtual void mousePressEvent(MapView2D* m, QMouseEvent* e) override {
if (e->button() == Qt::MouseButton::MidButton) {
mouseIsDown = true;
this->sx = e->x();
this->sy = e->y();
this->startOffset = m->getScaler().getOffset();
}
}
virtual void mouseMoveEvent(MapView2D* m, QMouseEvent* e) override {
if (!mouseIsDown) {return;}
m->getScaler().setOffset(startOffset);
m->getScaler().addOffset(e->x()-sx, e->y()-sy);
}
virtual void mouseReleaseEvent(MapView2D* m, QMouseEvent* e) override {
(void) m;
(void) e;
mouseIsDown = false;
}
virtual void keyPressEvent(MapView2D* m, QKeyEvent* e) override {
(void) m;
(void) e;
// TODO: move on arrow keys?
}
};
#endif // TOOLMOVEMAP_H

140
mapview/tools/ToolRuler.h Normal file
View File

@@ -0,0 +1,140 @@
#ifndef TOOLRULER_H
#define TOOLRULER_H
#include "Tool.h"
class ToolRuler : public Tool {
private:
int mouseX;
int mouseY;
const bool fullSize = true;
const int rs = 40; // ruler size
const int tsMajor = 20; // major-tick size
const int tsMinor = 5; // minor-tick size
public:
virtual void mouseMoveEvent(MapView2D* m, QMouseEvent* e) override {
(void) m;
this->mouseX = e->x();
this->mouseY = e->y();
}
virtual void paintBefore(MapView2D* m, Painter& p) override {
(void) m;
// mouse-indicator within the image?
if (fullSize) {
const int w = p.width();
const int h = p.height();
p.setPenBrush(Qt::lightGray, Qt::NoBrush);
p.p->drawLine(rs, mouseY, w, mouseY);
p.p->drawLine(mouseX, rs, mouseX, h);
}
}
virtual void paintAfter(MapView2D* m, Painter& p) override {
(void) m;
static const QColor c1(240,240,240);
static const QColor c2(200,200,200);
const int w = p.width();
const int h = p.height();
// ruler step-size depending on the current zoom level
const float step = p.getScaler().getLODstep();
const float sStep = step / 10.0f;
// the visible map-rect
const Rect r = p.getScaler().getMapVisible(w, h, step);
QRect rx(rs,0,w-1-rs,rs);
QRect ry(0,rs,rs,h-1-rs);
// background
{
// samller font
QFont f = p.p->font(); f.setPointSize(8);
p.p->setFont(f);
// outline
p.setPen(Qt::darkGray);
// x-axis
QLinearGradient gx(0,0,0,rs); gx.setColorAt(0, c1); gx.setColorAt(1, c2); p.setBrush(gx);
p.p->drawRect(rx);
// y-axis
QLinearGradient gy(0,0,rs,0); gy.setColorAt(0, c2); gy.setColorAt(1, c1); p.setBrush(gy);
p.p->drawRect(ry);
}
// mouse-indicator
p.setPenBrush(Qt::darkGray, Qt::NoBrush);
p.p->drawLine(0, mouseY, rs, mouseY);
p.p->drawLine(mouseX, 0, mouseX, rs);
p.setPenBrush(Qt::black, Qt::NoBrush);
char buf[128];
// y-axis
p.p->setClipRect(ry);
for (float y = r.y0; y <= r.y1; y += step) {
// major-lines
const float yMajor = p.s.yms(y);
//if (yMajor < 0 || yMajor > h) {continue;} // stop at the end
p.p->drawLine(0,yMajor, tsMajor,yMajor);
// minor-lines
for (float y1 = y+sStep; y1 < y+step; y1 += sStep) {
const float yMinor = p.s.yms(y1);
p.p->drawLine(0,yMinor, tsMinor,yMinor);
}
// text-label
std::sprintf(buf, "%.1f", y);
p.p->drawText(6, yMajor-2, buf);
}
// x-axis
p.p->setClipRect(rx);
for (float x = r.x0; x <= r.x1; x += step) {
// major-lines
const float xMajor = p.s.xms(x);
//if (xMajor < 0 || xMajor > w) {continue;} // stop at the end
p.p->drawLine(xMajor,0, xMajor,tsMajor);
// minor-lines
for (float x1 = x+sStep; x1 < x+step; x1 += sStep) {
const float xMinor = p.s.xms(x1);
p.p->drawLine(xMinor,0, xMinor,tsMinor);
}
// text-label
std::sprintf(buf, "%.1f", x);
p.p->drawText(xMajor+2, 18, buf);
}
p.p->setClipping(false);
}
};
#endif // TOOLRULER_H

View File

View File

@@ -0,0 +1,163 @@
#ifndef TOOLSELECTOR_H
#define TOOLSELECTOR_H
#include "Tool.h"
#include "../model/MapModelElement.h"
#include "../MapView2D.h"
#include "../model/MapModel.h"
class ToolSelector : public Tool {
Q_OBJECT
private:
/** the currently focused MapElement (if any) */
MapModelElement* focused = nullptr;
/** whether the mouse-button is currently pressed */
bool mouseIsDown = false;
public:
virtual ~ToolSelector() {;}
virtual void mousePressEvent(MapView2D* m, QMouseEvent* e) override {
if (e->button() != Qt::MouseButton::LeftButton) {return;}
mouseIsDown = true;
const Scaler& s = m->getScaler();
Point2 p2(s.xsm(e->x()), s.ysm(e->y()));
//Point3 p3(s.xsm(e->x()), s.ysm(e->y()), 0);
const float g = m->getScaler().sm(10); // increase each BBox by 10 px (needed mainly for hor/ver lines)
// get all elements with bounding-box matchings
std::vector<MapModelElement*> possible;
for (MapModelElement* el : m->getModel()->getSelectedLayerElements()) {
BBox2 bbox = el->getMV2D()->getBoundingBox(); // elements 3D bbox
bbox.grow(Point2(g, g)); // grow a little (needed for straight lines)
if (bbox.contains(p2)) {possible.push_back(el);} // intersection?
}
// among those, find the best-matching one (smallest distance to an intersection)
auto lambda = [&] (const MapModelElement* el1, const MapModelElement* el2) {return el1->getMV2D()->getMinDistanceXY(p2) < el2->getMV2D()->getMinDistanceXY(p2);};
auto it = std::min_element(possible.begin(), possible.end(), lambda);
MapModelElement* el = (it == possible.end()) ? (nullptr) : (*it);
// focus changed? -> unfocus the old one (if any)
if (setFocused(el)) {
;
} else {
// focus kept. provide the currently focused element with events
if (focused) {focused->getMV2D()->mousePressed(m, p2);}
}
}
/** needed eg. when the focused element gets invalid (switching visible layers) */
void layerChange(MapView2D* m) override {
(void) m;
setFocused(nullptr);
}
private:
/**
* @brief change the currently focused element. throws an event.
* @param el the to-be-focused element or null
* @return true if the focused element has changed. false otherwise
*/
bool setFocused(MapModelElement* el) {
// whether the focus has changed or not
const bool focusChanged = (focused != el);
if (focusChanged) {
// unfocus the old one (if any)
if (focused) {focused->getMV2D()->unfocus();}
// set the currently focused object (if any)
focused = el;
// focus the new one (if any)
if (focused) {focused->getMV2D()->focus();}
emit onMapElementSelected(el);
}
// done
return focusChanged;
}
virtual void mouseMoveEvent(MapView2D* m, QMouseEvent* e) override {
const Scaler& s = m->getScaler();
Point2 p2(s.xsm(e->x()), s.ysm(e->y()));
// mouse pressed?
if (mouseIsDown) {
// provide the focused element with the mouse event?
if (focused) {focused->getMV2D()->mouseMove(m, p2); return;}
}
}
virtual void mouseReleaseEvent(MapView2D* m, QMouseEvent* e) override {
const Scaler& s = m->getScaler();
Point2 p2(s.xsm(e->x()), s.ysm(e->y()));
// provide the focused element with the mouse event?
if (focused) {focused->getMV2D()->mouseReleased(m, p2);}
mouseIsDown = false;
}
virtual void keyPressEvent(MapView2D* m, QKeyEvent* e) override {
(void) m;
if (focused) {
// pass it to the element which may consume this event
if (focused->getMV2D()->keyPressEvent(m, e)) {return;}
// not consumed -> additional options
// ESCAPE -> unfocus
if (e->key() == Qt::Key_Escape) {setFocused(nullptr);}
// DELETE -> delete
if (e->key() == Qt::Key_Delete) {
focused->deleteMe();
setFocused(nullptr);
}
}
}
signals:
/** map element was selected */
void onMapElementSelected(MapModelElement* el);
};
#endif // TOOLSELECTOR_H

59
mapview/tools/Tools.h Normal file
View File

@@ -0,0 +1,59 @@
#ifndef TOOLS_H
#define TOOLS_H
#include <vector>
#include "Tool.h"
/**
* combine several tools under the interface for one tool
*/
class Tools : public Tool {
private:
std::vector<Tool*> tools;
public:
/** add this tool */
void enable(Tool* t) {tools.push_back(t);}
/** remove this tool */
void disable(Tool* t) {tools.erase(std::remove(tools.begin(), tools.end(), t));}
virtual void mousePressEvent(MapView2D* m, QMouseEvent* e) override {
for (Tool* t : tools) {t->mousePressEvent(m, e);}
}
virtual void mouseMoveEvent(MapView2D* m, QMouseEvent* e) override {
for (Tool* t : tools) {t->mouseMoveEvent(m, e);}
}
virtual void mouseReleaseEvent(MapView2D* m, QMouseEvent* e) override {
for (Tool* t : tools) {t->mouseReleaseEvent(m, e);}
}
virtual void wheelEvent(MapView2D* m, QWheelEvent* e) override {
for (Tool* t : tools) {t->wheelEvent(m, e);}
}
virtual void keyPressEvent(MapView2D* m, QKeyEvent* e) override {
for (Tool* t : tools) {t->keyPressEvent(m, e);}
}
virtual void paintBefore(MapView2D* m, Painter& p) override {
for (Tool* t : tools) {t->paintBefore(m, p);}
}
virtual void paintAfter(MapView2D* m, Painter& p) override {
for (Tool* t : tools) {t->paintAfter(m, p);}
}
virtual void layerChange(MapView2D* m) override {
for (Tool* t : tools) {t->layerChange(m);}
}
};
#endif // TOOLS_H