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

@@ -7,6 +7,12 @@
#include "../model/MapModel.h"
/**
* this tool allows:
* - selecting 2D elements within the view (focus/unfocus)
* - selecting and moving nodes of elements inheriting from HasMoveableNodes
*
*/
class ToolSelector : public Tool {
Q_OBJECT
@@ -24,54 +30,115 @@ 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()) {
if (!el->getMV2D()) {continue;}
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);
setFocused(m, nullptr);
}
private:
void processUnfocus(MapView2D* m, MapModelElement* elem) {
MV2DElement* me = elem->getMV2D();
if (!me) {return;}
// elements has selectedable nodes? unselect them
if (dynamic_cast<HasMoveableNodes*>(me)) {
dynamic_cast<HasMoveableNodes*>(me)->onNodeUnselect(m);
}
// let the element itself process the unfocus
me->unfocus();
}
void processPress(MapView2D* m, const Point2 p, MapModelElement* elem) {
MV2DElement* me = elem->getMV2D();
if (!me) {return;}
// let the element itself process all events
me->mousePressed(m, p);
}
void processMove(MapView2D* m, const Point2 p, MapModelElement* elem) {
MV2DElement* me = elem->getMV2D();
if (!me) {return;}
// elements has selectedable nodes? try to process them
if (dynamic_cast<HasMoveableNodes*>(me)) {
if (moveNode(m, p, dynamic_cast<HasMoveableNodes*>(me))) {return;}
}
// otherwise: let the element itself process all events
me->mouseMove(m, p);
}
void processRelease(MapView2D* m, const Point2 p, MapModelElement* elem) {
MV2DElement* me = elem->getMV2D();
if (!me) {return;}
// element has selectedable nodes? try to process them
if (dynamic_cast<HasMoveableNodes*>(me)) {
if (selectNode(m, p, dynamic_cast<HasMoveableNodes*>(me))) {return;}
}
// otherwise: let the element itself process all events
me->mouseReleased(m, p);
}
private:
/** the given element has selectable nodes. try to select the one near to the mouse. true if successful */
bool selectNode(MapView2D* v, Point2 p, HasMoveableNodes* elem) {
// select a new point on mouse-release (more robust than on mouse-press)
// find the node nearest to p
auto comp = [&] (const MoveableNode& n1, const MoveableNode& n2) {return n1.pos.getDistance(p) < n2.pos.getDistance(p);};
auto lst = elem->getMoveableNodes();
auto it = std::min_element(lst.begin(), lst.end(), comp);
// is the nearest point below the threshold?
const float t = v->getScaler().sm(CFG::SEL_THRESHOLD_SIZE_PX);
const float d = it->pos.getDistance(p);
if (d < t) {
elem->onNodeSelect(v, it->userIdx);
return true;
} else {
elem->onNodeSelect(v, -1);
return false;
}
}
/** move the currently selected node. true if successful */
bool moveNode(MapView2D* v, Point2 p, HasMoveableNodes* elem) {
// no node selected? -> done
if (elem->getSelectedNode() == -1) {return false;}
// snap the node
const Point2 pSnapped = v->getScaler().snap(p);
// move
elem->onNodeMove(v, elem->getSelectedNode(), pSnapped);
return true;
}
private:
/**
@@ -79,7 +146,7 @@ private:
* @param el the to-be-focused element or null
* @return true if the focused element has changed. false otherwise
*/
bool setFocused(MapModelElement* el) {
bool setFocused(MapView2D* v, MapModelElement* el) {
// whether the focus has changed or not
const bool focusChanged = (focused != el);
@@ -87,7 +154,7 @@ private:
if (focusChanged) {
// unfocus the old one (if any)
if (focused) {focused->getMV2D()->unfocus();}
if (focused) {processUnfocus(v, focused);}
// set the currently focused object (if any)
focused = el;
@@ -104,6 +171,53 @@ private:
}
private:
virtual void mousePressEvent(MapView2D* m, QMouseEvent* e) override {
if (e->button() != Qt::MouseButton::LeftButton) {return;}
mouseIsDown = true;
const Scaler& s = m->getScaler();
const Point2 p2(s.xsm(e->x()), s.ysm(e->y()));
const float g = m->getScaler().sm(15); // increase each BBox by 15 px (needed mainly for hor/ver lines)
// get all elements with bounding-box matchings
std::vector<MapModelElement*> possible;
for (MapModelElement* el : m->getModel()->getSelectedLayerElements()) {
if (!el->getMV2D()) {continue;}
BBox2 bbox = el->getMV2D()->getBoundingBox(); // elements 2D 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(m, el)) {
;
} else {
// focus kept. provide the currently focused element with events
if (focused) {
processPress(m, p2, focused);
}
}
}
virtual void mouseMoveEvent(MapView2D* m, QMouseEvent* e) override {
const Scaler& s = m->getScaler();
@@ -113,7 +227,7 @@ private:
if (mouseIsDown) {
// provide the focused element with the mouse event?
if (focused) {focused->getMV2D()->mouseMove(m, p2); return;}
if (focused) {processMove(m, p2, focused);}
}
@@ -125,7 +239,7 @@ private:
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);}
if (focused) {processRelease(m, p2, focused);}
mouseIsDown = false;
@@ -142,12 +256,12 @@ private:
// not consumed -> additional options
// ESCAPE -> unfocus
if (e->key() == Qt::Key_Escape) {setFocused(nullptr);}
if (e->key() == Qt::Key_Escape) {setFocused(m, nullptr);}
// DELETE -> delete
if (e->key() == Qt::Key_Delete) {
focused->deleteMe();
setFocused(nullptr);
setFocused(m, nullptr);
}
}