diff --git a/IndoorMap.pro b/IndoorMap.pro index 0f2fc8c..2f5936e 100644 --- a/IndoorMap.pro +++ b/IndoorMap.pro @@ -122,7 +122,10 @@ HEADERS += MainWindow.h \ mapview/elements/HasMoveableNodes.h \ mapview/2D/MapView2D.h \ mapview/2D/Painter.h \ - mapview/2D/Scaler.h + mapview/2D/Scaler.h \ + mapview/2D/MV2DElementElevator.h \ + mapview/model/MMFloorElevators.h \ + mapview/model/MMFloorElevator.h FORMS += MainWindow.ui diff --git a/MainController.cpp b/MainController.cpp index 24e6ce7..03dd1ae 100644 --- a/MainController.cpp +++ b/MainController.cpp @@ -85,8 +85,13 @@ MainController::MainController() { //mapModel->load("../IndoorMap/maps/test.xml"); //mapModel->load("/mnt/data/workspaces/IPIN2016/IPIN2016/competition/maps/CAR/CAR9.xml"); - //mapModel->load("/mnt/data/workspaces/IPIN2016/IPIN2016/competition/maps/UAH/UAH7_test.xml"); - mapModel->load("/mnt/data/workspaces/IPIN2016/IPIN2016/competition/maps/UJI-TI/UJI-TI4.xml"); + mapModel->load("/mnt/data/workspaces/IPIN2016/IPIN2016/competition/maps/UAH/UAH9.xml"); + //mapModel->load("/mnt/data/workspaces/IPIN2016/IPIN2016/competition/maps/UJI-TI/UJI-TI4.xml"); + //mapModel->load("/mnt/data/workspaces/IPIN2016/IPIN2016/competition/maps/UJI-UB/UJI-UB4.xml"); + //mapModel->load("/mnt/data/workspaces/Indoor/tests/data/WalkHeadingMap.xml"); + //mapModel->load("/mnt/data/workspaces/IPIN2016/IPIN2016/competition/maps/test.xml"); + + } diff --git a/mapview/2D/MV2DElementElevator.h b/mapview/2D/MV2DElementElevator.h new file mode 100644 index 0000000..3533ef8 --- /dev/null +++ b/mapview/2D/MV2DElementElevator.h @@ -0,0 +1,111 @@ +#ifndef MV2DELEMENTELEVATOR_H +#define MV2DELEMENTELEVATOR_H + +#include "MV2DElement.h" +#include "HasMoveableNodes.h" + +#include "MapViewElementHelper.h" +#include + +#include "../../UIHelper.h" + +class MV2DElementElevator : public MV2DElement, public HasMoveableNodes { + +private: + + Floorplan::Elevator* elevator; + +public: + + /** ctor with the AP to render/edit */ + MV2DElementElevator(Floorplan::Elevator* elevator) : elevator(elevator) {;} + + + BBox2 getBoundingBox() const override { + BBox2 bbox; + const float max = std::max(elevator->width, elevator->depth); + bbox.add(Point2(elevator->center.x, elevator->center.y)); + bbox.grow(Point2(max/2, max/2)); + return bbox; + } + + /** get the element's minimal distance (nearest whatsoever) to the given point */ + float getMinDistanceXY(const Point2 p) const override { +// std::vector points = elevator->getPoints().points; +// points.push_back(elevator->center); +// auto it minEl = std::min_element(points.begin(), points.end(), + return p.getDistance(elevator->center); + } + + /** repaint me */ + void paint(Painter& p) override { + + // area + const Floorplan::Polygon2 poly = elevator->getPoints(); + p.setPenBrush(Qt::gray, Qt::lightGray); + p.drawPolygon(poly.points); + + // outline + QPen pen; pen.setWidth(2); pen.setColor(QColor(0,0,0)); + p.setPenBrush(pen, Qt::NoBrush); + //p.drawLine(poly.points[0], poly.points[1]); + p.drawLine(poly.points[1], poly.points[2]); + p.drawLine(poly.points[2], poly.points[3]); + p.drawLine(poly.points[3], poly.points[0]); + + if (selectedUserIdx == 0) { + p.setPenBrush(Qt::black, CFG::SEL_COLOR); + p.drawCircle(elevator->center); + } else if (hasFocus()) { + p.setPenBrush(Qt::black, Qt::NoBrush); + p.drawCircle(elevator->center); + } else { + //p.setPenBrush(Qt::gray, Qt::NoBrush); + //p.drawCircle(elevator->center); + } + + } + + virtual std::vector getMoveableNodes() const override { + return { MoveableNode(0, elevator->center) }; + } + + virtual void onNodeMove(MapView2D* v, const int userIdx, const Point2 newPos) override { + (void) v; + if (userIdx == 0) {elevator->center.x = newPos.x; elevator->center.y = newPos.y;} + } + + + 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; + } + + virtual bool keyPressEvent(MapView2D* v, QKeyEvent *e) override { + (void) v; + (void) e; + return false; + } + + virtual void onFocus() override { + ; + } + + virtual void onUnfocus() override { + ; + } + +}; + + +#endif // MV2DELEMENTELEVATOR_H diff --git a/mapview/2D/MV2DElementFloorUnderlay.h b/mapview/2D/MV2DElementFloorUnderlay.h index ee09ac3..79a3d1a 100644 --- a/mapview/2D/MV2DElementFloorUnderlay.h +++ b/mapview/2D/MV2DElementFloorUnderlay.h @@ -15,6 +15,8 @@ class MV2DElementFloorUnderlay : public MV2DElement { private: QImage img; + QImage imgScaled; + std::string tmpFile; Floorplan::UnderlayImage* underlay; BBox2 bbox; @@ -58,9 +60,8 @@ public: if (tmpFile != underlay->filename) { img = QImage(underlay->filename.c_str()); - if (img.size().width() == 0) { - missing(); - } + if (img.size().width() == 0) { missing(); } + img = img.convertToFormat(QImage::Format_Grayscale8); // saves a huge amount of memory and should suffice tmpFile = underlay->filename; } @@ -79,17 +80,39 @@ public: float sy1 = p.s.yms(my1); float sx2 = p.s.xms(mx2); float sy2 = p.s.yms(my2); - float sw = std::abs(sx1-sx2); - float sh = std::abs(sy1-sy2); + float sw = std::round(std::abs(sx1-sx2)); + float sh = std::round(std::abs(sy1-sy2)); + + const float origArea = img.width() * img.height(); + const float scaledArea = sw*sh; bbox = BBox2(); bbox.add(Point2(mx1, my1)); bbox.add(Point2(mx2, my2)); + // if the to-be-displayed image is smaller than the input-one, use a pre-computed downscaled version + if (scaledArea < origArea) { + // does the cached downscaled image needs rebuild? (size changed) + if (imgScaled.width() != sw || imgScaled.height() != sh) { + imgScaled = img.scaled(sw, sh, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + } + } else { + imgScaled = QImage(); + } + + float opacity = p.p->opacity(); p.p->setOpacity(0.50f); - p.p->drawImage(QRectF(sx1, sy1-sh, sw, sh), img, QRectF(0,0,img.width(),img.height())); + + // render downscaled image from cache? or use live-upscaling (faster, eats up less memory, ...) + if (imgScaled.width() > 0) { + p.p->drawImage(sx1, sy1-sh, imgScaled); + } else { + p.p->setRenderHint(QPainter::SmoothPixmapTransform, true); + p.p->drawImage(QRectF(sx1, sy1-sh, sw, sh), img, QRectF(0,0,img.width(),img.height())); + } + p.p->setOpacity(opacity); // selected endpoint(s)? diff --git a/mapview/3DGrid/GridModel.h b/mapview/3DGrid/GridModel.h index ab24063..b27901d 100644 --- a/mapview/3DGrid/GridModel.h +++ b/mapview/3DGrid/GridModel.h @@ -84,7 +84,7 @@ public: GridFactory fac(grid); fac.build(im, &l); - Importance::addImportance(grid); + Importance::addImportance(grid, &l); //Importance::addImportance(grid, 400); } diff --git a/mapview/model/MMFloor.h b/mapview/model/MMFloor.h index 3b2d67b..010e35b 100644 --- a/mapview/model/MMFloor.h +++ b/mapview/model/MMFloor.h @@ -9,6 +9,7 @@ #include "MMFloorUnderlays.h" #include "MMFloorPOIs.h" #include "MMFloorStairs.h" +#include "MMFloorElevators.h" #include "IHasParams.h" @@ -39,7 +40,7 @@ public: new MMFloorBeacons(this, floor); new MMFloorPOIs(this, floor); new MMFloorStairs(this, floor); - + new MMFloorElevators(this, floor); } diff --git a/mapview/model/MMFloorElevator.h b/mapview/model/MMFloorElevator.h new file mode 100644 index 0000000..c83a956 --- /dev/null +++ b/mapview/model/MMFloorElevator.h @@ -0,0 +1,68 @@ +#ifndef MMFLOORELEVATOR_H +#define MMFLOORELEVATOR_H + +#include "MapModelElement.h" +#include "IHasParams.h" + +#include "../2D/MV2DElementElevator.h" +//#include "../3D/MV3DElementElevator.h" TODO + +#include + +class MMFloorElevator : public MapModelElement, public IHasParams { + +private: + + Floorplan::Floor* floor; + Floorplan::Elevator* elevator; + MV2DElementElevator mv2d; + //MV3DElementElevator mv3d; TODO + +public: + + MMFloorElevator(MapLayer* parent, Floorplan::Floor* floor, Floorplan::Elevator* elevator) : + MapModelElement(parent), floor(floor), elevator(elevator), mv2d(elevator) { + + } + + virtual int getNumParams() const override { + return 3; + } + + virtual Param getParamDesc(const int idx) const override { + switch(idx) { + case 0: return Param("width", ParamType::FLOAT); + case 1: return Param("depth", ParamType::FLOAT); + case 2: return Param("rotation", ParamType::FLOAT); + } + throw 1; + } + + virtual ParamValue getParamValue(const int idx) const override { + switch(idx) { + case 0: return elevator->width; + case 1: return elevator->depth; + case 2: return (elevator->rotation * 180.0f / (float)M_PI); + } + throw 1; + } + + virtual void setParamValue(const int idx, const ParamValue& val) const override { + switch(idx) { + case 0: elevator->width = val.toFloat(); break; + case 1: elevator->depth = val.toFloat(); break; + case 2: elevator->rotation = val.toFloat() / 180.0f * (float)M_PI; break; + } + } + + MV2DElement* getMV2D() const override {return (MV2DElement*) &mv2d;} + MV3DElement* getMV3D() const override {return nullptr;} // TODO + + void deleteMe() const override { + parent->removeElement(this); + floor->elevators.erase(std::remove(floor->elevators.begin(), floor->elevators.end(), elevator), floor->elevators.end()); + } + +}; + +#endif // MMFLOORELEVATOR_H diff --git a/mapview/model/MMFloorElevators.h b/mapview/model/MMFloorElevators.h new file mode 100644 index 0000000..7212d54 --- /dev/null +++ b/mapview/model/MMFloorElevators.h @@ -0,0 +1,47 @@ +#ifndef MMFLOORELEVATORS_H +#define MMFLOORELEVATORS_H + + +#include "MapLayer.h" +#include "MMFloorElevator.h" + +#include + +/** + * layer containing one floor's elevators + */ +class MMFloorElevators : public MapLayer { + +private: + + Floorplan::Floor* floor; + +public: + + /** ctor with the underlying model */ + MMFloorElevators(MapLayer* parent, Floorplan::Floor* floor) : MapLayer(parent, MapLayerType::FLOOR_ELEVATORS), floor(floor) { + + // add all elevators + for (Floorplan::Elevator* elevator : floor->elevators) { + elements.push_back(new MMFloorElevator(this, floor, elevator)); + } + + } + + std::string getLayerName() const override {return "Elevators";} + + //TODO: check + void create(Floorplan::Elevator* elevator) { + + // add to underlying model + floor->elevators.push_back(elevator); + + // add to myself as element + elements.push_back(new MMFloorElevator(this, floor, elevator)); + + } + +}; + + +#endif // MMFLOORELEVATORS_H diff --git a/mapview/model/MapLayer.h b/mapview/model/MapLayer.h index 0166f65..b5be0dc 100644 --- a/mapview/model/MapLayer.h +++ b/mapview/model/MapLayer.h @@ -17,6 +17,7 @@ enum class MapLayerType { FLOOR_OBSTACLES, FLOOR_BEACONS, FLOOR_ACCESS_POINTS, + FLOOR_ELEVATORS, FLOOR_UNDERLAYS, FLOOR_POIS, FLOOR_STAIRS, diff --git a/params/ToolBox.cpp b/params/ToolBox.cpp index 9081eab..080375c 100644 --- a/params/ToolBox.cpp +++ b/params/ToolBox.cpp @@ -57,6 +57,11 @@ ToolBoxWidget::ToolBoxWidget(MapView2D* view, QWidget *parent) : QWidget(parent) lay->addWidget(btnStair, r++, 0, 1,1,Qt::AlignTop); connect(btnStair, SIGNAL(clicked(bool)), this, SLOT(onNewStair())); + btnElevator = new QPushButton(UIHelper::getIcon("elevator"), ""); + btnElevator->setMinimumSize(s,s); + lay->addWidget(btnElevator, r++, 0, 1,1,Qt::AlignTop); + connect(btnElevator, SIGNAL(clicked(bool)), this, SLOT(onNewElevator())); + // TRANSMITTERS btnWifi = new QPushButton(UIHelper::getIcon("wifi"), ""); @@ -100,6 +105,7 @@ void ToolBoxWidget::setSelectedLayer(MapLayer *ml) { btnDoor->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_OBSTACLES)); btnStair->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_STAIRS)); + btnElevator->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_ELEVATORS)); btnWifi->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_ACCESS_POINTS)); btnBeacon->setEnabled(ml && (ml->getLayerType() == MapLayerType::FLOOR_BEACONS)); @@ -491,9 +497,6 @@ void ToolBoxWidget::onNewStair() { const Point2 center = view->getScaler().getCenter(); -// Floorplan::Stair* stair = new Floorplan::StairNormal(center, 0, 0, 3, 2, 6); -// stair->center = center; - Floorplan::StairFreeform* stair = new Floorplan::StairFreeform(); Floorplan::StairPart part(Point3(center.x-3, center.y, 0), Point3(center.x+3, center.y, 3), 3); stair->parts.push_back( part ); @@ -505,6 +508,19 @@ void ToolBoxWidget::onNewStair() { } +void ToolBoxWidget::onNewElevator() { + + const Point2 center = view->getScaler().getCenter(); + + Floorplan::Elevator* elevator = new Floorplan::Elevator(center); + + MMFloorElevators* elevators = (MMFloorElevators*)curLayer; + elevators->create(elevator); + + //view->getModel()->reselect(); + +} + void ToolBoxWidget::onNewAccessPoint() { const Point2 center = view->getScaler().getCenter(); diff --git a/params/ToolBoxWidget.h b/params/ToolBoxWidget.h index a9481bc..be020a9 100644 --- a/params/ToolBoxWidget.h +++ b/params/ToolBoxWidget.h @@ -38,6 +38,7 @@ private: QPushButton* btnPillar; QPushButton* btnDoor; QPushButton* btnStair; + QPushButton* btnElevator; QPushButton* btnWifi; QPushButton* btnBeacon; @@ -54,6 +55,7 @@ private slots: void onNewPillar(); void onNewDoor(); void onNewStair(); + void onNewElevator(); void onNewAccessPoint(); void onNewBeacon(); diff --git a/res.qrc b/res.qrc index 7e03938..73ca53d 100644 --- a/res.qrc +++ b/res.qrc @@ -13,5 +13,6 @@ res/icons/stair.svg res/icons/door.svg res/icons/cursor.svg + res/icons/elevator.svg diff --git a/res/icons/elevator.svg b/res/icons/elevator.svg new file mode 100644 index 0000000..15bf019 --- /dev/null +++ b/res/icons/elevator.svg @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +