293 lines
7.8 KiB
C++
293 lines
7.8 KiB
C++
#include "MV2DElementFloorObstacleWall.h"
|
|
|
|
#include "MV2DElement.h"
|
|
#include "HasMoveableNodes.h"
|
|
|
|
#include "MapViewElementHelper.h"
|
|
#include <Indoor/floorplan/v2/Floorplan.h>
|
|
#include <stdio.h>
|
|
|
|
|
|
void drawDoorSwing(const Floorplan::FloorObstacleWall* wall, const Floorplan::FloorObstacleWallDoor* door, Painter& p, QPen& pen) {
|
|
|
|
const float len = door->width;
|
|
//const Point2 dir = line->to - line->from;
|
|
Point2 start = door->getStart(wall);
|
|
Point2 end = door->getEnd(wall);
|
|
|
|
// opening indicator
|
|
float open = (+M_PI * 0.5);
|
|
if (door->inOut) {open = -open;}
|
|
if (door->leftRight) {open = -open;}
|
|
|
|
const float angle1 = std::atan2(end.y - start.y, end.x - start.x);
|
|
const float angle2 = angle1 + open;
|
|
|
|
if (std::isnan(angle1)) {return;}
|
|
if (std::isnan(angle2)) {return;}
|
|
|
|
const Point2 pOpen = Point2( std::cos(angle2) * len, std::sin(angle2) * len ) + start;
|
|
|
|
pen.setWidth(2); p.setPen(pen);
|
|
p.drawLine(start, end);
|
|
|
|
pen.setWidth(1); p.setPen(pen);
|
|
p.drawLine(start, pOpen);
|
|
p.drawArc(start, door->width, angle1, open);
|
|
|
|
}
|
|
|
|
void drawDoorRevolve(const Floorplan::FloorObstacleWallDoor* door, Painter& p, QPen& pen) {
|
|
|
|
// const float angle_rad = std::atan2(fo->to.y-fo->from.y, fo->to.x-fo->from.x);
|
|
|
|
// // arcs
|
|
// const Point2 cen = (fo->from + fo->to) / 2;
|
|
// const float rad = (fo->to - fo->from).length() / 2;
|
|
// p.drawArc(cen, rad, (40-90)/180.0f*M_PI+angle_rad, 100/180.0f*M_PI);
|
|
// p.drawArc(cen, rad, (180+40-90)/180.0f*M_PI+angle_rad, 100/180.0f*M_PI);
|
|
|
|
// const int funAngle = (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count() / 50) % 360;
|
|
|
|
// // inner spinner
|
|
// int numDoors = 3;
|
|
// for (int i = 0; i < numDoors; ++i) {
|
|
// const int deg = 360 * i / numDoors + angle_rad*180.0f/M_PI + funAngle;
|
|
// const float sx = std::cos(deg / 180.0f * M_PI);
|
|
// const float sy = std::sin(deg / 180.0f * M_PI);
|
|
// const Point2 dst = cen + Point2(sx,sy) * rad;
|
|
// p.drawLine(cen, dst);
|
|
// }
|
|
|
|
}
|
|
|
|
void drawDoor(const Floorplan::FloorObstacleWall* line, const Floorplan::FloorObstacleWallDoor* door, Painter& p) {
|
|
|
|
QPen pen;
|
|
pen.setColor(QColor(0.5,0.5,0.5));
|
|
pen.setStyle(Qt::PenStyle::DotLine);
|
|
p.setPenBrush(pen, Qt::NoBrush);
|
|
|
|
if (Floorplan::DoorType::SWING == door->type) {
|
|
drawDoorSwing(line, door, p, pen);
|
|
} else if (Floorplan::DoorType::REVOLVING == door->type) {
|
|
drawDoorRevolve(door, p, pen);
|
|
}
|
|
|
|
}
|
|
|
|
void drawWindow(const Floorplan::FloorObstacleWall* wall, const Floorplan::FloorObstacleWallWindow* win, Painter& p) {
|
|
|
|
QPen pen;
|
|
pen.setColor(QColor(0.5,0.5,0.5));
|
|
pen.setWidth(3);
|
|
pen.setStyle(Qt::PenStyle::DotLine);
|
|
p.setPenBrush(pen, Qt::NoBrush);
|
|
|
|
const Point2 p1 = win->getStart(wall);
|
|
const Point2 p2 = win->getEnd(wall);
|
|
|
|
p.drawLine(p1, p2);
|
|
|
|
}
|
|
|
|
bool isConnected(const Point2 p, const Floorplan::Floor* f, const Floorplan::FloorObstacleWall* fo) {
|
|
const float delta = 0.001;
|
|
for (const Floorplan::FloorObstacle* fo1 : f->obstacles) {
|
|
if (fo1 == fo) {continue;}
|
|
const Floorplan::FloorObstacleWall* wall = dynamic_cast<const Floorplan::FloorObstacleWall*>(fo1);
|
|
if (wall) {
|
|
if (wall->from.eq(p, delta)) {return true;}
|
|
if (wall->to.eq(p, delta)) {return true;}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
MV2DElementFloorObstacleWall::MV2DElementFloorObstacleWall(Floorplan::Floor* f, Floorplan::FloorObstacleWall* fo) : f(f), fo(fo) {
|
|
;
|
|
}
|
|
|
|
BBox2 MV2DElementFloorObstacleWall::getBoundingBox() const {
|
|
BBox2 bbox;
|
|
bbox.add(fo->from);
|
|
bbox.add(fo->to);
|
|
return bbox;
|
|
}
|
|
|
|
ClickDist MV2DElementFloorObstacleWall::getMinDistanceXY(const Point2 p) const {
|
|
return MapElementHelper::getLineDistanceXY(fo->from, fo->to, p);
|
|
}
|
|
|
|
|
|
|
|
void MV2DElementFloorObstacleWall::paint(Painter& p) {
|
|
|
|
// convert wall's thickness from meter to pixels
|
|
const float thickness_px = p.s.ms(fo->thickness_m);
|
|
|
|
// see notes within MapElementHelper!
|
|
// lines only get thicker, but not longer!
|
|
p.setPenBrush(MapElementHelper::getPen(fo->material, fo->type, hasFocus(), thickness_px), Qt::NoBrush);
|
|
|
|
// draw the wall itself
|
|
|
|
// sort all doors by position on the line
|
|
std::vector<Floorplan::FloorObstacleWallDoor*> doors = fo->doors;
|
|
auto comp = [] (const Floorplan::FloorObstacleWallDoor* d1, const Floorplan::FloorObstacleWallDoor* d2) {
|
|
return d1->atLinePos < d2->atLinePos;
|
|
};
|
|
std::sort(doors.begin(), doors.end(), comp);
|
|
|
|
std::vector<Point2> pts;
|
|
pts.push_back(fo->from);
|
|
for (const Floorplan::FloorObstacleWallDoor* door : doors) {
|
|
pts.push_back(door->getStart(fo));
|
|
pts.push_back(door->getEnd(fo));
|
|
}
|
|
pts.push_back(fo->to);
|
|
|
|
for (size_t i = 0; i < pts.size(); i+=2) {
|
|
p.drawLine(pts[i], pts[i+1]);
|
|
}
|
|
//p.drawLine(fo->from, fo->to);
|
|
|
|
const bool c1 = isConnected(fo->from, f, fo);
|
|
const bool c2 = isConnected(fo->to, f, fo);
|
|
|
|
// wall conencted to other walls?
|
|
if (c1 || c2) {
|
|
|
|
// QPen change is costly!
|
|
QPen pp = p.getPen();
|
|
pp.setCapStyle(Qt::RoundCap);
|
|
p.setPen(pp);
|
|
|
|
// indicate connection with other wall
|
|
if (c1) {p.drawDot(fo->from);}
|
|
if (c2) {p.drawDot(fo->to);}
|
|
|
|
}
|
|
|
|
for (const Floorplan::FloorObstacleWallDoor* door : fo->doors) {
|
|
drawDoor(fo, door, p);
|
|
}
|
|
|
|
for (const Floorplan::FloorObstacleWallWindow* window : fo->windows) {
|
|
drawWindow(fo, window, p);
|
|
}
|
|
|
|
// length info
|
|
if (hasFocus()) {
|
|
|
|
// obstacle length
|
|
p.setPenBrush(Qt::black, Qt::NoBrush);
|
|
p.drawLength(fo->from, fo->to, fo->from.getDistance(fo->to), thickness_px/2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void MV2DElementFloorObstacleWall::onFocus() {
|
|
;
|
|
}
|
|
|
|
void MV2DElementFloorObstacleWall::onUnfocus() {
|
|
selectedUserIdx = -1; // clear selection
|
|
}
|
|
|
|
std::vector<MoveableNode> MV2DElementFloorObstacleWall::getMoveableNodes() const {
|
|
|
|
std::vector<MoveableNode> nodes;
|
|
nodes.push_back(MoveableNode(0, fo->from));
|
|
nodes.push_back(MoveableNode(1, fo->to));
|
|
|
|
int cnt = 0;
|
|
for (const Floorplan::FloorObstacleWallDoor* door : fo->doors) {
|
|
const Point2 pos = fo->from + (fo->to - fo->from) * door->atLinePos;
|
|
nodes.push_back(MoveableNode(cnt+1000, pos));
|
|
++cnt;
|
|
}
|
|
|
|
cnt = 0;
|
|
for (const Floorplan::FloorObstacleWallWindow* win : fo->windows) {
|
|
const Point2 pos = fo->from + (fo->to - fo->from) * win->atLinePos;
|
|
nodes.push_back(MoveableNode(cnt+2000, pos));
|
|
++cnt;
|
|
}
|
|
|
|
return nodes;
|
|
|
|
}
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
void MV2DElementFloorObstacleWall::onNodeMove(MapView2D* v, const int userIdx, const Point2 newPos) {
|
|
|
|
(void) v;
|
|
if (userIdx == 0) {fo->from.x = newPos.x; fo->from.y = newPos.y;}
|
|
if (userIdx == 1) {fo->to.x = newPos.x; fo->to.y = newPos.y;}
|
|
|
|
Point2 perp = (fo->from - fo->to).perpendicular() * 100;
|
|
Line2 l1(newPos-perp, newPos+perp);
|
|
Line2 l2(fo->from, fo->to);
|
|
|
|
Point2 p;
|
|
float u = 0;
|
|
bool isects = intersects(l2, l1, true, p, &u);
|
|
if (u < 0.1) {u = 0.1;}
|
|
if (u > 0.9) {u = 0.9;}
|
|
|
|
if (userIdx >= 1000 && userIdx < 2000) {
|
|
|
|
Floorplan::FloorObstacleWallDoor* door = fo->doors[userIdx-1000];
|
|
|
|
if (isects) {
|
|
door->atLinePos = u;
|
|
}
|
|
|
|
} else if (userIdx >= 2000 && userIdx < 3000) {
|
|
|
|
Floorplan::FloorObstacleWallWindow* win = fo->windows[userIdx-2000];
|
|
|
|
if (isects) {
|
|
win->atLinePos = u;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void MV2DElementFloorObstacleWall::onNodeMoved(MapView2D* v, const int userIdx, const Point2 newPos) {
|
|
(void) userIdx;
|
|
(void) newPos;
|
|
emit v->onElementChange(this);
|
|
}
|
|
|
|
|
|
bool MV2DElementFloorObstacleWall::keyPressEvent(MapView2D* v, QKeyEvent* e) {
|
|
|
|
if (e->key() == Qt::Key_D) {
|
|
Floorplan::FloorObstacleWallDoor* door = new Floorplan::FloorObstacleWallDoor(Floorplan::DoorType::SWING, Floorplan::Material::WOOD, 0.5, 1.0, 2.1);
|
|
fo->doors.push_back(door);
|
|
return true;
|
|
} else if (e->key() == Qt::Key_W) {
|
|
Floorplan::FloorObstacleWallWindow* win = new Floorplan::FloorObstacleWallWindow(Floorplan::WindowType::UNKNOWN, Floorplan::Material::WOOD, 0.5, 0.5, 1.0, 1.0);
|
|
fo->windows.push_back(win);
|
|
return true;
|
|
} else if (e->key() == Qt::Key_Delete && getSelectedNode() >= 1000) {
|
|
const int idx = getSelectedNode() - 1000;
|
|
fo->doors.erase(fo->doors.begin()+idx);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|