a lot of work on th map-creator

This commit is contained in:
2016-07-04 15:11:10 +02:00
parent 6243165084
commit 2935f468fc
61 changed files with 2612 additions and 3342 deletions

View File

@@ -0,0 +1,64 @@
#ifndef MV2D_IHASMOVEABLENODES_H
#define MV2D_IHASMOVEABLENODES_H
#include <Indoor/geo/Point2.h>
#include "../MapView2D.h"
/** the selectable/moveable node */
struct MoveableNode {
/** user-defined index */
int userIdx;
/** the node's position */
Point2 pos;
/** ctor */
MoveableNode(const int userIdx, const Point2 pos) : userIdx(userIdx), pos(pos) {;}
};
/**
* base for all 2D elements that have selectable and moveable nodes
* the ToolSelector is able to get, select, and move those nodes
*/
class HasMoveableNodes {
protected:
/** currently selected node */
int selectedUserIdx = -1;
public:
/** get a list of all nodes that are selectable / moveable */
virtual std::vector<MoveableNode> getMoveableNodes() const = 0;
/** the given node was moved */
virtual void onNodeMove(MapView2D* v, const int userIdx, const Point2 newPos) = 0;
/** the given node was selected */
virtual void onNodeSelect(MapView2D* v, const int userIdx) {
(void) v;
this->selectedUserIdx = userIdx;
}
/** unselect any selected node */
virtual void onNodeUnselect(MapView2D* v) {
(void) v;
this->selectedUserIdx = -1;
}
/** get the currently selected node */
virtual int getSelectedNode() const {
return selectedUserIdx;
}
};
#endif // MV2D_IHASMOVEABLENODES_H

View File

@@ -63,6 +63,7 @@ public:
/** key pressed. return true when consumed. */
virtual bool keyPressEvent(MapView2D* v, QKeyEvent* e) = 0;
protected:
virtual void onFocus() = 0;

View File

@@ -2,14 +2,18 @@
#define MV2DELEMENTACCESSPOINT_H
#include "MV2DElement.h"
#include "HasMoveableNodes.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementAccessPoint : public MV2DElement {
#include "../../UIHelper.h"
class MV2DElementAccessPoint : public MV2DElement, public HasMoveableNodes {
private:
bool sel = false;
//bool sel = false;
Floorplan::AccessPoint* ap;
public:
@@ -34,19 +38,28 @@ public:
/** repaint me */
void paint(Painter& p) override {
if (sel) {
p.setPenBrush(Qt::black, CFG::SEL_COLOR);
p.drawCircle(ap->pos.xy());
static const QPixmap& pixmapUnfocused = UIHelper::getPixmapColored("wifi", CFG::UNFOCUS_COLOR, 16);
static const QPixmap& pixmapFocused = UIHelper::getPixmapColored("wifi", CFG::FOCUS_COLOR, 16);
static const QPixmap& pixmapSel = UIHelper::getPixmapColored("wifi", CFG::SEL_COLOR, 16);
if (selectedUserIdx == 0) {
//p.setPenBrush(Qt::black, CFG::SEL_COLOR);
//p.drawCircle(ap->pos.xy());
p.drawPixmap(ap->pos.xy(), pixmapSel);
} else if (hasFocus()) {
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawCircle(ap->pos.xy());
//p.setPenBrush(Qt::black, Qt::NoBrush);
//p.drawCircle(ap->pos.xy());
p.drawPixmap(ap->pos.xy(), pixmapFocused);
} else {
p.setPenBrush(Qt::gray, Qt::NoBrush);
p.drawCircle(ap->pos.xy());
//p.setPenBrush(Qt::gray, Qt::NoBrush);
//p.drawCircle(ap->pos.xy());
p.drawPixmap(ap->pos.xy(), pixmapUnfocused);
}
// label
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawDot(ap->pos.xy());
if (p.getScaler().getScale() >= 25) {
const std::string str = ap->name + " (" + ap->name + ")";
p.p->drawText(p.getScaler().xms(ap->pos.x) + 10, p.getScaler().yms(ap->pos.y) + 5, str.c_str());
@@ -57,6 +70,14 @@ public:
}
virtual std::vector<MoveableNode> getMoveableNodes() const override {
return { MoveableNode(0, ap->pos.xy()) };
}
virtual void onNodeMove(MapView2D* v, const int userIdx, const Point2 newPos) override {
(void) v;
if (userIdx == 0) {ap->pos.x = newPos.x; ap->pos.y = newPos.y;}
}
/** mouse pressed at the given point */
@@ -67,20 +88,15 @@ public:
}
/** mouse moved to the given point */
virtual void mouseMove(MapView2D* v, const Point2 _p) override {
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;
}
(void) p;
}
/** mouse released */
virtual void mouseReleased(MapView2D* v, const Point2 _p) override {
virtual void mouseReleased(MapView2D* v, const Point2 p) override {
(void) v;
(void) _p;
sel = true;
(void) p;
}
virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override {
@@ -90,11 +106,11 @@ public:
}
virtual void onFocus() override {
;
}
virtual void onUnfocus() override {
sel = false;
;
}
};

View File

@@ -2,14 +2,17 @@
#define MV2DELEMENTBEACON_H
#include "MV2DElement.h"
#include "HasMoveableNodes.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementBeacon : public MV2DElement {
#include "../../UIHelper.h"
class MV2DElementBeacon : public MV2DElement, public HasMoveableNodes {
private:
bool sel = false;
Floorplan::Beacon* b;
public:
@@ -33,19 +36,28 @@ public:
/** repaint me */
void paint(Painter& p) override {
if (sel) {
p.setPenBrush(Qt::black, CFG::SEL_COLOR);
p.drawCircle(b->pos.xy());
static const QPixmap& pixmapUnfocused = UIHelper::getPixmapColored("beacon", CFG::UNFOCUS_COLOR, 16);
static const QPixmap& pixmapFocused = UIHelper::getPixmapColored("beacon", CFG::FOCUS_COLOR, 16);
static const QPixmap& pixmapSel = UIHelper::getPixmapColored("beacon", CFG::SEL_COLOR, 16);
if (selectedUserIdx == 0) {
//p.setPenBrush(Qt::black, CFG::SEL_COLOR);
//p.drawCircle(b->pos.xy());
p.drawPixmap(b->pos.xy(), pixmapSel);
} else if (hasFocus()) {
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawCircle(b->pos.xy());
//p.setPenBrush(Qt::black, Qt::NoBrush);
//p.drawCircle(b->pos.xy());
p.drawPixmap(b->pos.xy(), pixmapFocused);
} else {
p.setPenBrush(Qt::gray, Qt::NoBrush);
p.drawCircle(b->pos.xy());
//p.setPenBrush(Qt::gray, Qt::NoBrush);
//p.drawCircle(b->pos.xy());
p.drawPixmap(b->pos.xy(), pixmapUnfocused);
}
// label
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawDot(b->pos.xy());
if (p.getScaler().getScale() >= 25) {
const std::string str = b->name + " (" + b->mac + ")";
p.p->drawText(p.getScaler().xms(b->pos.x) + 10, p.getScaler().yms(b->pos.y) + 5, str.c_str());
@@ -56,12 +68,21 @@ public:
}
virtual std::vector<MoveableNode> getMoveableNodes() const override {
return { MoveableNode(0, b->pos.xy()) };
}
virtual void onNodeMove(MapView2D* v, const int userIdx, const Point2 newPos) override {
(void) v;
if (userIdx == 0) {b->pos.x = newPos.x; b->pos.y = newPos.y;}
}
virtual void onFocus() override {
;
}
virtual void onUnfocus() override {
sel = false;
;
}
/** mouse pressed at the given point */
@@ -71,20 +92,15 @@ public:
}
/** mouse moved to the given point */
virtual void mouseMove(MapView2D* v, const Point2 _p) override {
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;
}
(void) p;
}
/** 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 {

View File

@@ -35,7 +35,7 @@ public:
/** repaint me */
void paint(Painter& p) override {
QPen pen = MapElementHelper::getPen(c->material, c->type, hasFocus());
QPen pen;// = MapElementHelper::getPen(c->material, c->type, hasFocus());
p.setPenBrush(pen, Qt::NoBrush);
p.drawCircle(c->center, c->radius);
@@ -81,7 +81,7 @@ public:
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);
const Point2 p = v->getScaler().snap(_p);
if (selPoint == 0) {c->center = p;}
if (selPoint == 1) {c->radius = p.getDistance(c->center);}
}

View File

@@ -0,0 +1,146 @@
#ifndef MV2DELEMENTFLOOROBSTACLEDOOR_H
#define MV2DELEMENTFLOOROBSTACLEDOOR_H
#include "MV2DElement.h"
#include "MapViewElementHelper.h"
#include "HasMoveableNodes.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementFloorObstacleDoor : public MV2DElement, public HasMoveableNodes {
private:
//int selPoint = -1;
Floorplan::FloorObstacleDoor* fo;
public:
/** ctor */
MV2DElementFloorObstacleDoor(Floorplan::FloorObstacleDoor* 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 (selectedUserIdx == 0) {p.drawCircle(fo->from);}
if (selectedUserIdx == 1) {p.drawCircle(fo->to);}
}
QPen pen;
pen.setColor(QColor(0.5,0.5,0.5));
pen.setStyle(Qt::PenStyle::DotLine);
p.setPenBrush(pen, Qt::NoBrush);
// opening indicator
const float open = (fo->swap) ? (-M_PI * 0.5) : (+M_PI * 0.5);
const float len = (fo->to - fo->from).length();
const float angle1 = std::atan2(fo->to.y-fo->from.y, fo->to.x-fo->from.x);
const float angle2 = angle1 + open;
const Point2 pOpen = Point2( std::cos(angle2) * len, std::sin(angle2) * len ) + fo->from;
pen.setWidth(2); p.setPen(pen);
p.drawLine(fo->from, fo->to);
pen.setWidth(1); p.setPen(pen);
p.drawLine(fo->from, pOpen);
p.drawArc(fo->from, len, angle1, open);
// 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 {
selectedUserIdx = -1; // clear selection
}
virtual void mousePressed(MapView2D* v, const Point2 p) override {
(void) v;
(void) p;
}
virtual void mouseMove(MapView2D* v, const Point2 p) override {
(void) v;
(void) p;
}
virtual void mouseReleased(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 = v->getScaler().snap(_p);
// 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;}
// emit v->onElementChange(this);
// }
/** mouse released */
// 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(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;}
// }
/** get a list of all nodes that are selectable / moveable */
virtual std::vector<MoveableNode> getMoveableNodes() const override {
std::vector<MoveableNode> nodes = {
MoveableNode(0, fo->from),
MoveableNode(1, fo->to)
};
return nodes;
}
/** the given node was moved */
virtual void onNodeMove(MapView2D* v, const int userIdx, const Point2 newPos) override {
switch (userIdx) {
case 0: fo->from = newPos; break;
case 1: fo->to = newPos; break;
}
emit v->onElementChange(this);
}
virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override {
(void) v;
(void) e;
return false;
}
};
#endif // MV2DELEMENTFLOOROBSTACLEDOOR_H

View File

@@ -42,10 +42,18 @@ public:
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);
// // door?
// if (fo->type == Floorplan::ObstacleType::DOOR) {
// paintDoor(p);
// } else {
// 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);
@@ -55,6 +63,29 @@ public:
}
void paintDoor(Painter& p) {
QPen pen;
pen.setColor(QColor(0.5,0.5,0.5));
pen.setStyle(Qt::PenStyle::DotLine);
p.setPenBrush(pen, Qt::NoBrush);
// opening indicator
const float open = M_PI / 4;
const float len = (fo->to - fo->from).length();
const float angle1 = std::atan2(fo->to.y-fo->from.y, fo->to.x-fo->from.x);
const float angle2 = angle1 + open;
const Point2 pOpen = Point2( std::cos(angle2) * len, std::sin(angle2) * len ) + fo->from;
p.drawLine(fo->from, fo->to);
p.drawLine(fo->from, pOpen);
p.drawArc(fo->from, len, angle1, open);
//p.drawLine(fo->to, pOpen);
}
virtual void onFocus() override {
;
}
@@ -74,7 +105,7 @@ public:
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);
const Point2 p = v->getScaler().snap(_p);
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;}
}

View File

@@ -93,7 +93,7 @@ public:
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);
const Point2 p = v->getScaler().snap(_p);
fo.poly.points[selPoint].x = p.x;
fo.poly.points[selPoint].y = p.y;
}

View File

@@ -115,7 +115,7 @@ public:
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);
const Point2 p = v->getScaler().snap(_p);
if (selPoint == 0) {underlay->anchor = p;}
}

View File

@@ -2,14 +2,17 @@
#define MV2DELEMENTPOI_H
#include "MV2DElement.h"
#include "HasMoveableNodes.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementPOI : public MV2DElement {
#include "../../UIHelper.h"
class MV2DElementPOI : public MV2DElement, public HasMoveableNodes {
private:
bool sel = false;
//bool sel = false;
Floorplan::POI* poi;
public:
@@ -34,19 +37,28 @@ public:
/** repaint me */
void paint(Painter& p) override {
if (sel) {
p.setPenBrush(Qt::black, CFG::SEL_COLOR);
p.drawCircle(poi->pos);
static const QPixmap& pixmapUnfocused = UIHelper::getPixmapColored("poi", CFG::UNFOCUS_COLOR, 16);
static const QPixmap& pixmapFocused = UIHelper::getPixmapColored("poi", CFG::FOCUS_COLOR, 16);
static const QPixmap& pixmapSel = UIHelper::getPixmapColored("poi", CFG::SEL_COLOR, 16);
if (selectedUserIdx == 0) {
// p.setPenBrush(Qt::black, CFG::SEL_COLOR);
// p.drawCircle(poi->pos);
p.drawPixmap(poi->pos, pixmapSel);
} else if (hasFocus()) {
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawCircle(poi->pos);
// p.setPenBrush(Qt::black, Qt::NoBrush);
// p.drawCircle(poi->pos);
p.drawPixmap(poi->pos, pixmapFocused);
} else {
p.setPenBrush(Qt::gray, Qt::NoBrush);
p.drawCircle(poi->pos);
// p.setPenBrush(Qt::gray, Qt::NoBrush);
// p.drawCircle(poi->pos);
p.drawPixmap(poi->pos, pixmapUnfocused);
}
// label
p.setPenBrush(Qt::black, Qt::NoBrush);
p.drawDot(poi->pos);
if (p.getScaler().getScale() >= 10) {
const std::string str = poi->name;
p.p->drawText(p.getScaler().xms(poi->pos.x) + 10, p.getScaler().yms(poi->pos.y) + 5, str.c_str());
@@ -55,29 +67,37 @@ public:
}
virtual std::vector<MoveableNode> getMoveableNodes() const override {
return { MoveableNode(0, poi->pos) };
}
virtual void onNodeMove(MapView2D* v, const int userIdx, const Point2 newPos) override {
(void) v;
if (userIdx == 0) {poi->pos = newPos;}
}
/** 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 {
virtual void mouseMove(MapView2D* v, const Point2 p) override {
(void) v;
if (sel) {
const Point2 p = Scaler::snap(_p, CFG::MOVE_SNAP_SIZE_M);
poi->pos.x = p.x;
poi->pos.y = p.y;
}
(void) p;
// if (sel) {
// const Point2 p = v->getScaler().snap(_p);
// poi->pos.x = p.x;
// poi->pos.y = p.y;
// }
}
/** mouse released */
virtual void mouseReleased(MapView2D* v, const Point2 _p) override {
virtual void mouseReleased(MapView2D* v, const Point2 p) override {
(void) v;
(void) _p;
sel = true;
(void) p;
}
virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override {
@@ -87,11 +107,11 @@ public:
}
virtual void onFocus() override {
;
}
virtual void onUnfocus() override {
sel = false;
;
}
};

View File

@@ -0,0 +1,233 @@
#ifndef MV2DELEMENTSTAIR_H
#define MV2DELEMENTSTAIR_H
#include "MV2DElement.h"
#include "MapViewElementHelper.h"
#include <Indoor/floorplan/v2/Floorplan.h>
class MV2DElementStair : public MV2DElement {
private:
bool sel = false;
Floorplan::Floor* floor;
Floorplan::Stair* stair;
int selPart = -1;
int selNode = -1;
public:
/** ctor with the AP to render/edit */
MV2DElementStair(Floorplan::Floor* floor, Floorplan::Stair* stair) : floor(floor), stair(stair) {;}
/** get the element's 3D bounding box */
BBox2 getBoundingBox() const override {
BBox2 bbox;
if (dynamic_cast<Floorplan::StairFreeform*>(stair)) {
Floorplan::StairFreeform* stair = dynamic_cast<Floorplan::StairFreeform*>(this->stair);
for (const Floorplan::StairPart p : stair->parts) {
bbox.add(p.start.xy());
bbox.add(p.end.xy());
}
}
return bbox;
}
/** get the element's minimal distance (nearest whatsoever) to the given point */
float getMinDistanceXY(const Point2 p) const override {
auto comp = [p] (const Floorplan::StairPart& p1, const Floorplan::StairPart& p2) {
const float d1 = MapElementHelper::getLineDistanceXY(p1.start.xy(), p1.end.xy(), p);
const float d2 = MapElementHelper::getLineDistanceXY(p2.start.xy(), p2.end.xy(), p);
return d1 < d2;
};
auto parts = stair->getParts();
auto min = std::min_element(parts.begin(), parts.end(), comp);
return MapElementHelper::getLineDistanceXY(min->start.xy(), min->end.xy(), p);
}
int getSelPart() const {return selPart;}
int getSelNode() const {return selNode;}
static inline float clamp01(const float val) {
if (val < 0) {return 0;}
if (val > 1) {return 1;}
return val;
}
/** repaint me */
void paint(Painter& p) override {
Floorplan::StairFreeform* stair = dynamic_cast<Floorplan::StairFreeform*>(this->stair);
// if (sel) {
// p.setPenBrush(Qt::black, CFG::SEL_COLOR);
// p.drawCircle(stair->center);
// } else if (hasFocus()) {
// p.setPenBrush(Qt::black, Qt::NoBrush);
// p.drawCircle(stair->center);
// } else {
// p.setPenBrush(Qt::gray, Qt::NoBrush);
// p.drawCircle(stair->center);
// }
// draw all parts of the stair (all polygons)
p.setPenBrush(Qt::black, Qt::NoBrush);
std::vector<Floorplan::StairPart> parts = stair->getParts();
std::vector<Floorplan::Quad3> quads = Floorplan::getQuads(parts, floor);
for (int i = 0; i < (int) parts.size(); ++i) {
const Floorplan::StairPart& part = parts[i];
const Floorplan::Quad3& quad = quads[i];
// fill the polygon with a gradient corresponding with the stair's height relative to the floor's height
QLinearGradient gradient(p.s.xms(part.start.x), p.s.yms(part.start.y), p.s.xms(part.end.x), p.s.yms(part.end.y));
const float p1 = 0.1 + clamp01( part.start.z / floor->height) * 0.8;
const float p2 = 0.1 + clamp01( part.end.z / floor->height) * 0.8;
gradient.setColorAt(0, QColor(p1*255, p1*255, p1*255));
gradient.setColorAt(1, QColor(p2*255, p2*255, p2*255));
p.setBrush(gradient);
p.setPen(QColor(0,0,0,128));
// polygon-construction
//const Floorplan::Quad3 quad = part.getQuad(floor);
const std::vector<Point3> points = {quad.p1, quad.p2, quad.p3, quad.p4};
p.drawPolygon(points);
}
if (hasFocus()) {
int cnt = 0;
std::vector<Floorplan::StairPart> parts = stair->getParts();
for (const Floorplan::StairPart& part : parts) {
p.setPenBrush(Qt::black, (cnt == selPart && selNode == 0) ? CFG::SEL_COLOR : Qt::NoBrush); // part start
p.drawCircle(part.start.xy());
p.setPenBrush(Qt::black, (cnt == selPart && selNode == 1) ? CFG::SEL_COLOR : Qt::NoBrush); // part end
p.drawRect(part.end.xy());
p.setPenBrush(Qt::blue, Qt::NoBrush);
Point2 ctr = (part.start+part.end).xy() / 2;
p.drawText(ctr, "p" + std::to_string(cnt+1)); // part name
++cnt;
}
for (int i = 0; i < (int)parts.size() - 1; ++i) {
const Point3 p1 = parts[i+0][1];
const Point3 p2 = parts[i+1][0];
p.drawLine(p1.xy(), p2.xy());
}
}
}
/** 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 (selPart == -1) {return;}
Floorplan::StairFreeform* stair = dynamic_cast<Floorplan::StairFreeform*>(this->stair);
const Point2 p = v->getScaler().snap(_p);
stair->parts[selPart][selNode].x = p.x;
stair->parts[selPart][selNode].y = p.y;
}
/** mouse released */
virtual void mouseReleased(MapView2D* v, const Point2 _p) override {
(void) v;
(void) _p;
// select a new point on mouse-release (more robust than on mouse-press)
Floorplan::StairFreeform* stair = dynamic_cast<Floorplan::StairFreeform*>(this->stair);
const float t = v->getScaler().sm(CFG::SEL_THRESHOLD_SIZE_PX);
// auto comp = [&] (const Point3 a, const Point3 b) {return a.xy().getDistance(_p) < b.xy().getDistance(_p);};
// auto it = std::min_element(stair->nodes.begin(), stair->nodes.end(), comp);
// if (it == stair->nodes.end()) {selIdx = -1;} // none found -> skip
// else if ((*it).xy().getDistance(_p) > t) {selIdx = -1;} // nearest distance is above threshold -> skip
// else {selIdx = it - stair->nodes.begin();}
float best = 999999;
int minPart; int minNode;
for (int part = 0; part < (int) stair->parts.size(); ++part) {
for (int node = 0; node < 2; ++node) {
const float dist = stair->parts[part][node].xy().getDistance(_p);
if (dist < best) {best = dist; minPart = part; minNode = node;}
}
}
if (best <= t) {
selPart = minPart; selNode = minNode;
} else {
selPart = -1; selNode = -1;
}
emit v->onElementChange(this);
}
virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override {
(void) v;
(void) e;
Floorplan::StairFreeform* stair = dynamic_cast<Floorplan::StairFreeform*>(this->stair);
if (e->key() == Qt::Key_Delete) {
// delete the currently selected vertex?
if (selPart != -1) {
// stair->nodes.erase(stair->nodes.begin() + selIdx);
// selIdx = -1;
// return true;
}
} else if (e->key() == Qt::Key_Plus && selPart != -1) {
// int idx1 = selIdx;
// int idx2 = (selIdx + 1) % stair->nodes.size();
// int idxNew = idx2;
// Point3 pNew = (stair->nodes[idx1] + stair->nodes[idx2]) / 2.0f;
// stair->nodes.insert(stair->nodes.begin() + idxNew, pNew);
// selIdx = idxNew;
// return true;
const int idxNew = selPart + 1;
const Point3 p0 = stair->parts[selPart][1];
const Point3 p1 = p0 + Point3(1,1,0);
const Point3 p2 = p1 + Point3(2,2,0);
const float w = stair->parts[selPart].width;
stair->parts.insert(stair->parts.begin() + idxNew, Floorplan::StairPart(p1, p2, w));
return true;
}
// not consumed
return false;
}
virtual void onFocus() override {
selPart = -1;
selNode = -1;
}
virtual void onUnfocus() override {
sel = false;
}
};
#endif // MV2DELEMENTSTAIR_H

View File

@@ -15,6 +15,8 @@
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 FOCUS_COLOR = Qt::black;
const QColor UNFOCUS_COLOR = Qt::gray;
const QColor SEL_COLOR = Qt::blue;
}
@@ -52,7 +54,9 @@ public:
} else {
// no cut detected
return 9999999;
const float d1 = p1.getDistance(dst);
const float d2 = p2.getDistance(dst);
return std::min(d1, d2);
}