This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
IndoorMap/mapview/2D/MV2DElementFloorObstacleWall.cpp
2018-07-25 18:12:25 +02:00

306 lines
8.2 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) {
const Point2 ps = win->getStart(wall);
const Point2 pe = win->getEnd(wall);
const Point2 perp = (pe-ps).perpendicular().normalized();
const float s = 0.06;
const Point2 p1 = ps - perp*s;
const Point2 p2 = pe - perp*s;
const Point2 p3 = pe + perp*s;
const Point2 p4 = ps + perp*s;
std::vector<Point2> pts = {p1, p2, p3, p4, p1};
p.setPenBrush(QColor(0,0,0), QColor(255,255,255));
p.drawPolygon(pts);
}
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 : fo->doors) {
pts.push_back(door->getStart(fo));
pts.push_back(door->getEnd(fo));
}
for (const Floorplan::FloorObstacleWallWindow* win : fo->windows) {
pts.push_back(win->getStart(fo));
pts.push_back(win->getEnd(fo));
}
pts.push_back(fo->to);
auto comp = [&] (const Point2 p1, const Point2 p2) {
return pts.front().getDistance(p1) < pts.front().getDistance(p2);
};
std::sort(pts.begin(), pts.end(), comp);
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, 1, 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;
}