current revision
This commit is contained in:
29
Config.h
29
Config.h
@@ -1,29 +0,0 @@
|
|||||||
#ifndef CONFIG_H
|
|
||||||
#define CONFIG_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
class Config {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// notes
|
|
||||||
// copy: scp -P 2222 /tmp/grid.dat kazu@192.168.24.11:/storage/sdcard1/YASMIN/maps/car/
|
|
||||||
// all: scp -P 2222 -r /apps/android/workspace/YASMIN_DATA/* kazu@192.168.24.11:/storage/sdcard1/YASMIN/
|
|
||||||
|
|
||||||
/** get the directory where maps are stored */
|
|
||||||
static inline std::string getMapDir() {
|
|
||||||
#ifdef ANDROID
|
|
||||||
// const std::string folder = getenv("EXTERNAL_STORAGE") + std::string("/YASMIN/maps/"); // this is NOT the sdcard?!
|
|
||||||
// qDebug(folder.c_str());
|
|
||||||
// return folder;
|
|
||||||
return "/storage/sdcard1/YASMIN/maps/";
|
|
||||||
#else
|
|
||||||
return "/apps/android/workspace/YASMIN_DATA/maps/";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // CONFIG_H
|
|
||||||
145
Controller.cpp
145
Controller.cpp
@@ -1,6 +1,8 @@
|
|||||||
#include "Controller.h"
|
#include "Controller.h"
|
||||||
|
|
||||||
#include "ui/map/MapView.h"
|
#include "ui/map/3D/MapView3D.h"
|
||||||
|
#include "ui/map/2D/MapView2D.h"
|
||||||
|
|
||||||
#include "ui/menu/MainMenu.h"
|
#include "ui/menu/MainMenu.h"
|
||||||
#include "ui/MainWindow.h"
|
#include "ui/MainWindow.h"
|
||||||
#include "ui/dialog/LoadSetupDialog.h"
|
#include "ui/dialog/LoadSetupDialog.h"
|
||||||
@@ -11,15 +13,27 @@
|
|||||||
|
|
||||||
#include <Indoor/floorplan/v2/Floorplan.h>
|
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||||
#include <Indoor/floorplan/v2/FloorplanReader.h>
|
#include <Indoor/floorplan/v2/FloorplanReader.h>
|
||||||
|
#include <Indoor/floorplan/v2/FloorplanHelper.h>
|
||||||
|
|
||||||
|
#include <Indoor/sensors/radio/WiFiGridEstimator.h>
|
||||||
|
|
||||||
#include <Indoor/Assertions.h>
|
#include <Indoor/Assertions.h>
|
||||||
|
|
||||||
|
#include "ui/LoggerUI.h"
|
||||||
|
#include <Indoor/misc/log/LoggerComposite.h>
|
||||||
|
#include <Indoor/misc/log/LoggerCOUT.h>
|
||||||
|
#include <Indoor/misc/log/LoggerAndroid.h>
|
||||||
|
|
||||||
|
|
||||||
#include "sensors/dummy/SensorFactoryDummy.h"
|
#include "sensors/dummy/SensorFactoryDummy.h"
|
||||||
#include "sensors/android/SensorFactoryAndroid.h"
|
#include "sensors/android/SensorFactoryAndroid.h"
|
||||||
#include "sensors/offline/SensorFactoryOffline.h"
|
#include "sensors/offline/SensorFactoryOffline.h"
|
||||||
|
|
||||||
|
#include "tools/calibration/WiFiCalibrationDataModel.h"
|
||||||
|
|
||||||
#include "nav/NavController.h"
|
#include "nav/NavController.h"
|
||||||
|
|
||||||
Controller::Controller() {
|
Controller::Controller() : sl(scaler) {
|
||||||
|
|
||||||
// OpenGL setup
|
// OpenGL setup
|
||||||
// MUST happen before anything gets visible (= gets initialized)
|
// MUST happen before anything gets visible (= gets initialized)
|
||||||
@@ -27,50 +41,130 @@ Controller::Controller() {
|
|||||||
format.setDepthBufferSize(16);
|
format.setDepthBufferSize(16);
|
||||||
QSurfaceFormat::setDefaultFormat(format);
|
QSurfaceFormat::setDefaultFormat(format);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// configure the to-be-used sensor factory
|
// configure the to-be-used sensor factory
|
||||||
//SensorFactory::set(new SensorFactoryDummy());
|
//SensorFactory::set(new SensorFactoryDummy());
|
||||||
//SensorFactory::set(new SensorFactoryOffline("/apps/android/workspace/YASMIN_DATA/offline/gyroacctestingfrank/nexus6/kleinerKreis_216steps_6runden_telefongerade.csv"));
|
//SensorFactory::set(new SensorFactoryOffline("/apps/android/workspace/YASMIN_DATA/offline/gyroacctestingfrank/nexus6/kleinerKreis_216steps_6runden_telefongerade.csv"));
|
||||||
//SensorFactory::set(new SensorFactoryOffline("/apps/android/workspace/YASMIN_DATA/offline/gyroacctestingfrank/s3mini/kleinerKreis_225steps_6runden_telefongerade.csv"));
|
//SensorFactory::set(new SensorFactoryOffline("/apps/android/workspace/YASMIN_DATA/offline/gyroacctestingfrank/s3mini/kleinerKreis_225steps_6runden_telefongerade.csv"));
|
||||||
//SensorFactory::set(new SensorFactoryOffline("/apps/android/workspace/YASMIN_DATA/offline/gyroacctestingfrank/s4/kleinerKreis_220steps_6runden_telefongeneigt.csv"));
|
//SensorFactory::set(new SensorFactoryOffline("/apps/android/workspace/YASMIN_DATA/offline/gyroacctestingfrank/s4/kleinerKreis_220steps_6runden_telefongeneigt.csv"));
|
||||||
SensorFactory::set(new SensorFactoryOffline("/apps/android/workspace/YASMIN_DATA/offline/bergwerk/path4/nexus/vor/1454776525797.csv"));
|
|
||||||
|
//SensorFactory::set(new SensorFactoryOffline(Settings::Data::getOfflineDir() + "bergwerk/path3/nexus/vor/1454782562231.csv"));
|
||||||
|
//SensorFactory::set(new SensorFactoryOffline(Settings::Data::getOfflineDir() + "/bergwerk/path4/nexus/rueck/1454776724285_rueck.csv"));
|
||||||
|
SensorFactory::set(new SensorFactoryOffline(Settings::Data::getOfflineDir() + "/bergwerk/path4/nexus/vor/1454776525797.csv"));
|
||||||
|
|
||||||
|
// SensorFactory::set(new SensorFactoryAndroid());
|
||||||
|
// SensorFactory::get().getAccelerometer().start();
|
||||||
|
// SensorFactory::get().getGyroscope().start();
|
||||||
|
// SensorFactory::get().getBarometer().start();
|
||||||
|
// SensorFactory::get().getWiFi().start();
|
||||||
|
|
||||||
|
|
||||||
|
// create the main window
|
||||||
mainWindow = new MainWindow();
|
mainWindow = new MainWindow();
|
||||||
|
|
||||||
|
// attach logger
|
||||||
|
LoggerComposite* log = new LoggerComposite();
|
||||||
|
log->addLogger(new LoggerCOUT());
|
||||||
|
log->addLogger(new LoggerAndroid());
|
||||||
|
log->addLogger(new LoggerUI(mainWindow->getInfoWidget()));
|
||||||
|
Log::setLogger(log);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onLoadButton, this, &Controller::onLoadButton), "connect() failed");
|
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onLoadButton, this, &Controller::onLoadButton), "connect() failed");
|
||||||
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onDebugButton, this, &Controller::onDebugButton), "connect() failed");
|
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onDebugButton, this, &Controller::onDebugButton), "connect() failed");
|
||||||
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onStartButton, this, &Controller::onStartButton), "connect() failed");
|
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onStartButton, this, &Controller::onStartButton), "connect() failed");
|
||||||
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onTransparentButton, this, &Controller::onTransparentButton), "connect() failed");
|
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onTransparentButton, this, &Controller::onTransparentButton), "connect() failed");
|
||||||
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onCameraButton, this, &Controller::onCameraButton), "connect() failed");
|
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::onCameraButton, this, &Controller::onCameraButton), "connect() failed");
|
||||||
|
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::on3DButton, this, &Controller::on3DButton), "connect() failed");
|
||||||
|
|
||||||
// order is important! otherwise OpenGL fails!
|
// order is important! otherwise OpenGL fails!
|
||||||
mainWindow->show();
|
mainWindow->show();
|
||||||
|
|
||||||
|
// // start all sensors
|
||||||
|
// SensorFactory::get().getAccelerometer().start();
|
||||||
|
// SensorFactory::get().getGyroscope().start();
|
||||||
|
// SensorFactory::get().getBarometer().start();
|
||||||
|
// SensorFactory::get().getWiFi().start();
|
||||||
|
|
||||||
|
|
||||||
// start all sensors
|
|
||||||
SensorFactory::get().getAccelerometer().start();
|
|
||||||
SensorFactory::get().getGyroscope().start();
|
|
||||||
SensorFactory::get().getBarometer().start();
|
|
||||||
SensorFactory::get().getWiFi().start();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MapView* Controller::getMapView() const {
|
MapView3D* Controller::getMapView3D() const {
|
||||||
return mainWindow->getMapView();
|
return mainWindow->getMapView3D();
|
||||||
|
}
|
||||||
|
|
||||||
|
MapView2D* Controller::getMapView2D() const {
|
||||||
|
return mainWindow->getMapView2D();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void buildGridOnce(Grid<MyGridNode>* grid, Floorplan::IndoorMap* map, const std::string& saveFile) {
|
MainMenu* Controller::getMainMenu() const {
|
||||||
|
return mainWindow->getMainMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoWidget* Controller::getInfoWidget() const {
|
||||||
|
return mainWindow->getInfoWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <Indoor/sensors/radio/setup/WiFiOptimizer.h>
|
||||||
|
|
||||||
|
void buildGridOnce(Grid<MyGridNode>* grid, Floorplan::IndoorMap* map, const std::string& fpFile, const std::string& saveFile) {
|
||||||
|
//FloorplanHelper::align(map, grid->getGridSize_cm());
|
||||||
|
|
||||||
|
// ask questions
|
||||||
|
const QMessageBox::StandardButton replyWiFiFP = QMessageBox::question(nullptr, "WiFi", "Use Fingerprints for WiFiCalibration?\n\nYes: Use fingerprints and num-optimize AP-Params\nNo: Use APs from the map.xml (pos+params)", QMessageBox::Yes|QMessageBox::No);
|
||||||
|
|
||||||
|
// WiFi setup
|
||||||
|
WiFiModelLogDistCeiling wifiModel(map);
|
||||||
|
if (replyWiFiFP == QMessageBox::Yes) {
|
||||||
|
VAPGrouper vg(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||||
|
WiFiCalibrationDataModel mdl(fpFile);
|
||||||
|
Assert::isFalse(mdl.getFingerprints().empty(), "no fingerprints available!");
|
||||||
|
WiFiOptimizer opt(map, vg);
|
||||||
|
for (const WiFiFingerprint& fp : mdl.getFingerprints()) {
|
||||||
|
opt.addFingerprint(fp);
|
||||||
|
}
|
||||||
|
const std::vector<WiFiOptimizer::APParamsMAC> res = opt.optimizeAll();
|
||||||
|
WiFiGridEstimator::estimate(*grid, wifiModel, Settings::smartphoneAboveGround);
|
||||||
|
for (const WiFiOptimizer::APParamsMAC& ap : res) {
|
||||||
|
const WiFiModelLogDistCeiling::APEntry entry(ap.params.getPos(), ap.params.txp, ap.params.exp, ap.params.waf);
|
||||||
|
wifiModel.addAP(ap.mac, entry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// load all APs from the floorplan and use same TXP/EXP/WAF for all of them
|
||||||
|
wifiModel.loadAPs(map, Settings::WiFiModel::TXP, Settings::WiFiModel::EXP, Settings::WiFiModel::WAF);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// build the grid
|
||||||
GridFactory<MyGridNode> gf(*grid);
|
GridFactory<MyGridNode> gf(*grid);
|
||||||
gf.build(map);
|
gf.build(map);
|
||||||
|
|
||||||
|
// add node-importance
|
||||||
Importance::addImportance(*grid);
|
Importance::addImportance(*grid);
|
||||||
|
|
||||||
|
// stamp WiFi signal-strengths onto the grid
|
||||||
|
WiFiGridEstimator::estimate(*grid, wifiModel, Settings::smartphoneAboveGround);
|
||||||
|
|
||||||
|
// serialize the grid
|
||||||
std::ofstream out(saveFile, std::ofstream::binary);
|
std::ofstream out(saveFile, std::ofstream::binary);
|
||||||
grid->write(out);
|
grid->write(out);
|
||||||
out.close();
|
out.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::on3DButton() {
|
||||||
|
|
||||||
|
static bool use3D = false;
|
||||||
|
use3D = !use3D;
|
||||||
|
|
||||||
|
getMapView2D()->setVisible(!use3D);
|
||||||
|
getMapView3D()->setVisible( use3D);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::onLoadButton() {
|
void Controller::onLoadButton() {
|
||||||
@@ -83,6 +177,7 @@ void Controller::onLoadButton() {
|
|||||||
|
|
||||||
QFile fMap(dir.path() + "/map.xml");
|
QFile fMap(dir.path() + "/map.xml");
|
||||||
QFile fGrid(dir.path() + "/grid.dat");
|
QFile fGrid(dir.path() + "/grid.dat");
|
||||||
|
QFile fWiFiFP(dir.path() + "/wifi_fp.dat");
|
||||||
|
|
||||||
Assert::isTrue(fMap.exists(), "map.xml missing");
|
Assert::isTrue(fMap.exists(), "map.xml missing");
|
||||||
//Assert::isTrue(fGrid.exists(), "grid.dat missing");
|
//Assert::isTrue(fGrid.exists(), "grid.dat missing");
|
||||||
@@ -97,13 +192,15 @@ void Controller::onLoadButton() {
|
|||||||
std::ifstream inp(sGrid, std::ifstream::binary);
|
std::ifstream inp(sGrid, std::ifstream::binary);
|
||||||
//Assert::isTrue(inp.good(), "failed to open grid.dat");
|
//Assert::isTrue(inp.good(), "failed to open grid.dat");
|
||||||
|
|
||||||
|
const std::string sWiFiFP = fWiFiFP.fileName().toStdString();
|
||||||
|
|
||||||
// create a new, empty grid
|
// create a new, empty grid
|
||||||
if (grid) {delete grid; grid = nullptr;}
|
if (grid) {delete grid; grid = nullptr;}
|
||||||
grid = new Grid<MyGridNode>(20);
|
grid = new Grid<MyGridNode>(Settings::Grid::gridSize_cm);
|
||||||
|
|
||||||
// grid.dat empty? -> build one and save it
|
// grid.dat empty? -> build one and save it
|
||||||
if (!inp.good() || (inp.peek()&&0) || inp.eof()) {
|
if (!inp.good() || (inp.peek()&&0) || inp.eof()) {
|
||||||
buildGridOnce(grid, im, sGrid);
|
buildGridOnce(grid, im, sWiFiFP, sGrid);
|
||||||
} else {
|
} else {
|
||||||
grid->read(inp);
|
grid->read(inp);
|
||||||
}
|
}
|
||||||
@@ -112,8 +209,18 @@ void Controller::onLoadButton() {
|
|||||||
if (nav) {delete nav; nav = nullptr;}
|
if (nav) {delete nav; nav = nullptr;}
|
||||||
nav = new NavController(this, grid, im);
|
nav = new NavController(this, grid, im);
|
||||||
|
|
||||||
getMapView()->setMap(im);
|
WiFiCalibrationDataModel* wifiCalib = new WiFiCalibrationDataModel(sWiFiFP);
|
||||||
getMapView()->showGridImportance(grid);
|
|
||||||
|
getMapView3D()->setMap(im);
|
||||||
|
getMapView2D()->setMap(wifiCalib, im);
|
||||||
|
|
||||||
|
getMapView3D()->showGridImportance(grid);
|
||||||
|
getMapView2D()->showGridImportance(grid);
|
||||||
|
|
||||||
|
getMapView3D()->setVisible(false);
|
||||||
|
|
||||||
|
// attach ipin step logger
|
||||||
|
nav->addListener(&sl);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -127,7 +234,7 @@ void Controller::onStartButton() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Controller::onTransparentButton() {
|
void Controller::onTransparentButton() {
|
||||||
mainWindow->getMapView()->toggleRenderMode();
|
mainWindow->getMapView3D()->toggleRenderMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::onCameraButton() {
|
void Controller::onCameraButton() {
|
||||||
|
|||||||
23
Controller.h
23
Controller.h
@@ -1,6 +1,11 @@
|
|||||||
#ifndef CONTROLLER_H
|
#ifndef CONTROLLER_H
|
||||||
#define CONTROLLER_H
|
#define CONTROLLER_H
|
||||||
|
|
||||||
|
#include "misc/fixc11.h"
|
||||||
|
#include "ipin/Scaler.h"
|
||||||
|
#include "ipin/StepLoggerWrapper.h"
|
||||||
|
#include "ipin/StepLoggerWrapperAndroid.h"
|
||||||
|
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
class MainMenu;
|
class MainMenu;
|
||||||
class MapView;
|
class MapView;
|
||||||
@@ -10,6 +15,9 @@ class NavController;
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
template <typename T> class Grid;
|
template <typename T> class Grid;
|
||||||
class MyGridNode;
|
class MyGridNode;
|
||||||
|
class InfoWidget;
|
||||||
|
class MapView3D;
|
||||||
|
class MapView2D;
|
||||||
|
|
||||||
namespace Floorplan {
|
namespace Floorplan {
|
||||||
class IndoorMap;
|
class IndoorMap;
|
||||||
@@ -26,7 +34,19 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MapView* getMapView() const;
|
MapView3D* getMapView3D() const;
|
||||||
|
MapView2D* getMapView2D() const;
|
||||||
|
|
||||||
|
MainMenu* getMainMenu() const;
|
||||||
|
InfoWidget* getInfoWidget() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// scaling for the UAH building
|
||||||
|
IPINScaler scaler = IPINScaler(1869, 1869, 40.51312440, -3.34959080, -40.73112000, 0.07596002);
|
||||||
|
//StepLoggerWrapper sl;
|
||||||
|
StepLoggerWrapperAndroid sl;
|
||||||
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
@@ -36,6 +56,7 @@ private slots:
|
|||||||
|
|
||||||
void onTransparentButton();
|
void onTransparentButton();
|
||||||
void onCameraButton();
|
void onCameraButton();
|
||||||
|
void on3DButton();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
83
Settings.h
83
Settings.h
@@ -2,27 +2,88 @@
|
|||||||
#define SETTINGS_H
|
#define SETTINGS_H
|
||||||
|
|
||||||
#include <Indoor/grid/GridPoint.h>
|
#include <Indoor/grid/GridPoint.h>
|
||||||
|
#include <Indoor/data/Timestamp.h>
|
||||||
|
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
namespace Settings {
|
namespace Settings {
|
||||||
|
|
||||||
const int numParticles = 3000;
|
const int numParticles = 2000;
|
||||||
|
|
||||||
const float turnSigma = 3.5;
|
namespace IMU {
|
||||||
|
const float turnSigma = 1.5; // 3.5
|
||||||
const float stepLength = 0.80;
|
const float stepLength = 0.80;
|
||||||
const float stepSigma = 0.1;
|
const float stepSigma = 0.10;
|
||||||
|
}
|
||||||
|
|
||||||
const float smartphoneAboveGround = 1.3;
|
const float smartphoneAboveGround = 1.3;
|
||||||
|
|
||||||
const float offlineSensorSpeedup = 2.5;
|
const float offlineSensorSpeedup = 2;
|
||||||
|
|
||||||
|
namespace Grid {
|
||||||
|
constexpr int gridSize_cm = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const GridPoint destination = GridPoint(70*100, 35*100, 0*100);
|
//const GridPoint destination = GridPoint(70*100, 35*100, 0*100); // use destination
|
||||||
|
const GridPoint destination = GridPoint(0,0,0); // do not use destination
|
||||||
|
|
||||||
const float wifiSigma = 9.0;
|
namespace SensorDebug {
|
||||||
const float wifiTXP = -48;
|
const Timestamp updateEvery = Timestamp::fromMS(200);
|
||||||
const float wifiEXP = 2.5;
|
}
|
||||||
const float wifiWAF = -9.0;
|
|
||||||
|
namespace WiFiModel {
|
||||||
|
constexpr float sigma = 11.0;
|
||||||
|
/** if the wifi-signal-strengths are stored on the grid-nodes, this needs a grid rebuild! */
|
||||||
|
constexpr float TXP = -48;
|
||||||
|
constexpr float EXP = 2.5;
|
||||||
|
constexpr float WAF = -5.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace MapView {
|
||||||
|
constexpr int fps = 15;
|
||||||
|
const Timestamp msPerFrame = Timestamp::fromMS(1000/fps);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Filter {
|
||||||
|
const Timestamp updateEvery = Timestamp::fromMS(500);
|
||||||
|
constexpr bool useMainThread = false; // perform filtering in the main thread
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
|
||||||
|
// notes
|
||||||
|
// copy: scp -P 2222 /tmp/grid.dat kazu@192.168.24.11:/storage/sdcard1/YASMIN/maps/car/
|
||||||
|
// all: scp -P 2222 -r /apps/android/workspace/YASMIN_DATA/* kazu@192.168.24.11:/storage/sdcard1/YASMIN/
|
||||||
|
|
||||||
|
static inline std::string getRoot() {
|
||||||
|
#ifdef ANDROID
|
||||||
|
// const std::string folder = getenv("EXTERNAL_STORAGE") + std::string("/YASMIN/maps/"); // this is NOT the sdcard?!
|
||||||
|
// qDebug(folder.c_str());
|
||||||
|
// return folder;
|
||||||
|
//return "/storage/sdcard1/YASMIN/";
|
||||||
|
std::string f1 = "/storage/sdcard1/YASMIN/";
|
||||||
|
std::string f2 = "/sdcard/YASMIN/";
|
||||||
|
if (QFile(f1.c_str()).exists()) {return f1;}
|
||||||
|
if (QFile(f2.c_str()).exists()) {return f2;}
|
||||||
|
throw Exception("data folder missing");
|
||||||
|
#else
|
||||||
|
return "/apps/android/workspace/YASMIN_DATA/";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get the directory where maps are stored */
|
||||||
|
static inline std::string getMapDir() {
|
||||||
|
return getRoot() + "maps/";
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline std::string getOfflineDir() {
|
||||||
|
return getRoot() + "offline/";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,18 @@ public class MyActivity extends QtActivity {
|
|||||||
|
|
||||||
public static MyActivity act;
|
public static MyActivity act;
|
||||||
|
|
||||||
|
// IPIN2016
|
||||||
|
private StepLoggerClient stepLogger;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedState) {
|
public void onCreate(Bundle savedState) {
|
||||||
MyActivity.act = this;
|
MyActivity.act = this;
|
||||||
super.onCreate(savedState);
|
super.onCreate(savedState);
|
||||||
|
|
||||||
|
// IPIN2016
|
||||||
|
stepLogger = new StepLoggerClient(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
79
_android/src/StepLoggerClient.java
Normal file
79
_android/src/StepLoggerClient.java
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
package indoor.java;
|
||||||
|
|
||||||
|
import android.app.IntentService;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
|
||||||
|
import it.cnr.isti.steplogger.IStepLoggerService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link IntentService} subclass for handling asynchronous task requests in
|
||||||
|
* a service on a separate handler thread.
|
||||||
|
*/
|
||||||
|
public class StepLoggerClient {
|
||||||
|
|
||||||
|
private static StepLoggerClient instance;
|
||||||
|
|
||||||
|
// Intent Service fields
|
||||||
|
private static String LOG_TAG = "StepLoggerClient";
|
||||||
|
private boolean mustRun = true;
|
||||||
|
|
||||||
|
// Bound Service fields
|
||||||
|
final String BOUNDSERVICE_PACKAGE = "it.cnr.isti.steplogger";
|
||||||
|
final String BOUNDSERVICE_CLASS = ".StepLoggerService";
|
||||||
|
IStepLoggerService mService;
|
||||||
|
|
||||||
|
Boolean isBound = false;
|
||||||
|
Intent intentService = new Intent();
|
||||||
|
|
||||||
|
//Bound Service Connection
|
||||||
|
private ServiceConnection mConnection = new ServiceConnection() {
|
||||||
|
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder boundService) {
|
||||||
|
mService = IStepLoggerService.Stub.asInterface((IBinder) boundService);
|
||||||
|
Log.d(LOG_TAG, "onServiceConnected() : OK ");
|
||||||
|
isBound = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
mService = null;
|
||||||
|
Log.d(LOG_TAG, "onServiceDisconnected() : OK ");
|
||||||
|
isBound = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
public StepLoggerClient(MyActivity act) {
|
||||||
|
|
||||||
|
instance = this;
|
||||||
|
|
||||||
|
intentService.setClassName(BOUNDSERVICE_PACKAGE, BOUNDSERVICE_PACKAGE + BOUNDSERVICE_CLASS);
|
||||||
|
act.bindService(intentService, mConnection , Context.BIND_AUTO_CREATE );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** static access from C++ */
|
||||||
|
public static int log(double x, double y, double z) {
|
||||||
|
Log.d("me", "got values");
|
||||||
|
instance._log(x,y,z);
|
||||||
|
return 1337; // return a magic-code that is checked within c++
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _log(double x, double y, double z) {
|
||||||
|
Log.d("me", mService + "");
|
||||||
|
if (mService == null) {return;}
|
||||||
|
try {
|
||||||
|
mService.logPosition(System.currentTimeMillis(), x, y, z);
|
||||||
|
} catch (final Exception e) {;}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -34,13 +34,13 @@ public class WiFi {
|
|||||||
MyActivity act = MyActivity.act;
|
MyActivity act = MyActivity.act;
|
||||||
manager = (WifiManager) act.getSystemService(Context.WIFI_SERVICE);
|
manager = (WifiManager) act.getSystemService(Context.WIFI_SERVICE);
|
||||||
|
|
||||||
reset();
|
// reset();
|
||||||
|
|
||||||
WiFi.receiver = new BroadcastReceiver() {
|
WiFi.receiver = new BroadcastReceiver() {
|
||||||
public final void onReceive(final Context context, final Intent intent) {
|
public final void onReceive(final Context context, final Intent intent) {
|
||||||
final byte[] result = serialize(manager.getScanResults());
|
final byte[] result = serialize(manager.getScanResults());
|
||||||
|
triggerOneScan();
|
||||||
WiFi.onScanComplete(result);
|
WiFi.onScanComplete(result);
|
||||||
triggerOneScan();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// IMisuratoreService.aidl
|
||||||
|
package it.cnr.isti.steplogger;
|
||||||
|
|
||||||
|
// Declare any non-default types here with import statements
|
||||||
|
|
||||||
|
interface IStepLoggerService {
|
||||||
|
void logPosition(in long timestamp, in double x, in double y, in double z);
|
||||||
|
}
|
||||||
104
ipin/Config.h
Normal file
104
ipin/Config.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#ifndef EVALCONFIG_H
|
||||||
|
#define EVALCONFIG_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "IPINHelper.h"
|
||||||
|
|
||||||
|
class EvalConfig {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::unordered_map<std::string, std::string> keyVal;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
EvalConfig() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get the value for the given key */
|
||||||
|
const std::string& get(const std::string& key) {
|
||||||
|
static std::string empty = "";
|
||||||
|
auto it = keyVal.find(key);
|
||||||
|
return (it == keyVal.end()) ? (empty) : (it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** load the given configuration file */
|
||||||
|
void load(const std::string& file) {
|
||||||
|
|
||||||
|
std::ifstream inp(file);
|
||||||
|
|
||||||
|
if (!inp.good()) {throw "error while opening config file " + file;}
|
||||||
|
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::string tmp;
|
||||||
|
while (!inp.eof()) {
|
||||||
|
|
||||||
|
// read the next line (might be empty)
|
||||||
|
std::getline(inp, tmp);
|
||||||
|
if (tmp.empty()) {continue;}
|
||||||
|
|
||||||
|
// in case of \r\n linebreaks, remove the remaining \r (might hereafter be empty)
|
||||||
|
if (tmp.back() == '\r') {tmp.erase(tmp.end()-1);}
|
||||||
|
if (tmp.empty()) {continue;}
|
||||||
|
|
||||||
|
// multiline?
|
||||||
|
bool multiline = false;
|
||||||
|
if (tmp.back() == '\\') {multiline = true; tmp.erase(tmp.end()-1);}
|
||||||
|
|
||||||
|
// attach
|
||||||
|
line += tmp;
|
||||||
|
|
||||||
|
// complete line? -> parse it
|
||||||
|
if (!multiline) {parse(line); line = "";}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// trailing data
|
||||||
|
parse(line);
|
||||||
|
|
||||||
|
inp.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** parse one line */
|
||||||
|
void parse(const std::string& line) {
|
||||||
|
|
||||||
|
// check
|
||||||
|
if (line.empty()) {return;}
|
||||||
|
if (line.front() == '[') {return;}
|
||||||
|
|
||||||
|
// split key and value
|
||||||
|
const size_t pos = line.find(" = ");
|
||||||
|
if (pos == std::string::npos) {throw "something wrong";}
|
||||||
|
|
||||||
|
const std::string key = line.substr(0, pos);
|
||||||
|
const std::string val = line.substr(pos+3);
|
||||||
|
|
||||||
|
// add
|
||||||
|
keyVal[key] = val;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get the eval config.ini filename */
|
||||||
|
std::string getConfigFile() const {
|
||||||
|
|
||||||
|
const std::string folder = IPINHelper::getDataFolder();
|
||||||
|
const std::string file = folder + "it.cnr.isti.steplogger.config.ini";
|
||||||
|
return file;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EVALCONFIG_H
|
||||||
22
ipin/IPINHelper.h
Normal file
22
ipin/IPINHelper.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef IPINHELPER_H
|
||||||
|
#define IPINHELPER_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
class IPINHelper {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** get the StepLogger data folder */
|
||||||
|
static std::string getDataFolder() {
|
||||||
|
|
||||||
|
#ifdef ANDROID
|
||||||
|
return getenv("DIRECTORY_DOWNLOADS");
|
||||||
|
#else
|
||||||
|
return "/apps/android/workspace/YASMIN_DATA/";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IPINHELPER_H
|
||||||
104
ipin/Scaler.h
Normal file
104
ipin/Scaler.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#ifndef IPIN_SCALER_H
|
||||||
|
#define IPIN_SCALER_H
|
||||||
|
|
||||||
|
#include <Indoor/geo/Point2.h>
|
||||||
|
#include <Indoor/geo/Point3.h>
|
||||||
|
|
||||||
|
struct IPIN {
|
||||||
|
double lat;
|
||||||
|
double lon;
|
||||||
|
double floorNr;
|
||||||
|
IPIN(const double lat, const double lon, const double floorNr) : lat(lat), lon(lon), floorNr(floorNr) {;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPINScaler {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int w;
|
||||||
|
int h;
|
||||||
|
double cenLat;
|
||||||
|
double cenLon;
|
||||||
|
double rotDeg;
|
||||||
|
double mPerPx;
|
||||||
|
|
||||||
|
Point2 mapCenter_m;
|
||||||
|
|
||||||
|
double refLat;
|
||||||
|
double m_per_deg_lat;
|
||||||
|
double m_per_deg_lon;
|
||||||
|
|
||||||
|
const float fixedFloorHeight = 4.0f;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
/** image width, image height, map-center (lat/lon), map-rotation, meter<->pixel conversion factor */
|
||||||
|
IPINScaler(int w, int h, double cenLat, double cenLon, double rotDeg, double mPerPx) : w(w), h(h), cenLat(cenLat), cenLon(cenLon), rotDeg(rotDeg), mPerPx(mPerPx) {
|
||||||
|
|
||||||
|
mapCenter_m = Point2( (w*mPerPx/2), (h*mPerPx/2) );
|
||||||
|
|
||||||
|
refLat = cenLat / 180.0 * M_PI;
|
||||||
|
m_per_deg_lat = 111132.954 - 559.822 * std::cos( 2.0 * refLat ) + 1.175 * std::cos( 4.0 * refLat);
|
||||||
|
m_per_deg_lon = 111132.954 * std::cos ( refLat );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** convert from (x,y,z) to (lat,lon,floorNr) */
|
||||||
|
IPIN toIPIN3(const float x, const float y, const float z) const {
|
||||||
|
|
||||||
|
Point2 pos(x,y);
|
||||||
|
|
||||||
|
// move to (0,0)
|
||||||
|
pos -= mapCenter_m;
|
||||||
|
|
||||||
|
// undo the rotation
|
||||||
|
pos = pos.rotated(-rotDeg / 180 * M_PI);
|
||||||
|
|
||||||
|
const double lat = cenLat + (pos.y / m_per_deg_lat);
|
||||||
|
const double lon = cenLon + (pos.x / m_per_deg_lon);
|
||||||
|
const double floorNr = z / fixedFloorHeight;
|
||||||
|
|
||||||
|
return IPIN(lat, lon, floorNr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
IPIN toIPIN3(const Point3 p) const {
|
||||||
|
return toIPIN3(p.x, p.y, p.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3 convert3D(const IPIN& ipin) const {
|
||||||
|
return convert3D(ipin.lat, ipin.lon, ipin.floorNr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3 convert3D(double lat, double lon, float floorNr) const {
|
||||||
|
|
||||||
|
Point2 p2 = convert2D(lat, lon);
|
||||||
|
|
||||||
|
return Point3(p2.x, p2.y, floorNr * fixedFloorHeight);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2 convert2D(double lat, double lon) const {
|
||||||
|
|
||||||
|
const double y_m = +(lat-cenLat) * m_per_deg_lat;
|
||||||
|
const double x_m = +(lon-cenLon) * m_per_deg_lon;
|
||||||
|
|
||||||
|
// rotate (our map is axis aligned)
|
||||||
|
Point2 pos(x_m, y_m);
|
||||||
|
pos = pos.rotated(rotDeg / 180 * M_PI);
|
||||||
|
|
||||||
|
// apply movement
|
||||||
|
pos += mapCenter_m;
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // IPIN_SCALER_H
|
||||||
188
ipin/StepLogger.h
Normal file
188
ipin/StepLogger.h
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
#ifndef STEPLOGGER_H
|
||||||
|
#define STEPLOGGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <Indoor/data/Timestamp.h>
|
||||||
|
#include "Scaler.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include "IPINHelper.h"
|
||||||
|
|
||||||
|
class StepLogger {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
EvalConfig cfg;
|
||||||
|
std::string configFile;
|
||||||
|
std::string competitorID = "navindoor";
|
||||||
|
|
||||||
|
|
||||||
|
std::ofstream outButtons;
|
||||||
|
std::ofstream outPositions;
|
||||||
|
|
||||||
|
/** all step-logger wayponts defined within the config file */
|
||||||
|
std::vector<std::string> waypoints;
|
||||||
|
int curWP = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor with the map<->world scaler */
|
||||||
|
StepLogger() {
|
||||||
|
loadConfig();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** log current timestamp + waypoint and proceed with the next one */
|
||||||
|
void onButtonPress() {
|
||||||
|
|
||||||
|
// sanity check
|
||||||
|
if (isDone()) {throw "all waypoints were processed";}
|
||||||
|
|
||||||
|
// construct output string
|
||||||
|
std::stringstream ss;
|
||||||
|
std::string wpEntry = waypoints[curWP]; ++curWP;
|
||||||
|
wpEntry = replace(wpEntry, ":" , " : ");
|
||||||
|
ss << Timestamp::fromUnixTime().ms() << " : " << wpEntry << "\r\n";
|
||||||
|
|
||||||
|
// log
|
||||||
|
std::cout << ss.str() << std::flush;
|
||||||
|
outButtons << ss.str(); outButtons.flush();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** all waypoints done? */
|
||||||
|
bool isDone() const {
|
||||||
|
return curWP >= (int)waypoints.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** log our map-relative format */
|
||||||
|
void onNewEstimation(const double lat, const double lon, const double floorNr) {
|
||||||
|
|
||||||
|
// construct output string
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << Timestamp::fromUnixTime().ms() << " : " << lat << " : " << lon << " : " << floorNr << "\r\n";
|
||||||
|
|
||||||
|
// log
|
||||||
|
std::cout << ss.str() << std::endl;
|
||||||
|
outPositions << ss.str(); outPositions.flush();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get the current waypoint's number, starting at 0 */
|
||||||
|
int getCurrentWaypointNumber() const {
|
||||||
|
return curWP;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** split the given string */
|
||||||
|
std::vector<std::string> split(const std::string& str, const char delim) {
|
||||||
|
std::vector<std::string> res;
|
||||||
|
int start = 0;
|
||||||
|
while (true) {
|
||||||
|
size_t pos = str.find(delim, start);
|
||||||
|
if (pos == std::string::npos) {break;}
|
||||||
|
const std::string sub = str.substr(start, pos-start);
|
||||||
|
res.push_back(sub);
|
||||||
|
start = pos + 1;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** string replacement helper */
|
||||||
|
std::string replace(std::string str, const std::string& from, const std::string& to) {
|
||||||
|
size_t start_pos = 0;
|
||||||
|
while((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
||||||
|
str.replace(start_pos, from.length(), to);
|
||||||
|
start_pos += to.length();
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get the current time as [YYYYMMDD]T[HHMMSS] */
|
||||||
|
std::string getDate() const {
|
||||||
|
const char* format = "%Y%m%dT%H%m%S";
|
||||||
|
std::time_t t = std::time(nullptr);
|
||||||
|
struct tm* tt = std::localtime(&t);
|
||||||
|
|
||||||
|
char buf[128];
|
||||||
|
strftime(buf, 128, format, tt);
|
||||||
|
return std::string(buf);
|
||||||
|
|
||||||
|
// std::stringstream ss;
|
||||||
|
// ss << std::put_time(tt, format);
|
||||||
|
// return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** load the config.ini and parse the waypoints */
|
||||||
|
void loadConfig() {
|
||||||
|
cfg.load(IPINHelper::getDataFolder() + "it.cnr.isti.steplogger.config.ini");
|
||||||
|
const std::string tmp = cfg.get("counter");
|
||||||
|
waypoints = split(tmp, ',');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** create the data-folder, open the two output files and perform sanity checks */
|
||||||
|
void start() {
|
||||||
|
|
||||||
|
// get the output data folder and construct filenames
|
||||||
|
const std::string folder = getOutputFolder();
|
||||||
|
const std::string fBtn = folder + "buttonsPressed.log";
|
||||||
|
const std::string fPos = folder + "positions.log";
|
||||||
|
|
||||||
|
// open two output files
|
||||||
|
outButtons.open(fBtn); if (!outButtons.good()) {throw "error while creating file";}
|
||||||
|
outPositions.open(fPos); if (!outPositions.good()) {throw "error while creating file";}
|
||||||
|
|
||||||
|
// reset current WayPoint
|
||||||
|
curWP = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** get a DateTime dependent data folder */
|
||||||
|
std::string getOutputFolder() {
|
||||||
|
const std::string& folder = IPINHelper::getDataFolder();
|
||||||
|
const std::string date = getDate();
|
||||||
|
const std::string sub = folder + date + "_" + competitorID + "/";
|
||||||
|
mkdir(sub.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||||
|
return sub;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// // config file
|
||||||
|
// Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) +
|
||||||
|
// File.separator +
|
||||||
|
// "it.cnr.isti.steplogger.config.ini";
|
||||||
|
|
||||||
|
// buttonsPressed.log
|
||||||
|
// milliseconds " : " number-starting-at-1" : "???" : "???" : "floor? // see configFile config.ini
|
||||||
|
// java current time millis
|
||||||
|
// positions.log
|
||||||
|
// timestamp " " x " " y " " z
|
||||||
|
|
||||||
|
// storage/sdcard0/Download/it.cnr.isti.steplogger/
|
||||||
|
|
||||||
|
// Within the folder it.cnr.isti.steplogger/ StepLogger creates a folder for every measurement session, the logs are placed in folder whose name follows this convention:
|
||||||
|
|
||||||
|
// [YearMonthDay]T[HourMinutesSeconds][Competitor ID]
|
||||||
|
// // Coordinates will need to be in the WGS84 coordinate system (longitude and latitude) for x, y,
|
||||||
|
// //and the number of floor (an integer starting from 0) for z.
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // STEPLOGGER_H
|
||||||
97
ipin/StepLoggerWrapper.h
Normal file
97
ipin/StepLoggerWrapper.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#ifndef STEPLOGGERWRAPPER_H
|
||||||
|
#define STEPLOGGERWRAPPER_H
|
||||||
|
|
||||||
|
#include "Scaler.h"
|
||||||
|
#include "StepLogger.h"
|
||||||
|
#include "../nav/NavControllerListener.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QWindow>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QDesktopWidget>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper class to connect our NavigationController with the StepLogger
|
||||||
|
*/
|
||||||
|
class StepLoggerWrapper : public StepLogger, public NavControllerListener {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** convert from our position-format to ipin position-format */
|
||||||
|
IPINScaler& scaler;
|
||||||
|
|
||||||
|
QMainWindow* window;
|
||||||
|
QPushButton* btn;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
StepLoggerWrapper(IPINScaler& scaler) : scaler(scaler) {
|
||||||
|
setupUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event fired every 500ms from the navigation controller.
|
||||||
|
* convert from our format to IPIN format
|
||||||
|
* and pass it to the logger
|
||||||
|
*/
|
||||||
|
void onNewEstimation(const Point3 pos_m) override {
|
||||||
|
|
||||||
|
// convert from our coordinate system (meter relative to (0,0,0)) to the WGS84 format
|
||||||
|
const IPIN ipin = scaler.toIPIN3(pos_m);
|
||||||
|
|
||||||
|
// inform the logger
|
||||||
|
StepLogger::onNewEstimation(ipin.lat, ipin.lon, ipin.floorNr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** create a clickable check button */
|
||||||
|
void setupUI() {
|
||||||
|
|
||||||
|
window = new QMainWindow();
|
||||||
|
//window->setTitle("StepLogger");
|
||||||
|
btn = new QPushButton(window);
|
||||||
|
|
||||||
|
// almost fullscreen
|
||||||
|
QRect geom = QDesktopWidget().availableGeometry();
|
||||||
|
const int w = geom.width() * 0.9;
|
||||||
|
const int h = geom.height() * 0.6;
|
||||||
|
|
||||||
|
// center and set always-on-top
|
||||||
|
window->setGeometry(geom.width()/2 - w/2, geom.height()/2 - h/2, w, h);
|
||||||
|
const Qt::WindowFlags flags = window->windowFlags();
|
||||||
|
window->setWindowFlags(flags | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint);
|
||||||
|
|
||||||
|
|
||||||
|
btn->setGeometry(5,5,w-5-5,h-5-5);
|
||||||
|
window->show();
|
||||||
|
|
||||||
|
// button clicked -> next waypoint
|
||||||
|
btn->connect(btn, &QPushButton::clicked, [&] () {
|
||||||
|
StepLogger::onButtonPress();
|
||||||
|
updateButton();
|
||||||
|
});
|
||||||
|
|
||||||
|
// show the current waypoint
|
||||||
|
updateButton();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** update the current button label */
|
||||||
|
void updateButton() {
|
||||||
|
|
||||||
|
// show the number of the next waypoint
|
||||||
|
const int nr = getCurrentWaypointNumber() + 1;
|
||||||
|
btn->setText(QString::number(nr));
|
||||||
|
|
||||||
|
// button is visible when we are not yet done
|
||||||
|
btn->setVisible(!StepLogger::isDone());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // STEPLOGGERWRAPPER_H
|
||||||
61
ipin/StepLoggerWrapperAndroid.h
Normal file
61
ipin/StepLoggerWrapperAndroid.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#ifndef STEPLOGGERWRAPPERANDROID_H
|
||||||
|
#define STEPLOGGERWRAPPERANDROID_H
|
||||||
|
|
||||||
|
#include "Scaler.h"
|
||||||
|
#include "../nav/NavControllerListener.h"
|
||||||
|
#include <Indoor/misc/Debug.h>
|
||||||
|
|
||||||
|
#ifdef Android
|
||||||
|
#include <QtAndroidExtras>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sends the position-estimation-result to the step-logger service
|
||||||
|
*/
|
||||||
|
class StepLoggerWrapperAndroid : public NavControllerListener {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** convert from our position-format to ipin position-format */
|
||||||
|
IPINScaler& scaler;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
StepLoggerWrapperAndroid(IPINScaler& scaler) : scaler(scaler) {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* event fired every 500ms from the navigation controller.
|
||||||
|
* convert from our format to IPIN format
|
||||||
|
* and pass it to the logger
|
||||||
|
*/
|
||||||
|
void onNewEstimation(const Point3 pos_m) override {
|
||||||
|
|
||||||
|
// convert from our coordinate system (meter relative to (0,0,0)) to the WGS84 format
|
||||||
|
const IPIN ipin = scaler.toIPIN3(pos_m);
|
||||||
|
|
||||||
|
// inform the logger
|
||||||
|
log(ipin.lon, ipin.lat, ipin.floorNr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** call java */
|
||||||
|
void log(const double x, const double y, const double z) {
|
||||||
|
|
||||||
|
#ifdef Android
|
||||||
|
Log::add("SLWA", "calling android with lon/lat/floor");
|
||||||
|
int res = QAndroidJniObject::callStaticMethod<int>("indoor/java/StepLoggerClient", "log", "(DDD)I", x, y, z);
|
||||||
|
if (res != 1337) {throw Exception("error while logging");}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // STEPLOGGERWRAPPERANDROID_H
|
||||||
2467
lib/tinyxml/tinyxml2.cpp
Normal file
2467
lib/tinyxml/tinyxml2.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2102
lib/tinyxml/tinyxml2.h
Normal file
2102
lib/tinyxml/tinyxml2.h
Normal file
File diff suppressed because it is too large
Load Diff
68
main.cpp
68
main.cpp
@@ -1,75 +1,31 @@
|
|||||||
#include <misc/fixc11.h>
|
#include <misc/fixc11.h>
|
||||||
|
|
||||||
#include <QGuiApplication>
|
//#include <QGuiApplication>
|
||||||
#include <QQmlApplicationEngine>
|
//#include <QQmlApplicationEngine>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMainWindow>
|
|
||||||
#include <QGridLayout>
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include <Indoor/math/Interpolator.h>
|
|
||||||
#include <Indoor/grid/factory/v2/Importance.h>
|
|
||||||
|
|
||||||
#include <Indoor/nav/dijkstra/Dijkstra.h>
|
|
||||||
#include <Indoor/nav/dijkstra/DijkstraPath.h>
|
|
||||||
|
|
||||||
#include "sensors/SensorFactory.h"
|
|
||||||
#include "Controller.h"
|
#include "Controller.h"
|
||||||
#include "ui/map/MapView.h"
|
#include "ui/map/3D/MapView3D.h"
|
||||||
|
|
||||||
#include <iostream>
|
#include "tests/RuntimeTests.h"
|
||||||
|
|
||||||
#include <Indoor/floorplan/v2/FloorplanReader.h>
|
|
||||||
#include <Indoor/api/DummyAPI.h>
|
|
||||||
#include <Indoor/sensors/radio/WiFiGridNode.h>
|
|
||||||
#include <Indoor/sensors/radio/WiFiGridEstimator.h>
|
|
||||||
#include <Indoor/sensors/radio/model/WiFiModelLogDist.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct MyNode : public GridPoint, public GridNode, public WiFiGridNode<10> {
|
|
||||||
|
|
||||||
float navImportance;
|
|
||||||
MyNode() {;}
|
|
||||||
MyNode(const float x_cm, const float y_cm, const float z_cm) : GridPoint(x_cm, y_cm, z_cm) {;}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static void staticSerialize(std::ostream& out) {
|
|
||||||
WiFiGridNode::staticSerialize(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void staticDeserialize(std::istream& inp) {
|
|
||||||
WiFiGridNode::staticDeserialize(inp);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
|
||||||
|
RuntimeTests::run();
|
||||||
|
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
std::cout << "resampling mit streuung? z.B in nachbar nodes?";
|
||||||
|
std::cout << "gerade am anfang geht seeehr viel verloren";
|
||||||
|
|
||||||
Controller ctrl;
|
Controller ctrl;
|
||||||
|
|
||||||
Point3 eye(40,42,1.8);
|
Point3 eye(40,42,1.8);
|
||||||
ctrl.getMapView()->setLookEye(eye);
|
ctrl.getMapView3D()->setLookEye(eye);
|
||||||
ctrl.getMapView()->setLookDir(Point3(-1, 0, -0.1));
|
ctrl.getMapView3D()->setLookDir(Point3(-1, 0, -0.1));
|
||||||
|
|
||||||
|
|
||||||
// auto run = [&] () {
|
|
||||||
// static float r = 0;
|
|
||||||
// while(true) {
|
|
||||||
// r += 0.01;
|
|
||||||
// eye += Point3(-0.01, 0, 0);
|
|
||||||
// ctrl.getMapView()->setLookEye(eye);
|
|
||||||
// usleep(1000*50);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
// std::thread t(run);
|
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
|
|
||||||
|
|||||||
150
nav/Filter.h
150
nav/Filter.h
@@ -12,18 +12,21 @@
|
|||||||
#include <Indoor/sensors/radio/WiFiProbabilityFree.h>
|
#include <Indoor/sensors/radio/WiFiProbabilityFree.h>
|
||||||
#include <Indoor/sensors/radio/model/WiFiModelLogDistCeiling.h>
|
#include <Indoor/sensors/radio/model/WiFiModelLogDistCeiling.h>
|
||||||
#include <Indoor/sensors/radio/WiFiProbabilityFree.h>
|
#include <Indoor/sensors/radio/WiFiProbabilityFree.h>
|
||||||
|
#include <Indoor/sensors/radio/WiFiProbabilityGrid.h>
|
||||||
|
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleHeadingControl.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleHeadingControl.h>
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleNodeImportance.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleNodeImportance.h>
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleFavorZ.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleFavorZ.h>
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleButterActivity.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleActivityControl.h>
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleFollowDestination.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleFollowDestination.h>
|
||||||
|
|
||||||
#include "State.h"
|
#include "State.h"
|
||||||
#include "Node.h"
|
#include "Node.h"
|
||||||
|
#include "NodeResampling.h"
|
||||||
#include "../Settings.h"
|
#include "../Settings.h"
|
||||||
|
|
||||||
|
#include <omp.h>
|
||||||
|
|
||||||
class PFInit : public K::ParticleFilterInitializer<MyState> {
|
class PFInit : public K::ParticleFilterInitializer<MyState> {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -42,17 +45,20 @@ public:
|
|||||||
std::uniform_int_distribution<int> distIdx(0, grid->getNumNodes()-1);
|
std::uniform_int_distribution<int> distIdx(0, grid->getNumNodes()-1);
|
||||||
std::uniform_real_distribution<float> distHead(0, 2*M_PI);
|
std::uniform_real_distribution<float> distHead(0, 2*M_PI);
|
||||||
|
|
||||||
|
|
||||||
for (K::Particle<MyState>& p : particles) {
|
for (K::Particle<MyState>& p : particles) {
|
||||||
const int idx = distIdx(gen);
|
const int idx = distIdx(gen);
|
||||||
const MyGridNode& node = (*grid)[idx];
|
const MyGridNode& node = (*grid)[idx];
|
||||||
p.state.position = node; // random position
|
p.state.position = node; // random position
|
||||||
p.state.heading.direction = Heading(distHead(gen)); // random heading
|
p.state.heading.direction = Heading(distHead(gen)); // random heading
|
||||||
|
p.weight = 1.0 / particles.size(); // equal weight
|
||||||
}
|
}
|
||||||
|
|
||||||
// // fix position + heading
|
// // fix position + heading
|
||||||
// for (K::Particle<MyState>& p : particles) {
|
// for (K::Particle<MyState>& p : particles) {
|
||||||
// const int idx = 9000;
|
//// const int idx = 9000;
|
||||||
// const MyGridNode& node = (*grid)[idx];
|
//// const MyGridNode& node = (*grid)[idx];
|
||||||
|
// const MyGridNode& node = grid->getNodeFor(GridPoint(2000, 2000, 0)); // center of the testmap
|
||||||
// p.state.position = node;
|
// p.state.position = node;
|
||||||
// p.state.heading.direction = Heading(0);
|
// p.state.heading.direction = Heading(0);
|
||||||
// }
|
// }
|
||||||
@@ -65,28 +71,34 @@ class PFTrans : public K::ParticleFilterTransition<MyState, MyControl> {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/** local, static control-data COPY */
|
||||||
|
MyControl ctrl;
|
||||||
|
|
||||||
Grid<MyGridNode>* grid;
|
Grid<MyGridNode>* grid;
|
||||||
GridWalker<MyGridNode, MyState> walker;
|
GridWalker<MyGridNode, MyState> walker;
|
||||||
|
|
||||||
WalkModuleFavorZ<MyGridNode, MyState> modFavorZ;
|
WalkModuleFavorZ<MyGridNode, MyState> modFavorZ;
|
||||||
WalkModuleHeadingControl<MyGridNode, MyState, MyControl> modHeading;
|
WalkModuleHeadingControl<MyGridNode, MyState, MyControl> modHeading;
|
||||||
WalkModuleNodeImportance<MyGridNode, MyState> modImportance;
|
WalkModuleNodeImportance<MyGridNode, MyState> modImportance;
|
||||||
WalkModuleButterActivity<MyGridNode, MyState> modBarometer;
|
|
||||||
WalkModuleFollowDestination<MyGridNode, MyState> modDestination;
|
WalkModuleFollowDestination<MyGridNode, MyState> modDestination;
|
||||||
|
WalkModuleActivityControl<MyGridNode, MyState, MyControl> modActivity;
|
||||||
|
|
||||||
|
NodeResampling<MyState, MyGridNode> resampler;
|
||||||
|
|
||||||
std::minstd_rand gen;
|
std::minstd_rand gen;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PFTrans(Grid<MyGridNode>* grid, MyControl* ctrl) : grid(grid), modHeading(ctrl, Settings::turnSigma), modDestination(*grid) {
|
PFTrans(Grid<MyGridNode>* grid) : grid(grid), modHeading(&ctrl, Settings::IMU::turnSigma), modDestination(*grid), modActivity(&ctrl), resampler(*grid) {
|
||||||
|
|
||||||
walker.addModule(&modFavorZ);
|
//walker.addModule(&modFavorZ);
|
||||||
walker.addModule(&modHeading);
|
walker.addModule(&modHeading);
|
||||||
walker.addModule(&modImportance);
|
//walker.addModule(&modImportance);
|
||||||
walker.addModule(&modBarometer);
|
walker.addModule(&modActivity);
|
||||||
walker.addModule(&modDestination);
|
|
||||||
|
|
||||||
if (Settings::destination != GridPoint(0,0,0)) {
|
if (Settings::destination != GridPoint(0,0,0)) {
|
||||||
|
//walker.addModule(&modDestination);
|
||||||
modDestination.setDestination(grid->getNodeFor(Settings::destination));
|
modDestination.setDestination(grid->getNodeFor(Settings::destination));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,16 +106,52 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void transition(std::vector<K::Particle<MyState>>& particles, const MyControl* control) override {
|
void transition(std::vector<K::Particle<MyState>>& particles, const MyControl* _ctrl) override {
|
||||||
|
|
||||||
std::normal_distribution<float> noise(0, Settings::stepSigma);
|
// local copy!! observation might be changed async outside!! (will really produces crashes!)
|
||||||
|
this->ctrl = *_ctrl;
|
||||||
|
((MyControl*)_ctrl)->resetAfterTransition();
|
||||||
|
|
||||||
for (K::Particle<MyState>& p : particles) {
|
std::normal_distribution<float> noise(0, Settings::IMU::stepSigma);
|
||||||
const float dist_m = std::abs(control->numStepsSinceLastTransition * Settings::stepLength + noise(gen));
|
double probSum = 0;
|
||||||
p.state = walker.getDestination(*grid, p.state, dist_m);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// seems OK
|
||||||
|
// float sum = 0;
|
||||||
|
// for (int i = 0; i < 1000; ++i) {
|
||||||
|
// float val = noise(gen);
|
||||||
|
// sum += std::abs(val);
|
||||||
|
// }
|
||||||
|
//Log::add("123", "sum: " + std::to_string(sum));
|
||||||
|
//Log::add("123", std::to_string(Timestamp::fromRunningTime().ms()) + ": " + std::to_string(ctrl.numStepsSinceLastTransition));
|
||||||
|
|
||||||
|
//for (K::Particle<MyState>& p : particles) {
|
||||||
|
#pragma omp parallel for num_threads(2)
|
||||||
|
for (int i = 0; i < (int) particles.size(); ++i) {
|
||||||
|
K::Particle<MyState>& p = particles[i];
|
||||||
|
const float dist_m = std::abs(ctrl.numStepsSinceLastTransition * Settings::IMU::stepLength + noise(gen));
|
||||||
|
double prob;
|
||||||
|
p.state = walker.getDestination(*grid, p.state, dist_m, prob);
|
||||||
|
//p.weight *= prob;//(prob > 0.01) ? (1.0) : (0.15);
|
||||||
|
//p.weight = (prob > 0.01) ? (1.0) : (0.15);
|
||||||
|
//p.weight = prob;
|
||||||
|
p.weight = 1.0; // reset
|
||||||
|
p.weight = std::pow(p.weight, 0.1); // make all particles a little more equal [less strict]
|
||||||
|
p.weight *= std::pow(prob, 0.1); // add grid-walk-probability
|
||||||
|
if (p.weight != p.weight) {throw Exception("nan");}
|
||||||
|
probSum += prob;
|
||||||
|
//p.weight = Distribution::Exponential<double>::getProbability(5.0, prob);
|
||||||
}
|
}
|
||||||
|
|
||||||
((MyControl*)control)->resetAfterTransition();
|
// const double avgProb = probSum / particles.size();
|
||||||
|
// const double threshold = avgProb * 0.15;
|
||||||
|
// for (int i = 0; i < (int) particles.size(); ++i) {
|
||||||
|
// K::Particle<MyState>& p = particles[i];
|
||||||
|
// p.weight = (p.weight > threshold) ? (1.0) : (0.01); // downvote all transitions below the threshold
|
||||||
|
// //p.weight = 1;
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,12 +159,51 @@ public:
|
|||||||
|
|
||||||
class PFEval : public K::ParticleFilterEvaluation<MyState, MyObservation> {
|
class PFEval : public K::ParticleFilterEvaluation<MyState, MyObservation> {
|
||||||
|
|
||||||
|
Grid<MyGridNode>* grid;
|
||||||
|
|
||||||
WiFiModelLogDistCeiling& wifiModel;
|
WiFiModelLogDistCeiling& wifiModel;
|
||||||
WiFiObserverFree wiFiProbability;
|
|
||||||
|
|
||||||
|
//WiFiObserverFree wiFiProbability; // free-calculation
|
||||||
|
WiFiObserverGrid<MyGridNode> wiFiProbability; // grid-calculation
|
||||||
|
|
||||||
|
// how to perform VAP grouping. also see calibration in Controller.cpp
|
||||||
|
VAPGrouper vg = VAPGrouper(VAPGrouper::Mode::LAST_MAC_DIGIT_TO_ZERO, VAPGrouper::Aggregation::AVERAGE);
|
||||||
|
|
||||||
|
// smartphone is 1.3 meter above ground
|
||||||
|
const Point3 person = Point3(0,0,Settings::smartphoneAboveGround);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
PFEval(WiFiModelLogDistCeiling& wifiModel) : wifiModel(wifiModel), wiFiProbability(Settings::wifiSigma, wifiModel) {
|
PFEval(Grid<MyGridNode>* grid, WiFiModelLogDistCeiling& wifiModel) :
|
||||||
|
grid(grid), wifiModel(wifiModel),
|
||||||
|
//wiFiProbability(Settings::WiFiModel::sigma, wifiModel) { // WiFi free
|
||||||
|
wiFiProbability(Settings::WiFiModel::sigma) { // WiFi grid
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
double getStairProb(const K::Particle<MyState>& p, const ActivityButterPressure::Activity act) {
|
||||||
|
|
||||||
|
const float kappa = 0.75;
|
||||||
|
|
||||||
|
const MyGridNode& gn = grid->getNodeFor(p.state.position);
|
||||||
|
switch (act) {
|
||||||
|
|
||||||
|
case ActivityButterPressure::Activity::STAY:
|
||||||
|
if (gn.getType() == GridNode::TYPE_FLOOR) {return kappa;}
|
||||||
|
if (gn.getType() == GridNode::TYPE_DOOR) {return kappa;}
|
||||||
|
{return 1-kappa;}
|
||||||
|
|
||||||
|
case ActivityButterPressure::Activity::UP:
|
||||||
|
case ActivityButterPressure::Activity::DOWN:
|
||||||
|
if (gn.getType() == GridNode::TYPE_STAIR) {return kappa;}
|
||||||
|
if (gn.getType() == GridNode::TYPE_ELEVATOR) {return kappa;}
|
||||||
|
{return 1-kappa;}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1.0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,18 +211,31 @@ public:
|
|||||||
|
|
||||||
double sum = 0;
|
double sum = 0;
|
||||||
|
|
||||||
// smartphone is 1.3 meter above ground
|
|
||||||
const Point3 person(0,0,Settings::smartphoneAboveGround);
|
|
||||||
|
|
||||||
// local copy!! observation might be changed async outside!! (will really produces crashes!)
|
// local copy!! observation might be changed async outside!! (will really produces crashes!)
|
||||||
const MyObservation observation = _observation;
|
const MyObservation observation = _observation;
|
||||||
|
|
||||||
|
// vap-grouping
|
||||||
|
const WiFiMeasurements wifiObs = vg.group(_observation.wifi);
|
||||||
|
|
||||||
for (K::Particle<MyState>& p : particles) {
|
for (K::Particle<MyState>& p : particles) {
|
||||||
const double pWiFi = wiFiProbability.getProbability(p.state.position.inMeter()+person, observation.currentTime, observation.wifi);
|
|
||||||
|
|
||||||
|
// WiFi free
|
||||||
|
//const double pWiFi = wiFiProbability.getProbability(p.state.position.inMeter()+person, observation.currentTime, vg.group(observation.wifi));
|
||||||
|
|
||||||
|
// WiFi grid
|
||||||
|
const MyGridNode& node = grid->getNodeFor(p.state.position);
|
||||||
|
const double pWiFi = wiFiProbability.getProbability(node, observation.currentTime, wifiObs);
|
||||||
|
|
||||||
|
const double pStair = getStairProb(p, observation.activity);
|
||||||
const double pGPS = 1;
|
const double pGPS = 1;
|
||||||
const double prob = pWiFi * pGPS;
|
const double prob = pWiFi * pGPS * pStair;
|
||||||
p.weight = prob;
|
p.weight *= prob; // NOTE: keeps the weight returned by the transition step!
|
||||||
sum += prob;
|
//p.weight = prob; // does NOT keep the weights returned by the transition step
|
||||||
|
sum += p.weight;
|
||||||
|
|
||||||
|
if (p.weight != p.weight) {throw Exception("nan");}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return sum;
|
return sum;
|
||||||
|
|||||||
@@ -10,7 +10,8 @@
|
|||||||
#include "../sensors/TurnSensor.h"
|
#include "../sensors/TurnSensor.h"
|
||||||
|
|
||||||
#include "../ui/debug/SensorDataWidget.h"
|
#include "../ui/debug/SensorDataWidget.h"
|
||||||
#include "../ui/map/MapView.h"
|
#include "../ui/map/3D/MapView3D.h"
|
||||||
|
#include "../ui/debug/InfoWidget.h"
|
||||||
|
|
||||||
#include <Indoor/Assertions.h>
|
#include <Indoor/Assertions.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@@ -18,24 +19,25 @@
|
|||||||
#include "State.h"
|
#include "State.h"
|
||||||
#include "Filter.h"
|
#include "Filter.h"
|
||||||
#include "Controller.h"
|
#include "Controller.h"
|
||||||
|
#include "NavControllerListener.h"
|
||||||
|
|
||||||
#include <KLib/misc/gnuplot/Gnuplot.h>
|
#include <KLib/misc/gnuplot/Gnuplot.h>
|
||||||
#include <KLib/misc/gnuplot/GnuplotSplot.h>
|
#include <KLib/misc/gnuplot/GnuplotSplot.h>
|
||||||
#include <KLib/misc/gnuplot/GnuplotSplotElementPoints.h>
|
#include <KLib/misc/gnuplot/GnuplotSplotElementPoints.h>
|
||||||
#include <KLib/misc/gnuplot/GnuplotSplotElementLines.h>
|
#include <KLib/misc/gnuplot/GnuplotSplotElementLines.h>
|
||||||
|
|
||||||
|
#ifndef ANDROID
|
||||||
|
#include <valgrind/callgrind.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
#include "RegionalResampling.h"
|
#include "RegionalResampling.h"
|
||||||
|
#include "NodeResampling.h"
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(const void*)
|
Q_DECLARE_METATYPE(const void*)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class NavController :
|
class NavController :
|
||||||
public SensorListener<AccelerometerData>,
|
public SensorListener<AccelerometerData>,
|
||||||
public SensorListener<GyroscopeData>,
|
public SensorListener<GyroscopeData>,
|
||||||
@@ -43,7 +45,9 @@ class NavController :
|
|||||||
public SensorListener<WiFiMeasurements>,
|
public SensorListener<WiFiMeasurements>,
|
||||||
public SensorListener<GPSData>,
|
public SensorListener<GPSData>,
|
||||||
public SensorListener<StepData>,
|
public SensorListener<StepData>,
|
||||||
public SensorListener<TurnData> {
|
public SensorListener<TurnData>,
|
||||||
|
public SensorListener<ActivityData> {
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -56,106 +60,164 @@ private:
|
|||||||
MyControl curCtrl;
|
MyControl curCtrl;
|
||||||
|
|
||||||
bool running = false;
|
bool running = false;
|
||||||
std::thread tUpdate;
|
std::thread tFilter;
|
||||||
std::thread tDisplay;
|
std::thread tDisplay;
|
||||||
|
|
||||||
std::unique_ptr<K::ParticleFilter<MyState, MyControl, MyObservation>> pf;
|
std::unique_ptr<K::ParticleFilter<MyState, MyControl, MyObservation>> pf;
|
||||||
|
|
||||||
|
/** the estimated path */
|
||||||
|
std::vector<Point3> estPath;
|
||||||
|
|
||||||
|
/** all listeners */
|
||||||
|
std::vector<NavControllerListener*> listeners;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual ~NavController() {
|
virtual ~NavController() {
|
||||||
if (running) {stop();}
|
if (running) {stop();}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
NavController(Controller* mainController, Grid<MyGridNode>* grid, Floorplan::IndoorMap* im) : mainController(mainController), grid(grid), wifiModel(im), im(im) {
|
NavController(Controller* mainController, Grid<MyGridNode>* grid, Floorplan::IndoorMap* im) : mainController(mainController), grid(grid), wifiModel(im), im(im) {
|
||||||
|
|
||||||
wifiModel.loadAPs(im, Settings::wifiTXP, Settings::wifiEXP, Settings::wifiWAF);
|
// filter init
|
||||||
|
|
||||||
SensorFactory::get().getAccelerometer().addListener(this);
|
|
||||||
SensorFactory::get().getGyroscope().addListener(this);
|
|
||||||
SensorFactory::get().getBarometer().addListener(this);
|
|
||||||
SensorFactory::get().getWiFi().addListener(this);
|
|
||||||
SensorFactory::get().getSteps().addListener(this);
|
|
||||||
SensorFactory::get().getTurns().addListener(this);
|
|
||||||
|
|
||||||
std::unique_ptr<K::ParticleFilterInitializer<MyState>> init(new PFInit(grid));
|
std::unique_ptr<K::ParticleFilterInitializer<MyState>> init(new PFInit(grid));
|
||||||
|
|
||||||
|
// estimation
|
||||||
//std::unique_ptr<K::ParticleFilterEstimationWeightedAverage<MyState>> estimation(new K::ParticleFilterEstimationWeightedAverage<MyState>());
|
//std::unique_ptr<K::ParticleFilterEstimationWeightedAverage<MyState>> estimation(new K::ParticleFilterEstimationWeightedAverage<MyState>());
|
||||||
std::unique_ptr<K::ParticleFilterEstimationOrderedWeightedAverage<MyState>> estimation(new K::ParticleFilterEstimationOrderedWeightedAverage<MyState>(0.1));
|
std::unique_ptr<K::ParticleFilterEstimationOrderedWeightedAverage<MyState>> estimation(new K::ParticleFilterEstimationOrderedWeightedAverage<MyState>(0.5));
|
||||||
|
|
||||||
|
// resampling
|
||||||
|
std::unique_ptr<NodeResampling<MyState, MyGridNode>> resample(new NodeResampling<MyState, MyGridNode>(*grid));
|
||||||
//std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>> resample(new K::ParticleFilterResamplingSimple<MyState>());
|
//std::unique_ptr<K::ParticleFilterResamplingSimple<MyState>> resample(new K::ParticleFilterResamplingSimple<MyState>());
|
||||||
//std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>> resample(new K::ParticleFilterResamplingPercent<MyState>(0.10));
|
//std::unique_ptr<K::ParticleFilterResamplingPercent<MyState>> resample(new K::ParticleFilterResamplingPercent<MyState>(0.05));
|
||||||
std::unique_ptr<RegionalResampling> resample(new RegionalResampling());
|
//std::unique_ptr<RegionalResampling> resample(new RegionalResampling());
|
||||||
|
|
||||||
|
// eval and transition
|
||||||
|
wifiModel.loadAPs(im, Settings::WiFiModel::TXP, Settings::WiFiModel::EXP, Settings::WiFiModel::WAF);
|
||||||
|
std::unique_ptr<K::ParticleFilterEvaluation<MyState, MyObservation>> eval(new PFEval(grid, wifiModel));
|
||||||
|
std::unique_ptr<K::ParticleFilterTransition<MyState, MyControl>> transition(new PFTrans(grid));
|
||||||
|
|
||||||
std::unique_ptr<K::ParticleFilterEvaluation<MyState, MyObservation>> eval(new PFEval(wifiModel));
|
// setup the filter
|
||||||
std::unique_ptr<K::ParticleFilterTransition<MyState, MyControl>> transition(new PFTrans(grid, &curCtrl));
|
|
||||||
|
|
||||||
pf = std::unique_ptr<K::ParticleFilter<MyState, MyControl, MyObservation>>(new K::ParticleFilter<MyState, MyControl, MyObservation>(Settings::numParticles, std::move(init)));
|
pf = std::unique_ptr<K::ParticleFilter<MyState, MyControl, MyObservation>>(new K::ParticleFilter<MyState, MyControl, MyObservation>(Settings::numParticles, std::move(init)));
|
||||||
pf->setTransition(std::move(transition));
|
pf->setTransition(std::move(transition));
|
||||||
pf->setEvaluation(std::move(eval));
|
pf->setEvaluation(std::move(eval));
|
||||||
pf->setEstimation(std::move(estimation));
|
pf->setEstimation(std::move(estimation));
|
||||||
pf->setResampling(std::move(resample));
|
pf->setResampling(std::move(resample));
|
||||||
|
|
||||||
pf->setNEffThreshold(1.0);
|
pf->setNEffThreshold(0.75);
|
||||||
|
//pf->setNEffThreshold(0.65); // still too low?
|
||||||
|
//pf->setNEffThreshold(0.25); // too low
|
||||||
|
|
||||||
|
// attach as listener to all sensors
|
||||||
|
SensorFactory::get().getAccelerometer().addListener(this);
|
||||||
|
SensorFactory::get().getGyroscope().addListener(this);
|
||||||
|
SensorFactory::get().getBarometer().addListener(this);
|
||||||
|
SensorFactory::get().getWiFi().addListener(this);
|
||||||
|
SensorFactory::get().getSteps().addListener(this);
|
||||||
|
SensorFactory::get().getTurns().addListener(this);
|
||||||
|
SensorFactory::get().getActivity().addListener(this);
|
||||||
|
|
||||||
|
// hacky.. but we need to call this one from the main thread!
|
||||||
|
//mainController->getMapView()->showParticles(pf->getParticles());
|
||||||
|
qRegisterMetaType<const void*>();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** attach a new event listener */
|
||||||
|
void addListener(NavControllerListener* l) {
|
||||||
|
listeners.push_back(l);
|
||||||
|
}
|
||||||
|
|
||||||
void start() {
|
void start() {
|
||||||
|
|
||||||
Assert::isFalse(running, "already started!");
|
Assert::isFalse(running, "already started!");
|
||||||
running = true;
|
running = true;
|
||||||
tUpdate = std::thread(&NavController::update, this);
|
curCtrl.resetAfterTransition(); // ensure we start empty ;)
|
||||||
tDisplay = std::thread(&NavController::display, this);
|
tFilter = std::thread(&NavController::filterUpdateLoop, this);
|
||||||
|
tDisplay = std::thread(&NavController::updateMapViewLoop, this);
|
||||||
|
|
||||||
|
// start all sensors
|
||||||
|
SensorFactory::get().getAccelerometer().start();
|
||||||
|
SensorFactory::get().getGyroscope().start();
|
||||||
|
SensorFactory::get().getBarometer().start();
|
||||||
|
SensorFactory::get().getWiFi().start();
|
||||||
|
|
||||||
|
#ifndef ANDROID
|
||||||
|
// #include <valgrind/callgrind.h>
|
||||||
|
// run with
|
||||||
|
// valgrind --tool=callgrind --quiet --instr-atstart=no ./yasmin
|
||||||
|
// show with
|
||||||
|
// kcachegrind callgrind.out.xxxx
|
||||||
|
CALLGRIND_START_INSTRUMENTATION;
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stop() {
|
void stop() {
|
||||||
Assert::isTrue(running, "not started!");
|
Assert::isTrue(running, "not started!");
|
||||||
running = false;
|
running = false;
|
||||||
tUpdate.join();
|
tFilter.join();
|
||||||
tDisplay.join();
|
tDisplay.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) override {
|
void onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
curObs.currentTime = ts;
|
(void) data;
|
||||||
|
(void) ts;
|
||||||
|
gotSensorData(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSensorData(Sensor<GyroscopeData>* sensor, const Timestamp ts, const GyroscopeData& data) override {
|
void onSensorData(Sensor<GyroscopeData>* sensor, const Timestamp ts, const GyroscopeData& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
curObs.currentTime = ts;
|
(void) ts;
|
||||||
|
(void) data;
|
||||||
|
gotSensorData(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSensorData(Sensor<BarometerData>* sensor, const Timestamp ts, const BarometerData& data) override {
|
void onSensorData(Sensor<BarometerData>* sensor, const Timestamp ts, const BarometerData& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
curObs.currentTime = ts;
|
(void) ts;
|
||||||
|
(void) data;
|
||||||
|
gotSensorData(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) override {
|
void onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
(void) ts;
|
(void) ts;
|
||||||
curObs.currentTime = ts;
|
|
||||||
curObs.wifi = data;
|
curObs.wifi = data;
|
||||||
|
gotSensorData(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSensorData(Sensor<GPSData>* sensor, const Timestamp ts, const GPSData& data) override {
|
void onSensorData(Sensor<GPSData>* sensor, const Timestamp ts, const GPSData& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
(void) ts;
|
(void) ts;
|
||||||
curObs.currentTime = ts;
|
|
||||||
curObs.gps = data;
|
curObs.gps = data;
|
||||||
|
gotSensorData(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSensorData(Sensor<StepData>* sensor, const Timestamp ts, const StepData& data) override {
|
void onSensorData(Sensor<StepData>* sensor, const Timestamp ts, const StepData& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
(void) ts;
|
(void) ts;
|
||||||
curObs.currentTime = ts;
|
|
||||||
curCtrl.numStepsSinceLastTransition += data.stepsSinceLastEvent; // set to zero after each transition
|
curCtrl.numStepsSinceLastTransition += data.stepsSinceLastEvent; // set to zero after each transition
|
||||||
|
gotSensorData(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSensorData(Sensor<TurnData>* sensor, const Timestamp ts, const TurnData& data) override {
|
void onSensorData(Sensor<TurnData>* sensor, const Timestamp ts, const TurnData& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
(void) ts;
|
(void) ts;
|
||||||
curObs.currentTime = ts;
|
|
||||||
curCtrl.turnSinceLastTransition_rad += data.radSinceLastEvent; // set to zero after each transition
|
curCtrl.turnSinceLastTransition_rad += data.radSinceLastEvent; // set to zero after each transition
|
||||||
|
gotSensorData(ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSensorData(Sensor<ActivityData>* sensor, const Timestamp ts, const ActivityData& data) override {
|
||||||
|
(void) sensor;
|
||||||
|
(void) ts;
|
||||||
|
curCtrl.activity = data.curActivity;
|
||||||
|
curObs.activity = data.curActivity;
|
||||||
|
debugActivity(data.curActivity);
|
||||||
|
gotSensorData(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cameraMode = 0;
|
int cameraMode = 0;
|
||||||
@@ -165,12 +227,29 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
/** called when any sensor has received new data */
|
||||||
|
void gotSensorData(const Timestamp ts) {
|
||||||
|
curObs.currentTime = ts;
|
||||||
|
if (Settings::Filter::useMainThread) {filterUpdateIfNeeded();}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void debugActivity(const ActivityData& activity) {
|
||||||
|
QString act;
|
||||||
|
switch(activity.curActivity) {
|
||||||
|
case ActivityButterPressure::Activity::STAY: act = "STAY"; break;
|
||||||
|
case ActivityButterPressure::Activity::DOWN: act = "DOWN"; break;
|
||||||
|
case ActivityButterPressure::Activity::UP: act = "UP"; break;
|
||||||
|
default: act = "???"; break;
|
||||||
|
}
|
||||||
|
Assert::isTrue(QMetaObject::invokeMethod(mainController->getInfoWidget(), "showActivity", Qt::QueuedConnection, Q_ARG(const QString&, act)), "call failed");
|
||||||
|
}
|
||||||
|
|
||||||
/** particle-filter update loop */
|
/** particle-filter update loop */
|
||||||
void update() {
|
void filterUpdateLoop() {
|
||||||
|
|
||||||
Timestamp lastTransition;
|
|
||||||
|
|
||||||
while(running) {
|
while(running && !Settings::Filter::useMainThread) {
|
||||||
|
|
||||||
// // fixed update rate based on the systems time -> LIVE! even for offline data
|
// // fixed update rate based on the systems time -> LIVE! even for offline data
|
||||||
// const Timestamp ts1 = Timestamp::fromUnixTime();
|
// const Timestamp ts1 = Timestamp::fromUnixTime();
|
||||||
@@ -180,82 +259,94 @@ private:
|
|||||||
// const Timestamp sleep = Timestamp::fromMS(500) - needed;
|
// const Timestamp sleep = Timestamp::fromMS(500) - needed;
|
||||||
// std::this_thread::sleep_for(std::chrono::milliseconds(sleep.ms()));
|
// std::this_thread::sleep_for(std::chrono::milliseconds(sleep.ms()));
|
||||||
|
|
||||||
// fixed update rate based on incoming sensor data
|
const bool wasUpdated = filterUpdateIfNeeded();
|
||||||
// allows working with live data and faster for offline data
|
if (!wasUpdated) { std::this_thread::sleep_for(std::chrono::milliseconds(2)); }
|
||||||
const Timestamp diff = curObs.currentTime - lastTransition;
|
|
||||||
if (diff > Timestamp::fromMS(500)) {
|
|
||||||
doUpdate();
|
|
||||||
lastTransition = curObs.currentTime;
|
|
||||||
} else {
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timestamp lastTransition;
|
||||||
|
|
||||||
|
/** check whether its time for a filter update, and if so, execute the update and return true */
|
||||||
|
bool filterUpdateIfNeeded() {
|
||||||
|
|
||||||
|
//static float avgSum = 0;
|
||||||
|
//static int avgCount = 0;
|
||||||
|
|
||||||
|
// fixed update rate based on incoming sensor data
|
||||||
|
// allows working with live data and faster for offline data
|
||||||
|
const Timestamp diff = curObs.currentTime - lastTransition;
|
||||||
|
if (diff >= Settings::Filter::updateEvery) {
|
||||||
|
|
||||||
|
// as the difference is slightly above the 500ms, calculate the error and incorporate it into the next one
|
||||||
|
const Timestamp err = diff - Settings::Filter::updateEvery;
|
||||||
|
lastTransition = curObs.currentTime - err;
|
||||||
|
|
||||||
|
const Timestamp ts1 = Timestamp::fromUnixTime();
|
||||||
|
filterUpdate();
|
||||||
|
const Timestamp ts2 = Timestamp::fromUnixTime();
|
||||||
|
const Timestamp tsDiff = ts2-ts1;
|
||||||
|
const QString filterTime = QString::number(tsDiff.ms());
|
||||||
|
//avgSum += tsDiff.ms(); ++avgCount; std::cout << "ts:" << curObs.currentTime << " avg:" << (avgSum/avgCount) << std::endl;
|
||||||
|
QMetaObject::invokeMethod(mainController->getInfoWidget(), "showFilterTime", Qt::QueuedConnection, Q_ARG(const QString&, filterTime));
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MyState curEst;
|
MyState curEst;
|
||||||
//MyState lastEst;
|
DijkstraPath<MyGridNode> pathToDest;
|
||||||
|
|
||||||
void doUpdate() {
|
/** perform a filter-update (called from a background-loop) */
|
||||||
|
void filterUpdate() {
|
||||||
|
|
||||||
//lastEst = curEst;
|
//lastEst = curEst;
|
||||||
curEst = pf->update(&curCtrl, curObs);
|
curEst = pf->update(&curCtrl, curObs);
|
||||||
|
Log::add("Nav", "cur est: " + curEst.position.asString());
|
||||||
|
|
||||||
// hacky.. but we need to call this one from the main thread!
|
// inform listeners about the new estimation
|
||||||
//mainController->getMapView()->showParticles(pf->getParticles());
|
for (NavControllerListener* l : listeners) {l->onNewEstimation(curEst.position.inMeter());}
|
||||||
qRegisterMetaType<const void*>();
|
|
||||||
Assert::isTrue(QMetaObject::invokeMethod(mainController->getMapView(), "showParticles", Qt::QueuedConnection, Q_ARG(const void*, &pf->getParticles())), "call failed");
|
|
||||||
|
|
||||||
|
Assert::isTrue(QMetaObject::invokeMethod(mainController->getMapView3D(), "showParticles", Qt::QueuedConnection, Q_ARG(const void*, &pf->getParticles())), "call failed");
|
||||||
|
Assert::isTrue(QMetaObject::invokeMethod(mainController->getMapView2D(), "showParticles", Qt::QueuedConnection, Q_ARG(const void*, &pf->getParticles())), "call failed");
|
||||||
|
|
||||||
|
// update estimated path
|
||||||
|
estPath.push_back(curEst.position.inMeter());
|
||||||
|
Assert::isTrue(QMetaObject::invokeMethod(mainController->getMapView3D(), "setPathWalked", Qt::QueuedConnection, Q_ARG(const void*, &estPath)), "call failed");
|
||||||
|
Assert::isTrue(QMetaObject::invokeMethod(mainController->getMapView2D(), "setPathWalked", Qt::QueuedConnection, Q_ARG(const void*, &estPath)), "call failed");
|
||||||
|
|
||||||
PFTrans* trans = (PFTrans*)pf->getTransition();
|
PFTrans* trans = (PFTrans*)pf->getTransition();
|
||||||
const MyGridNode* node = grid->getNodePtrFor(curEst.position);
|
const MyGridNode* node = grid->getNodePtrFor(curEst.position);
|
||||||
if (node) {
|
if (node) {
|
||||||
const DijkstraPath<MyGridNode> path = trans->modDestination.getShortestPath(*node);
|
try {
|
||||||
|
pathToDest = trans->modDestination.getShortestPath(*node);
|
||||||
|
Assert::isTrue(QMetaObject::invokeMethod(mainController->getMapView3D(), "setPathToDestination", Qt::QueuedConnection, Q_ARG(const void*, &pathToDest)), "call failed");
|
||||||
|
Assert::isTrue(QMetaObject::invokeMethod(mainController->getMapView2D(), "setPathToDestination", Qt::QueuedConnection, Q_ARG(const void*, &pathToDest)), "call failed");
|
||||||
|
} catch (...) {;}
|
||||||
|
}
|
||||||
// mainController->getMapView()->showGridImportance();
|
// mainController->getMapView()->showGridImportance();
|
||||||
Assert::isTrue(QMetaObject::invokeMethod(mainController->getMapView(), "setPath", Qt::QueuedConnection, Q_ARG(const void*, &path)), "call failed");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
static K::Gnuplot gp;
|
|
||||||
K::GnuplotSplot plot;
|
|
||||||
K::GnuplotSplotElementLines lines; plot.add(&lines);
|
|
||||||
K::GnuplotSplotElementPoints points; plot.add(&points);
|
|
||||||
K::GnuplotSplotElementPoints best; plot.add(&best); best.setPointSize(2); best.setColorHex("#0000ff");
|
|
||||||
|
|
||||||
for (const K::Particle<MyState>& p : pf->getParticles()) {
|
|
||||||
const Point3 pos = p.state.position.inMeter();
|
|
||||||
points.add(K::GnuplotPoint3(pos.x, pos.y, pos.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const Floorplan::Floor* f : im->floors) {
|
|
||||||
for (const Floorplan::FloorOutlinePolygon* polygon : f->outline) {
|
|
||||||
for (int i = 0; i < polygon->poly.points.size(); ++i) {
|
|
||||||
const Point2 p1 = polygon->poly.points[i];
|
|
||||||
const Point2 p2 = polygon->poly.points[(i+1)%polygon->poly.points.size()];
|
|
||||||
K::GnuplotPoint3 gp1(p1.x, p1.y, f->atHeight);
|
|
||||||
K::GnuplotPoint3 gp2(p2.x, p2.y, f->atHeight);
|
|
||||||
lines.addSegment(gp1, gp2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
K::GnuplotPoint3 gpBest(curEst.position.x_cm/100.0f, curEst.position.y_cm/100.0f, curEst.position.z_cm/100.0f);
|
|
||||||
best.add(gpBest);
|
|
||||||
|
|
||||||
gp.draw(plot);
|
|
||||||
gp.flush();
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int display_ms = 50;
|
|
||||||
|
const int display_ms = Settings::MapView::msPerFrame.ms();
|
||||||
|
|
||||||
/** UI update loop */
|
/** UI update loop */
|
||||||
void display() {
|
void updateMapViewLoop() {
|
||||||
|
|
||||||
while(running) {
|
while(running) {
|
||||||
doDisplay();
|
const Timestamp ts1 = Timestamp::fromUnixTime();
|
||||||
|
updateMapView();
|
||||||
|
const Timestamp ts2 = Timestamp::fromUnixTime();
|
||||||
|
const Timestamp tsDiff = ts2-ts1;
|
||||||
|
const QString mapViewTime = QString::number(tsDiff.ms());
|
||||||
|
//QMetaObject::invokeMethod(mainController->getInfoWidget(), "showMapViewTime", Qt::QueuedConnection, Q_ARG(const QString&, mapViewTime));
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(display_ms));
|
std::this_thread::sleep_for(std::chrono::milliseconds(display_ms));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -264,8 +355,8 @@ private:
|
|||||||
Point3 curPosSlow;
|
Point3 curPosSlow;
|
||||||
|
|
||||||
|
|
||||||
|
/** update the map-view (called from within a background-loop) */
|
||||||
void doDisplay() {
|
void updateMapView() {
|
||||||
|
|
||||||
const float kappa1 = display_ms / 1000.0f;
|
const float kappa1 = display_ms / 1000.0f;
|
||||||
const float kappa2 = kappa1 * 0.7;
|
const float kappa2 = kappa1 * 0.7;
|
||||||
@@ -278,19 +369,21 @@ private:
|
|||||||
const Point3 dir = (curPosFast - curPosSlow).normalized();
|
const Point3 dir = (curPosFast - curPosSlow).normalized();
|
||||||
const Point3 dir2 = Point3(dir.x, dir.y, -0.2).normalized();
|
const Point3 dir2 = Point3(dir.x, dir.y, -0.2).normalized();
|
||||||
|
|
||||||
|
// how to update the camera
|
||||||
if (cameraMode == 0) {
|
if (cameraMode == 0) {
|
||||||
mainController->getMapView()->setLookAt(curPosFast + Point3(0,0,myHeight_m), dir);
|
mainController->getMapView3D()->setLookAt(curPosFast + Point3(0,0,myHeight_m), dir);
|
||||||
} else if (cameraMode == 1) {
|
} else if (cameraMode == 1) {
|
||||||
mainController->getMapView()->setLookAt(curPosFast + Point3(0,0,myHeight_m) - dir2*4, dir2);
|
mainController->getMapView3D()->setLookAt(curPosFast + Point3(0,0,myHeight_m) - dir2*4, dir2);
|
||||||
} else if (cameraMode == 2) {
|
} else if (cameraMode == 2) {
|
||||||
const Point3 spectator = curPosFast + Point3(0,0,20) - dir*15;
|
const Point3 spectator = curPosFast + Point3(0,0,25) - dir*15;
|
||||||
const Point3 spectatorDir = (curPosFast - spectator).normalized();
|
const Point3 spectatorDir = (curPosFast - spectator).normalized();
|
||||||
mainController->getMapView()->setLookEye(spectator);
|
mainController->getMapView3D()->setLookEye(spectator);
|
||||||
mainController->getMapView()->setLookDir(spectatorDir);
|
mainController->getMapView3D()->setLookDir(spectatorDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
mainController->getMapView()->setCurrentEstimation(curPosFast, dir);
|
mainController->getMapView3D()->setClipAbove(curEst.position.inMeter().z + 2);
|
||||||
|
mainController->getMapView3D()->setCurrentEstimation(curEst.position.inMeter(), dir);
|
||||||
|
mainController->getMapView2D()->setCurrentEstimation(curEst.position.inMeter(), dir);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
nav/NavControllerListener.h
Normal file
15
nav/NavControllerListener.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef NAVCONTROLLERLISTENER_H
|
||||||
|
#define NAVCONTROLLERLISTENER_H
|
||||||
|
|
||||||
|
#include <Indoor/geo/Point3.h>
|
||||||
|
|
||||||
|
class NavControllerListener {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** a new position estimation is available */
|
||||||
|
virtual void onNewEstimation(const Point3 pos_m) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // NAVCONTROLLERLISTENER_H
|
||||||
10
nav/Node.h
10
nav/Node.h
@@ -4,11 +4,15 @@
|
|||||||
#include <Indoor/grid/Grid.h>
|
#include <Indoor/grid/Grid.h>
|
||||||
#include <Indoor/sensors/radio/WiFiGridNode.h>
|
#include <Indoor/sensors/radio/WiFiGridNode.h>
|
||||||
|
|
||||||
struct MyGridNode : public GridNode, public GridPoint {//, public WiFiGridNode<10> {
|
struct MyGridNode : public GridNode, public GridPoint, public WiFiGridNode<20> {
|
||||||
|
|
||||||
float navImportance;
|
float navImportance;
|
||||||
float getNavImportance() const { return navImportance; }
|
float getNavImportance() const { return navImportance; }
|
||||||
|
|
||||||
|
float walkImportance;
|
||||||
|
float getWalkImportance() const { return walkImportance; }
|
||||||
|
|
||||||
|
|
||||||
/** empty ctor */
|
/** empty ctor */
|
||||||
MyGridNode() : GridPoint(-1, -1, -1) {;}
|
MyGridNode() : GridPoint(-1, -1, -1) {;}
|
||||||
|
|
||||||
@@ -17,11 +21,11 @@ struct MyGridNode : public GridNode, public GridPoint {//, public WiFiGridNode<1
|
|||||||
|
|
||||||
|
|
||||||
static void staticDeserialize(std::istream& inp) {
|
static void staticDeserialize(std::istream& inp) {
|
||||||
//WiFiGridNode::staticDeserialize(inp);
|
WiFiGridNode::staticDeserialize(inp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void staticSerialize(std::ostream& out) {
|
static void staticSerialize(std::ostream& out) {
|
||||||
//WiFiGridNode::staticSerialize(out);
|
WiFiGridNode::staticSerialize(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
123
nav/NodeResampling.h
Normal file
123
nav/NodeResampling.h
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#ifndef NODERESAMPLING_H
|
||||||
|
#define NODERESAMPLING_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include <Indoor/grid/Grid.h>
|
||||||
|
#include <KLib/math/filter/particles/resampling/ParticleFilterResampling.h>
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uses simple probability resampling by drawing particles according
|
||||||
|
* to their current weight.
|
||||||
|
* HOWEVER: after drawing them, do NOT use them directly, but replace them with a neighbor
|
||||||
|
* O(log(n)) per particle
|
||||||
|
*/
|
||||||
|
template <typename State, typename Node>
|
||||||
|
class NodeResampling : public K::ParticleFilterResampling<State> {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** this is a copy of the particle-set to draw from it */
|
||||||
|
std::vector<K::Particle<State>> particlesCopy;
|
||||||
|
|
||||||
|
/** random number generator */
|
||||||
|
std::minstd_rand gen;
|
||||||
|
|
||||||
|
Grid<Node>& grid;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
NodeResampling(Grid<Node>& grid) : grid(grid) {
|
||||||
|
gen.seed(1234);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resample(std::vector<K::Particle<State>>& particles) override {
|
||||||
|
|
||||||
|
// compile-time sanity checks
|
||||||
|
// TODO: this solution requires EXPLICIT overloading which is bad...
|
||||||
|
//static_assert( HasOperatorAssign<State>::value, "your state needs an assignment operator!" );
|
||||||
|
|
||||||
|
const uint32_t cnt = (uint32_t) particles.size();
|
||||||
|
|
||||||
|
// equal weight for all particles. sums up to 1.0
|
||||||
|
const double equalWeight = 1.0 / (double) cnt;
|
||||||
|
|
||||||
|
// ensure the copy vector has the same size as the real particle vector
|
||||||
|
particlesCopy.resize(cnt);
|
||||||
|
|
||||||
|
// swap both vectors
|
||||||
|
particlesCopy.swap(particles);
|
||||||
|
|
||||||
|
// calculate cumulative weight
|
||||||
|
double cumWeight = 0;
|
||||||
|
for (uint32_t i = 0; i < cnt; ++i) {
|
||||||
|
cumWeight += particlesCopy[i].weight;
|
||||||
|
particlesCopy[i].weight = cumWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::uniform_real_distribution<float> distNewOne(0.0, 1.0);
|
||||||
|
// std::uniform_int_distribution<int> distRndNode(0, grid.getNumNodes()-1);
|
||||||
|
std::normal_distribution<float> distTurn(0.0, +0.03);
|
||||||
|
|
||||||
|
// now draw from the copy vector and fill the original one
|
||||||
|
// with the resampled particle-set
|
||||||
|
for (uint32_t i = 0; i < cnt; ++i) {
|
||||||
|
|
||||||
|
// slight chance to get a truely random node as particle
|
||||||
|
// mainly for testing
|
||||||
|
// if (distNewOne(gen) < 0.005) {
|
||||||
|
// particles[i].state.position = grid[distRndNode(gen)];
|
||||||
|
// particles[i].weight = equalWeight;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// normal redraw procedure
|
||||||
|
particles[i] = draw(cumWeight);
|
||||||
|
particles[i].weight = equalWeight;
|
||||||
|
|
||||||
|
const Node* n = grid.getNodePtrFor(particles[i].state.position);
|
||||||
|
if (n == nullptr) {continue;} // should not happen!
|
||||||
|
|
||||||
|
for (int j = 0; j < 2; ++j) {
|
||||||
|
std::uniform_int_distribution<int> distIdx(0, n->getNumNeighbors()-1);
|
||||||
|
const int idx = distIdx(gen);
|
||||||
|
n = &grid.getNeighbor(*n, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
particles[i].state.position = *n;
|
||||||
|
particles[i].state.heading.direction += distTurn(gen);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** draw one particle according to its weight from the copy vector */
|
||||||
|
const K::Particle<State>& draw(const double cumWeight) {
|
||||||
|
|
||||||
|
// generate random values between [0:cumWeight]
|
||||||
|
std::uniform_real_distribution<float> dist(0, cumWeight);
|
||||||
|
|
||||||
|
// draw a random value between [0:cumWeight]
|
||||||
|
const float rand = dist(gen);
|
||||||
|
|
||||||
|
// search comparator (cumWeight is ordered -> use binary search)
|
||||||
|
auto comp = [] (const K::Particle<State>& s, const float d) {return s.weight < d;};
|
||||||
|
auto it = std::lower_bound(particlesCopy.begin(), particlesCopy.end(), rand, comp);
|
||||||
|
return *it;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // NODERESAMPLING_H
|
||||||
12
nav/State.h
12
nav/State.h
@@ -2,7 +2,7 @@
|
|||||||
#define STATE_H
|
#define STATE_H
|
||||||
|
|
||||||
#include <Indoor/grid/walk/v2/GridWalker.h>
|
#include <Indoor/grid/walk/v2/GridWalker.h>
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleButterActivity.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleActivityControl.h>
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleHeadingControl.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleHeadingControl.h>
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleNodeImportance.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleNodeImportance.h>
|
||||||
#include <Indoor/grid/walk/v2/modules/WalkModuleFavorZ.h>
|
#include <Indoor/grid/walk/v2/modules/WalkModuleFavorZ.h>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#include <Indoor/sensors/radio/WiFiMeasurements.h>
|
#include <Indoor/sensors/radio/WiFiMeasurements.h>
|
||||||
#include <Indoor/sensors/gps/GPSData.h>
|
#include <Indoor/sensors/gps/GPSData.h>
|
||||||
|
|
||||||
struct MyState : public WalkState, public WalkStateFavorZ, public WalkStateHeading, public WalkStateBarometerActivity {
|
struct MyState : public WalkState, public WalkStateFavorZ, public WalkStateHeading {
|
||||||
|
|
||||||
|
|
||||||
/** ctor */
|
/** ctor */
|
||||||
@@ -52,6 +52,10 @@ struct MyObservation {
|
|||||||
/** gps measurements */
|
/** gps measurements */
|
||||||
GPSData gps;
|
GPSData gps;
|
||||||
|
|
||||||
|
// TODO: switch to a general activity enum/detector for barometer + accelerometer + ...?
|
||||||
|
/** detected activity */
|
||||||
|
ActivityButterPressure::Activity activity;
|
||||||
|
|
||||||
/** time of evaluation */
|
/** time of evaluation */
|
||||||
Timestamp currentTime;
|
Timestamp currentTime;
|
||||||
|
|
||||||
@@ -66,6 +70,10 @@ struct MyControl {
|
|||||||
/** number of steps since the last transition */
|
/** number of steps since the last transition */
|
||||||
int numStepsSinceLastTransition = 0;
|
int numStepsSinceLastTransition = 0;
|
||||||
|
|
||||||
|
// TODO: switch to a general activity enum/detector using barometer + accelerometer?
|
||||||
|
/** currently detected activity */
|
||||||
|
ActivityButterPressure::Activity activity;
|
||||||
|
|
||||||
/** reset the control-data after each transition */
|
/** reset the control-data after each transition */
|
||||||
void resetAfterTransition() {
|
void resetAfterTransition() {
|
||||||
turnSinceLastTransition_rad = 0;
|
turnSinceLastTransition_rad = 0;
|
||||||
|
|||||||
2
qml.qrc
2
qml.qrc
@@ -19,5 +19,7 @@
|
|||||||
<file>res/gl/tex/empty_normals.jpg</file>
|
<file>res/gl/tex/empty_normals.jpg</file>
|
||||||
<file>res/icons/cube.svg</file>
|
<file>res/icons/cube.svg</file>
|
||||||
<file>res/icons/camera.svg</file>
|
<file>res/icons/camera.svg</file>
|
||||||
|
<file>res/icons/wall.svg</file>
|
||||||
|
<file>res/icons/dots.svg</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ void main() {
|
|||||||
#ifdef GL_ES
|
#ifdef GL_ES
|
||||||
|
|
||||||
// set point size
|
// set point size
|
||||||
gl_PointSize = 3.0;
|
//gl_PointSize = 3.0;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ uniform vec3 lightWorldPos;
|
|||||||
|
|
||||||
uniform sampler2D texDiffuse;
|
uniform sampler2D texDiffuse;
|
||||||
uniform sampler2D texNormalMap;
|
uniform sampler2D texNormalMap;
|
||||||
|
uniform float alpha;
|
||||||
|
|
||||||
// interpolated values
|
// interpolated values
|
||||||
varying vec3 v_WorldPos;
|
varying vec3 v_WorldPos;
|
||||||
@@ -55,12 +56,12 @@ void main() {
|
|||||||
|
|
||||||
// Set fragment color from texture
|
// Set fragment color from texture
|
||||||
vec4 finalColor =
|
vec4 finalColor =
|
||||||
ambient * 0.05 +
|
ambient * 0.30 +
|
||||||
diffuse * 0.95 * diffuseIntensity * lightInt +
|
diffuse * 0.70 * diffuseIntensity * lightInt +
|
||||||
clamp(specular * specularIntensity, 0.0, 1.0) * 1.0;
|
clamp(specular * specularIntensity, 0.0, 1.0) * 1.0;
|
||||||
|
|
||||||
gl_FragColor = clamp(finalColor, 0.0, 1.0);
|
gl_FragColor = clamp(finalColor, 0.0, 1.0);
|
||||||
gl_FragColor.a = 0.4;
|
gl_FragColor.a = alpha;
|
||||||
|
|
||||||
// FOG
|
// FOG
|
||||||
//float mixing = pow((1.0 - v_CamPos.z * 3.0), 2);
|
//float mixing = pow((1.0 - v_CamPos.z * 3.0), 2);
|
||||||
|
|||||||
73
res/icons/dots.svg
Normal file
73
res/icons/dots.svg
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="0 0 525.153 525.153" style="enable-background:new 0 0 525.153 525.153;" xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<path d="M96.781,290.234c-15.229,0-27.658,12.407-27.658,27.658c0,15.12,12.407,27.658,27.658,27.658
|
||||||
|
c15.12,0,27.658-12.516,27.658-27.658C124.439,302.641,111.901,290.234,96.781,290.234z M96.781,400.713
|
||||||
|
c-15.229,0-27.658,12.516-27.658,27.658c0,15.229,12.407,27.658,27.658,27.658c15.12,0,27.658-12.407,27.658-27.658
|
||||||
|
C124.439,413.251,111.901,400.713,96.781,400.713z M96.781,179.624c-15.229,0-27.658,12.516-27.658,27.658
|
||||||
|
c0,15.229,12.407,27.658,27.658,27.658c15.12,0,27.658-12.407,27.658-27.658C124.439,192.14,111.901,179.624,96.781,179.624z
|
||||||
|
M13.829,193.453C6.105,193.453,0,199.558,0,207.282c0,7.724,6.105,13.829,13.829,13.829s13.829-6.105,13.829-13.829
|
||||||
|
C27.658,199.558,21.531,193.453,13.829,193.453z M96.781,69.123c-15.229,0-27.658,12.407-27.658,27.658
|
||||||
|
c0,15.12,12.407,27.658,27.658,27.658c15.12,0,27.658-12.516,27.658-27.658C124.439,81.552,111.901,69.123,96.781,69.123z
|
||||||
|
M511.324,221.089c7.724,0,13.829-6.105,13.829-13.829c0-7.724-6.105-13.829-13.829-13.829c-7.724,0-13.829,6.105-13.829,13.829
|
||||||
|
C497.495,214.984,503.621,221.089,511.324,221.089z M317.87,124.439c15.12,0,27.658-12.516,27.658-27.658
|
||||||
|
c0-15.229-12.516-27.658-27.658-27.658c-15.229,0-27.658,12.407-27.658,27.658C290.234,111.901,302.641,124.439,317.87,124.439z
|
||||||
|
M317.87,27.658c7.724,0,13.829-6.105,13.829-13.829S325.595,0,317.87,0c-7.724,0-13.829,6.105-13.829,13.829
|
||||||
|
S310.168,27.658,317.87,27.658z M13.829,304.063C6.105,304.063,0,310.168,0,317.87s6.105,13.829,13.829,13.829
|
||||||
|
s13.829-6.105,13.829-13.829C27.658,310.146,21.531,304.063,13.829,304.063z M207.282,497.495c-7.724,0-13.829,6.105-13.829,13.829
|
||||||
|
c0,7.724,6.105,13.829,13.829,13.829c7.724,0,13.829-6.105,13.829-13.829C221.111,503.599,214.984,497.495,207.282,497.495z
|
||||||
|
M207.282,27.658c7.724,0,13.829-6.105,13.829-13.829S214.984,0,207.282,0s-13.829,6.105-13.829,13.829
|
||||||
|
S199.558,27.658,207.282,27.658z M207.282,124.439c15.229,0,27.658-12.516,27.658-27.658c0-15.229-12.407-27.658-27.658-27.658
|
||||||
|
c-15.12,0-27.658,12.407-27.658,27.658C179.624,111.901,192.14,124.439,207.282,124.439z M207.282,276.405
|
||||||
|
c-22.975,0-41.487,18.512-41.487,41.487s18.512,41.487,41.487,41.487s41.487-18.512,41.487-41.487S230.236,276.405,207.282,276.405
|
||||||
|
z M428.371,290.234c-15.12,0-27.658,12.407-27.658,27.658c0,15.12,12.516,27.658,27.658,27.658
|
||||||
|
c15.229,0,27.658-12.516,27.658-27.658C456.029,302.641,443.601,290.234,428.371,290.234z M428.371,400.713
|
||||||
|
c-15.12,0-27.658,12.516-27.658,27.658c0,15.229,12.516,27.658,27.658,27.658c15.229,0,27.658-12.407,27.658-27.658
|
||||||
|
C456.029,413.251,443.601,400.713,428.371,400.713z M428.371,179.624c-15.12,0-27.658,12.516-27.658,27.658
|
||||||
|
c0,15.229,12.516,27.658,27.658,27.658c15.229,0,27.658-12.407,27.658-27.658C456.029,192.14,443.601,179.624,428.371,179.624z
|
||||||
|
M428.371,69.123c-15.12,0-27.658,12.407-27.658,27.658c0,15.12,12.516,27.658,27.658,27.658c15.229,0,27.658-12.516,27.658-27.658
|
||||||
|
C456.029,81.552,443.601,69.123,428.371,69.123z M511.324,304.063c-7.724,0-13.829,6.105-13.829,13.829s6.105,13.829,13.829,13.829
|
||||||
|
c7.724,0,13.829-6.127,13.829-13.851C525.153,310.146,519.048,304.063,511.324,304.063z M317.87,400.713
|
||||||
|
c-15.229,0-27.658,12.516-27.658,27.658c0,15.229,12.407,27.658,27.658,27.658c15.12,0,27.658-12.407,27.658-27.658
|
||||||
|
C345.529,413.251,333.012,400.713,317.87,400.713z M317.87,497.495c-7.724,0-13.829,6.105-13.829,13.829
|
||||||
|
c0,7.724,6.127,13.829,13.829,13.829s13.829-6.105,13.829-13.829C331.699,503.599,325.595,497.495,317.87,497.495z
|
||||||
|
M207.282,165.795c-22.975,0-41.487,18.512-41.487,41.487s18.512,41.487,41.487,41.487s41.487-18.512,41.487-41.487
|
||||||
|
S230.236,165.795,207.282,165.795z M207.282,400.713c-15.12,0-27.658,12.516-27.658,27.658c0,15.229,12.516,27.658,27.658,27.658
|
||||||
|
c15.229,0,27.658-12.407,27.658-27.658C234.918,413.251,222.511,400.713,207.282,400.713z M317.87,276.405
|
||||||
|
c-22.975,0-41.487,18.512-41.487,41.487s18.512,41.487,41.487,41.487s41.487-18.512,41.487-41.487S340.846,276.405,317.87,276.405z
|
||||||
|
M317.87,165.795c-22.975,0-41.487,18.512-41.487,41.487s18.512,41.487,41.487,41.487s41.487-18.512,41.487-41.487
|
||||||
|
S340.846,165.795,317.87,165.795z"/>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.5 KiB |
54
res/icons/wall.svg
Normal file
54
res/icons/wall.svg
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
width="439.875px" height="439.875px" viewBox="0 0 439.875 439.875" style="enable-background:new 0 0 439.875 439.875;"
|
||||||
|
xml:space="preserve">
|
||||||
|
<g>
|
||||||
|
<g id="iconos_32_">
|
||||||
|
<rect y="329.906" width="133.875" height="47.812"/>
|
||||||
|
<rect x="153" y="329.906" width="133.875" height="47.812"/>
|
||||||
|
<rect x="76.5" y="262.969" width="133.875" height="47.812"/>
|
||||||
|
<rect y="196.031" width="133.875" height="47.812"/>
|
||||||
|
<rect x="153" y="196.031" width="133.875" height="47.812"/>
|
||||||
|
<rect x="76.5" y="129.094" width="133.875" height="47.812"/>
|
||||||
|
<rect x="229.5" y="262.969" width="133.875" height="47.812"/>
|
||||||
|
<rect x="229.5" y="129.094" width="133.875" height="47.812"/>
|
||||||
|
<rect y="62.156" width="133.875" height="47.812"/>
|
||||||
|
<rect x="153" y="62.156" width="133.875" height="47.812"/>
|
||||||
|
<rect x="306" y="329.906" width="133.875" height="47.812"/>
|
||||||
|
<rect x="306" y="196.031" width="133.875" height="47.812"/>
|
||||||
|
<rect x="306" y="62.156" width="133.875" height="47.812"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
<g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
63
sensors/ActivitySensor.h
Normal file
63
sensors/ActivitySensor.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef BAROMETERACTIVITYSENSOR_H
|
||||||
|
#define BAROMETERACTIVITYSENSOR_H
|
||||||
|
|
||||||
|
#include <Indoor/sensors/pressure/ActivityButterPressure.h>
|
||||||
|
#include "BarometerSensor.h"
|
||||||
|
#include "AccelerometerSensor.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct ActivityData {
|
||||||
|
const ActivityButterPressure::Activity curActivity;
|
||||||
|
ActivityData(const ActivityButterPressure::Activity act) : curActivity(act) {;}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* step-sensor detects steps from the accelerometer
|
||||||
|
*/
|
||||||
|
class ActivitySensor :
|
||||||
|
public SensorListener<BarometerData>, // << takes
|
||||||
|
public SensorListener<AccelerometerData>, // << takes
|
||||||
|
public Sensor<ActivityData> { // << provides
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
ActivityButterPressure act;
|
||||||
|
|
||||||
|
BarometerSensor& baro;
|
||||||
|
AccelerometerSensor& acc;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ActivitySensor(BarometerSensor& baro, AccelerometerSensor& acc) : baro(baro), acc(acc) {
|
||||||
|
baro.addListener(this);
|
||||||
|
acc.addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void start() override {
|
||||||
|
// not needed
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void stop() override {
|
||||||
|
// not needed
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return acc.isRunning() && baro.isRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onSensorData(Sensor<BarometerData>* sensor, const Timestamp ts, const BarometerData& data) override {
|
||||||
|
(void) sensor;
|
||||||
|
const ActivityButterPressure::Activity curAct = act.add(ts, data);
|
||||||
|
informListeners(ts, ActivityData(curAct));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) override {
|
||||||
|
(void) sensor;
|
||||||
|
(void) ts;
|
||||||
|
(void) data;
|
||||||
|
// TODO!
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BAROMETERACTIVITYSENSOR_H
|
||||||
@@ -33,11 +33,19 @@ public:
|
|||||||
/** stop this sensor */
|
/** stop this sensor */
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
/** whether the sensor is currently start()ed */
|
||||||
|
virtual bool isRunning() const = 0;
|
||||||
|
|
||||||
/** add the given listener to the sensor */
|
/** add the given listener to the sensor */
|
||||||
void addListener(SensorListener<T>* l) {
|
void addListener(SensorListener<T>* l) {
|
||||||
listeners.push_back(l);
|
listeners.push_back(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** remove the given listener from the sensor */
|
||||||
|
void removeListener(SensorListener<T>* l) {
|
||||||
|
listeners.erase(std::remove(listeners.begin(), listeners.end(), l), listeners.end());
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** inform all attached listeners */
|
/** inform all attached listeners */
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
#include "StepSensor.h"
|
#include "StepSensor.h"
|
||||||
#include "TurnSensor.h"
|
#include "TurnSensor.h"
|
||||||
|
#include "ActivitySensor.h"
|
||||||
|
|
||||||
|
|
||||||
class SensorFactory {
|
class SensorFactory {
|
||||||
@@ -75,6 +75,12 @@ public:
|
|||||||
return turns;
|
return turns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** get the Activity sensor */
|
||||||
|
ActivitySensor& getActivity() {
|
||||||
|
static ActivitySensor activity(getBarometer(), getAccelerometer());
|
||||||
|
return activity;
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SENSORFACTORY_H
|
#endif // SENSORFACTORY_H
|
||||||
|
|||||||
@@ -13,15 +13,18 @@ struct StepData {
|
|||||||
/**
|
/**
|
||||||
* step-sensor detects steps from the accelerometer
|
* step-sensor detects steps from the accelerometer
|
||||||
*/
|
*/
|
||||||
class StepSensor : public SensorListener<AccelerometerData>, public Sensor<StepData> {
|
class StepSensor :
|
||||||
|
public SensorListener<AccelerometerData>, // << takes
|
||||||
|
public Sensor<StepData> { // << provides
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
AccelerometerSensor& acc;
|
||||||
StepDetection sd;
|
StepDetection sd;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
StepSensor(AccelerometerSensor& acc) {
|
StepSensor(AccelerometerSensor& acc) : acc(acc) {
|
||||||
acc.addListener(this);
|
acc.addListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +36,10 @@ public:
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return acc.isRunning();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) override {
|
virtual void onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
const bool step = sd.add(ts, data);
|
const bool step = sd.add(ts, data);
|
||||||
|
|||||||
@@ -11,17 +11,23 @@ struct TurnData {
|
|||||||
TurnData() : radSinceLastEvent(0), radSinceStart(0) {;}
|
TurnData() : radSinceLastEvent(0), radSinceStart(0) {;}
|
||||||
};
|
};
|
||||||
|
|
||||||
class TurnSensor : public SensorListener<AccelerometerData>, public SensorListener<GyroscopeData>, public Sensor<TurnData> {
|
class TurnSensor :
|
||||||
|
public SensorListener<AccelerometerData>, // << takes
|
||||||
|
public SensorListener<GyroscopeData>, // << takes
|
||||||
|
public Sensor<TurnData> { // << provides
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
TurnDetection turn;
|
TurnDetection turn;
|
||||||
TurnData data;
|
TurnData data;
|
||||||
|
|
||||||
|
AccelerometerSensor& acc;
|
||||||
|
GyroscopeSensor& gyro;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** ctor */
|
/** ctor */
|
||||||
TurnSensor(AccelerometerSensor& acc, GyroscopeSensor& gyro) {
|
TurnSensor(AccelerometerSensor& acc, GyroscopeSensor& gyro) : acc(acc), gyro(gyro) {
|
||||||
acc.addListener(this);
|
acc.addListener(this);
|
||||||
gyro.addListener(this);
|
gyro.addListener(this);
|
||||||
}
|
}
|
||||||
@@ -34,6 +40,10 @@ public:
|
|||||||
//
|
//
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return acc.isRunning() && gyro.isRunning();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) override {
|
virtual void onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) override {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
turn.addAccelerometer(ts, data);
|
turn.addAccelerometer(ts, data);
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return acc.isActive();
|
||||||
|
}
|
||||||
|
|
||||||
void stop() override {
|
void stop() override {
|
||||||
throw "TODO";
|
throw "TODO";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public:
|
|||||||
void start() override {
|
void start() override {
|
||||||
|
|
||||||
auto onSensorData = [&] () {
|
auto onSensorData = [&] () {
|
||||||
BarometerData data(baro.reading()->pressure());
|
BarometerData data(baro.reading()->pressure() / 100.0f); // convert Pa to hPa
|
||||||
informListeners(data);
|
informListeners(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -42,6 +42,10 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return baro.isActive();
|
||||||
|
}
|
||||||
|
|
||||||
void stop() override {
|
void stop() override {
|
||||||
throw "TODO";
|
throw "TODO";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,10 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return gyro.isActive();
|
||||||
|
}
|
||||||
|
|
||||||
void stop() override {
|
void stop() override {
|
||||||
throw "TODO";
|
throw "TODO";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ extern "C" {
|
|||||||
JNIEXPORT void JNICALL Java_indoor_java_WiFi_onScanComplete(JNIEnv* env, jobject jobj, jbyteArray arrayID) {
|
JNIEXPORT void JNICALL Java_indoor_java_WiFi_onScanComplete(JNIEnv* env, jobject jobj, jbyteArray arrayID) {
|
||||||
(void) env; (void) jobj;
|
(void) env; (void) jobj;
|
||||||
jsize length = env->GetArrayLength(arrayID);
|
jsize length = env->GetArrayLength(arrayID);
|
||||||
jboolean isCopy;
|
jbyte* data = env->GetByteArrayElements(arrayID, 0);
|
||||||
jbyte* data = env->GetByteArrayElements(arrayID, &isCopy);
|
|
||||||
std::string str((char*)data, length);
|
std::string str((char*)data, length);
|
||||||
env->ReleaseByteArrayElements(arrayID, data, JNI_ABORT);
|
env->ReleaseByteArrayElements(arrayID, data, JNI_ABORT);
|
||||||
WiFiSensorAndroid::get().handle(str);
|
WiFiSensorAndroid::get().handle(str);
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ private:
|
|||||||
/** hidden ctor. use singleton! */
|
/** hidden ctor. use singleton! */
|
||||||
WiFiSensorAndroid() {;}
|
WiFiSensorAndroid() {;}
|
||||||
|
|
||||||
|
bool started = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** singleton access */
|
/** singleton access */
|
||||||
@@ -28,7 +30,8 @@ public:
|
|||||||
|
|
||||||
// start scanning
|
// start scanning
|
||||||
int res = QAndroidJniObject::callStaticMethod<int>("indoor/java/WiFi", "start", "()I");
|
int res = QAndroidJniObject::callStaticMethod<int>("indoor/java/WiFi", "start", "()I");
|
||||||
(void) res;
|
if (res != 0) {throw Exception("error while starting WiFi");}
|
||||||
|
started = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,8 +39,12 @@ public:
|
|||||||
throw "todo";
|
throw "todo";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return started;
|
||||||
|
}
|
||||||
|
|
||||||
/** called from java. handle the given incoming scan result */
|
/** called from java. handle the given incoming scan result */
|
||||||
void handle(const std::string& data) {
|
void handle(const std::string data) {
|
||||||
|
|
||||||
// to-be-constructed sensor data
|
// to-be-constructed sensor data
|
||||||
WiFiMeasurements sensorData;
|
WiFiMeasurements sensorData;
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ public:
|
|||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** subclasses must provide a random entry here */
|
/** subclasses must provide a random entry here */
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ public:
|
|||||||
return wifi;
|
return wifi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
void start() override {
|
void start() override {
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ public:
|
|||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isRunning() const override {
|
||||||
|
return running;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
virtual void onGyroscope(const Timestamp _ts, const GyroscopeData data) override {
|
virtual void onGyroscope(const Timestamp _ts, const GyroscopeData data) override {
|
||||||
|
|||||||
58
tests/RuntimeTests.h
Normal file
58
tests/RuntimeTests.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef RUNTIMETESTS_H
|
||||||
|
#define RUNTIMETESTS_H
|
||||||
|
|
||||||
|
#include <Indoor/sensors/radio/setup/WiFiFingerprint.h>
|
||||||
|
#include "ipin/Scaler.h"
|
||||||
|
|
||||||
|
class RuntimeTests {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void run() {
|
||||||
|
testFingerprint();
|
||||||
|
testScaler();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static void testScaler() {
|
||||||
|
|
||||||
|
IPINScaler scaler = IPINScaler(1869, 1869, 40.51312440, -3.34959080, -40.73112000, 0.07596002);
|
||||||
|
|
||||||
|
// map center
|
||||||
|
const float cenX = 1869/2.0*0.07596002;
|
||||||
|
const float cenY = 1869/2.0*0.07596002;
|
||||||
|
|
||||||
|
const IPIN lonlat = scaler.toIPIN3(cenX, cenY, 0);
|
||||||
|
Assert::isNear(40.51312440, lonlat.lat, 0.000001, "scaler error"); // lat = up/down
|
||||||
|
Assert::isNear(-3.34959080, lonlat.lon, 0.000001, "scaler error"); // lon = left/right
|
||||||
|
Assert::isNear(0.0, lonlat.floorNr, 0.1, "scaler error");
|
||||||
|
|
||||||
|
const Point3 p3 = scaler.convert3D(lonlat);
|
||||||
|
Assert::isNear(cenX, p3.x, 0.01f, "scaler error");
|
||||||
|
Assert::isNear(cenY, p3.y, 0.01f, "scaler error");
|
||||||
|
Assert::isNear(0.0f, p3.z, 0.01f, "scaler error");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void testFingerprint() {
|
||||||
|
|
||||||
|
MACAddress mac1("00:00:00:00:00:01");
|
||||||
|
MACAddress mac2("00:00:00:00:00:02");
|
||||||
|
|
||||||
|
WiFiFingerprint fp;
|
||||||
|
fp.measurements.entries.push_back( WiFiMeasurement(AccessPoint(mac1), -60));
|
||||||
|
fp.measurements.entries.push_back( WiFiMeasurement(AccessPoint(mac1), -62));
|
||||||
|
fp.measurements.entries.push_back( WiFiMeasurement(AccessPoint(mac1), -63));
|
||||||
|
fp.measurements.entries.push_back( WiFiMeasurement(AccessPoint(mac2), -71));
|
||||||
|
fp.measurements.entries.push_back( WiFiMeasurement(AccessPoint(mac2), -72));
|
||||||
|
WiFiMeasurements avg = fp.average();
|
||||||
|
Assert::equal(2, (int)avg.entries.size(), "size mismatch");
|
||||||
|
Assert::isNear(-61.666f, avg.entries[1].rssi, 0.01f, "rssi avg mismatch");
|
||||||
|
Assert::isNear(-71.500f, avg.entries[0].rssi, 0.01f, "rssi avg mismatch");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RUNTIMETESTS_H
|
||||||
92
tools/calibration/WiFiCalibrationDataModel.h
Normal file
92
tools/calibration/WiFiCalibrationDataModel.h
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#ifndef WIFICALIBMODEL_H
|
||||||
|
#define WIFICALIBMODEL_H
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <Indoor/sensors/radio/setup/WiFiFingerprint.h>
|
||||||
|
|
||||||
|
class WiFiCalibrationDataModel {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** the file to save the calibration model to */
|
||||||
|
std::string file;
|
||||||
|
|
||||||
|
/** all fingerprints (position -> measurements) within the model */
|
||||||
|
std::vector<WiFiFingerprint> fingerprints;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
WiFiCalibrationDataModel(const std::string& file) : file(file) {
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<WiFiFingerprint>& getFingerprints() {
|
||||||
|
return fingerprints;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** deserialize the model */
|
||||||
|
void load() {
|
||||||
|
|
||||||
|
// open and check
|
||||||
|
std::ifstream inp(file.c_str());
|
||||||
|
if (inp.bad() || inp.eof() || ! inp.is_open()) { return; }
|
||||||
|
|
||||||
|
// read all entries
|
||||||
|
while (!inp.eof()) {
|
||||||
|
|
||||||
|
// each section starts with [fingerprint]
|
||||||
|
std::string section;
|
||||||
|
inp >> section;
|
||||||
|
if (inp.eof()) {break;}
|
||||||
|
if (section != "[fingerprint]") {throw Exception("error!");}
|
||||||
|
|
||||||
|
// deserialize it
|
||||||
|
WiFiFingerprint wfp;
|
||||||
|
wfp.read(inp);
|
||||||
|
fingerprints.push_back(wfp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inp.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** serialize the model */
|
||||||
|
void save() {
|
||||||
|
|
||||||
|
// open and check
|
||||||
|
std::ofstream out(file.c_str());
|
||||||
|
if (out.bad()) {throw Exception("error while opening " + file + " for write");}
|
||||||
|
|
||||||
|
// write all entries
|
||||||
|
for (const WiFiFingerprint& wfp : fingerprints) {
|
||||||
|
out << "[fingerprint]\n";
|
||||||
|
wfp.write(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// done
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get the fingerprint for the given location. if no fingerprint exists, an empty one is created! */
|
||||||
|
WiFiFingerprint& getFingerprint(const Point3 pos_m) {
|
||||||
|
|
||||||
|
// try to find an existing one
|
||||||
|
for (WiFiFingerprint& wfp : fingerprints) {
|
||||||
|
// get within range of floating-point rounding issues
|
||||||
|
if (wfp.pos_m.getDistance(pos_m) < 0.001) {return wfp;}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new one and return its reference
|
||||||
|
WiFiFingerprint wfp(pos_m);
|
||||||
|
fingerprints.push_back(wfp);
|
||||||
|
return fingerprints.back();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WIFICALIBMODEL_H
|
||||||
51
tools/calibration/WiFiCalibrationScanDialog.cpp
Normal file
51
tools/calibration/WiFiCalibrationScanDialog.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include "WiFiCalibrationScanDialog.h"
|
||||||
|
|
||||||
|
|
||||||
|
WiFiCalibrationScanDialog::WiFiCalibrationScanDialog(WiFiFingerprint& model) : model(model) {
|
||||||
|
|
||||||
|
dlg->resize(300, 300);
|
||||||
|
|
||||||
|
QGridLayout* lay = new QGridLayout(dlg);
|
||||||
|
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
QPushButton* btnClear = new QPushButton(dlg);
|
||||||
|
btnClear->setText("clear");
|
||||||
|
btnClear->connect(btnClear, &QPushButton::clicked, [&] () {clear();});
|
||||||
|
lay->addWidget(btnClear, row, 0, 1, 1);
|
||||||
|
|
||||||
|
QPushButton* btnRecord = new QPushButton(dlg);
|
||||||
|
btnRecord->setText("rec");
|
||||||
|
btnRecord->connect(btnRecord, &QPushButton::clicked, [&] () {startRecord();});
|
||||||
|
lay->addWidget(btnRecord, row, 2, 1, 1);
|
||||||
|
|
||||||
|
++row;
|
||||||
|
|
||||||
|
lay->addWidget(new QLabel("point"), row, 0, 1, 1);
|
||||||
|
lblPoint = new QLabel();
|
||||||
|
lay->addWidget(lblPoint, row, 1, 1, 2);
|
||||||
|
|
||||||
|
++row;
|
||||||
|
|
||||||
|
lay->addWidget(new QLabel("stats"), row, 0, 1, 1);
|
||||||
|
lblStats = new QLabel();
|
||||||
|
lay->addWidget(lblStats, row, 1, 1, 2);
|
||||||
|
|
||||||
|
++row;
|
||||||
|
|
||||||
|
barProg = new QProgressBar();
|
||||||
|
lay->addWidget(barProg, row, 0, 1, 3);
|
||||||
|
|
||||||
|
++row;
|
||||||
|
|
||||||
|
QPushButton* btnCancel = new QPushButton(dlg);
|
||||||
|
btnCancel->setText("cancel");
|
||||||
|
btnCancel->connect(btnCancel, &QPushButton::clicked, [&] () {close();});
|
||||||
|
lay->addWidget(btnCancel, row, 0, 1, 1);
|
||||||
|
|
||||||
|
QPushButton* btnOK = new QPushButton(dlg);
|
||||||
|
btnOK->setText("OK");
|
||||||
|
btnOK->connect(btnOK, &QPushButton::clicked, [&] () {save(); close();});
|
||||||
|
lay->addWidget(btnOK, row, 2, 1, 1);
|
||||||
|
|
||||||
|
}
|
||||||
102
tools/calibration/WiFiCalibrationScanDialog.h
Normal file
102
tools/calibration/WiFiCalibrationScanDialog.h
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#ifndef CALIBDIALOG_H
|
||||||
|
#define CALIBDIALOG_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QProgressBar>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
#include "../sensors/SensorFactory.h"
|
||||||
|
#include "../tools/calibration/WiFiCalibrationDataModel.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* show a dialog to perform a WiFiScan
|
||||||
|
*/
|
||||||
|
class WiFiCalibrationScanDialog : public QObject, public SensorListener<WiFiMeasurements> {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QDialog* dlg = new QDialog();
|
||||||
|
QLabel* lblStats;
|
||||||
|
QLabel* lblPoint;
|
||||||
|
QProgressBar* barProg;
|
||||||
|
|
||||||
|
struct Scan {
|
||||||
|
const int numRecords = 10;
|
||||||
|
int recordsDone = 0;
|
||||||
|
} scan;
|
||||||
|
|
||||||
|
/** the measurements model to fill with scan-entries */
|
||||||
|
WiFiFingerprint& model;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static void get(WiFiFingerprint& model) {
|
||||||
|
WiFiCalibrationScanDialog dlg(model);
|
||||||
|
dlg.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
WiFiCalibrationScanDialog(WiFiFingerprint& model);
|
||||||
|
|
||||||
|
void show() {
|
||||||
|
refresh();
|
||||||
|
dlg->exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
stopRecord();
|
||||||
|
dlg->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void save() {
|
||||||
|
//mdl.save();;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_INVOKABLE void refresh() {
|
||||||
|
lblPoint->setText(QString(model.pos_m.asString().c_str()));
|
||||||
|
lblStats->setText( QString::number(model.measurements.entries.size()) + " RSSI measurements\n" + QString::number(scan.recordsDone) + " scans");
|
||||||
|
barProg->setValue(scan.recordsDone);
|
||||||
|
barProg->setMaximum(scan.numRecords);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
model.measurements.entries.clear();
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void startRecord() {
|
||||||
|
scan.recordsDone = 0;
|
||||||
|
SensorFactory::get().getWiFi().addListener(this);
|
||||||
|
if (!SensorFactory::get().getWiFi().isRunning()) {
|
||||||
|
SensorFactory::get().getWiFi().start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopRecord() {
|
||||||
|
SensorFactory::get().getWiFi().removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) override {
|
||||||
|
(void) sensor;
|
||||||
|
(void) ts;
|
||||||
|
++scan.recordsDone;
|
||||||
|
if (scan.recordsDone >= scan.numRecords) {stopRecord();}
|
||||||
|
model.measurements.entries.insert(model.measurements.entries.end(), data.entries.begin(), data.entries.end());
|
||||||
|
QMetaObject::invokeMethod(this, "refresh", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CALIBDIALOG_H
|
||||||
46
ui/LoggerUI.h
Normal file
46
ui/LoggerUI.h
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
#ifndef LOGGERUI_H
|
||||||
|
#define LOGGERUI_H
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include "debug/InfoWidget.h"
|
||||||
|
#include <Indoor/misc/log/Logger.h>
|
||||||
|
|
||||||
|
/** send all log-messages to the UI */
|
||||||
|
class LoggerUI : public Logger {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
InfoWidget* iw;
|
||||||
|
|
||||||
|
std::vector<QString> lines;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor with the main-menu to show the log within */
|
||||||
|
LoggerUI(InfoWidget* iw) : iw(iw) {
|
||||||
|
lines.push_back("");
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const std::string& str, const bool nl) override {
|
||||||
|
lines.back() += QString(str.c_str());
|
||||||
|
if (nl) {lines.push_back("");}
|
||||||
|
while(lines.size() > 4) {lines.erase(lines.begin());}
|
||||||
|
QString qs = getStr();
|
||||||
|
QMetaObject::invokeMethod(iw, "showLog", Qt::QueuedConnection, Q_ARG(const QString&, qs));
|
||||||
|
QApplication::processEvents();
|
||||||
|
//mm->showActivity(getStr());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QString getStr() const {
|
||||||
|
QString str;
|
||||||
|
for (const QString& line : lines) {str += line + "\n";}
|
||||||
|
str.remove(str.length()-1, 1);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LOGGERUI_H
|
||||||
@@ -2,33 +2,58 @@
|
|||||||
|
|
||||||
#include <QResizeEvent>
|
#include <QResizeEvent>
|
||||||
|
|
||||||
#include "map/MapView.h"
|
#include "map/3D/MapView3D.h"
|
||||||
|
#include "map/2D/MapView2D.h"
|
||||||
|
|
||||||
#include "menu/MainMenu.h"
|
#include "menu/MainMenu.h"
|
||||||
#include "debug/SensorDataWidget.h"
|
#include "debug/SensorDataWidget.h"
|
||||||
|
#include "debug/InfoWidget.h"
|
||||||
|
#include "UIHelper.h"
|
||||||
|
|
||||||
|
#include <QGridLayout>
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
|
MainWindow::MainWindow(QWidget *parent) : QWidget(parent) {
|
||||||
|
|
||||||
setMinimumHeight(500);
|
setMinimumHeight(500);
|
||||||
setMinimumWidth(500);
|
setMinimumWidth(500);
|
||||||
|
|
||||||
mapView = new MapView(this);
|
mapView3D = new MapView3D(this);
|
||||||
|
mapView2D = new MapView2D(this);
|
||||||
|
|
||||||
mainMenu = new MainMenu(this);
|
mainMenu = new MainMenu(this);
|
||||||
sensorWidget = new SensorDataWidget(this);
|
infoWidget = new InfoWidget(this);
|
||||||
|
sensorWidget = new SensorDataWidget(this); sensorWidget->setVisible(false);
|
||||||
|
|
||||||
//sensorWidget->setVisible(false);
|
//sensorWidget->setVisible(false);
|
||||||
showMaximized();
|
showMaximized();
|
||||||
|
|
||||||
|
sleep(1);
|
||||||
|
emit resizeEvent(nullptr);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::resizeEvent(QResizeEvent* event) {
|
void MainWindow::resizeEvent(QResizeEvent* event) {
|
||||||
|
|
||||||
const int w = event->size().width();
|
const int w = this->width();
|
||||||
const int h = event->size().height();
|
const int h = this->height();
|
||||||
|
|
||||||
|
const int menuH = UIHelper::getMainMenuHeight(this);
|
||||||
|
const int infoH = UIHelper::getInfoHeight(this);
|
||||||
|
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
|
mainMenu->setGeometry(0,y,w,menuH); y += menuH;
|
||||||
|
infoWidget->setGeometry(0,y,w,infoH); y += infoH;
|
||||||
|
|
||||||
|
mapView3D->setGeometry(0,y,w,h-y);
|
||||||
|
mapView2D->setGeometry(0,y,w,h-y);
|
||||||
|
|
||||||
|
sensorWidget->setGeometry(0,y,w,h-y);
|
||||||
|
|
||||||
|
mainMenu->resizeEvent(event);
|
||||||
|
mapView2D->resizeEvent(event);
|
||||||
|
// infoWidget->resizeEvent(event);
|
||||||
|
|
||||||
mapView->setGeometry(0,0,w,h);
|
|
||||||
mainMenu->setGeometry(0,0,w,64);
|
|
||||||
sensorWidget->setGeometry(0,64,w,h-64);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,12 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class MapView;
|
class MapView3D;
|
||||||
|
class MapView2D;
|
||||||
|
|
||||||
class MainMenu;
|
class MainMenu;
|
||||||
class SensorDataWidget;
|
class SensorDataWidget;
|
||||||
|
class InfoWidget;
|
||||||
|
|
||||||
class MainWindow : public QWidget {
|
class MainWindow : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -17,21 +20,22 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
MapView* mapView = nullptr;
|
MapView3D* mapView3D = nullptr;
|
||||||
|
MapView2D* mapView2D = nullptr;
|
||||||
|
|
||||||
MainMenu* mainMenu = nullptr;
|
MainMenu* mainMenu = nullptr;
|
||||||
|
InfoWidget* infoWidget = nullptr;
|
||||||
SensorDataWidget* sensorWidget = nullptr;
|
SensorDataWidget* sensorWidget = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MapView* getMapView() const {return mapView;}
|
MapView3D* getMapView3D() const {return mapView3D;}
|
||||||
|
MapView2D* getMapView2D() const {return mapView2D;}
|
||||||
|
|
||||||
MainMenu* getMainMenu() const {return mainMenu;}
|
MainMenu* getMainMenu() const {return mainMenu;}
|
||||||
|
InfoWidget* getInfoWidget() const {return infoWidget;}
|
||||||
SensorDataWidget* getSensorDataWidget() const {return sensorWidget;}
|
SensorDataWidget* getSensorDataWidget() const {return sensorWidget;}
|
||||||
|
|
||||||
|
|
||||||
// void setMapView(QWidget* widget) {mapView = widget; mapView->setParent(this);}
|
|
||||||
// void setMainMenu(QWidget* widget) {mainMenu = widget; mainMenu->setParent(this);}
|
|
||||||
// void setSensorWidget(QWidget* widget) {sensorWidget = widget; sensorWidget->setParent(this);}
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|||||||
39
ui/UIHelper.h
Normal file
39
ui/UIHelper.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef UIHELPER_H
|
||||||
|
#define UIHELPER_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class UIHelper {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static int getButtonSize(const QObject* window) {
|
||||||
|
return isLarge(window) ? (48*2) : (48);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getMainMenuHeight(const QObject* window) {
|
||||||
|
return isLarge(window) ? (64*2) : (64);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getInfoHeight(const QObject* window) {
|
||||||
|
return isLarge(window) ? (70*2) : (70);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getPlotHeight(const QObject* window) {
|
||||||
|
return isLarge(window) ? (90*2) : (90);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getWifiLabelDistY(const QObject* window) {
|
||||||
|
return isLarge(window) ? (13*2) : (13);
|
||||||
|
}
|
||||||
|
static int getWifiLabelDistX(const QObject* window) {
|
||||||
|
return isLarge(window) ? (150*2) : (150);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isLarge(const QObject* window) {
|
||||||
|
return (((QWidget*)window)->height() > 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // UIHELPER_H
|
||||||
67
ui/debug/InfoWidget.cpp
Normal file
67
ui/debug/InfoWidget.cpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#include "InfoWidget.h"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QGridLayout>
|
||||||
|
|
||||||
|
#include <Indoor/Assertions.h>
|
||||||
|
|
||||||
|
InfoWidget::InfoWidget(QWidget *parent) : QWidget(parent) {
|
||||||
|
|
||||||
|
//setMinimumHeight(32);
|
||||||
|
//setMaximumHeight(32);
|
||||||
|
|
||||||
|
QGridLayout* lay = new QGridLayout(this);
|
||||||
|
int row = 0;
|
||||||
|
int col = 0;
|
||||||
|
|
||||||
|
lblActivity = new QLabel();
|
||||||
|
lblActivity->setText("-");
|
||||||
|
//lblActivity->setStyleSheet("QLabel { color : white; }");
|
||||||
|
//lblActivity->setFont(QFont("courier", 9));
|
||||||
|
lay->addWidget(lblActivity, row, col, 1,1,Qt::AlignLeft); ++row;
|
||||||
|
lblActivity->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
lblFilterTime = new QLabel();
|
||||||
|
lblFilterTime->setText("-");
|
||||||
|
//lblFilterTime->setStyleSheet("QLabel { color : white; }");
|
||||||
|
//lblFilterTime->setFont(QFont("courier", 9));
|
||||||
|
lay->addWidget(lblFilterTime, row, col, 1,1,Qt::AlignLeft); ++row;
|
||||||
|
lblFilterTime->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
// lblMapViewTime = new QLabel();
|
||||||
|
// lblMapViewTime->setText("-");
|
||||||
|
// //lblMapViewTime->setStyleSheet("QLabel { color : white; }");
|
||||||
|
// //lblMapViewTime->setFont(QFont("courier", 9));
|
||||||
|
// lay->addWidget(lblMapViewTime, row, col, 1,1,Qt::AlignLeft); ++row;
|
||||||
|
// lblMapViewTime->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
col = 1;
|
||||||
|
row = 0;
|
||||||
|
|
||||||
|
lblLog = new QLabel(this);
|
||||||
|
lblLog->setText("-");
|
||||||
|
//lblLog->setStyleSheet("QLabel { color : white; }");
|
||||||
|
lblLog->setFont(QFont("Arial", 8));
|
||||||
|
lay->addWidget(lblLog, row, col, 3, 1);
|
||||||
|
lblLog->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoWidget::showActivity(const QString& act) {
|
||||||
|
lblActivity->setText("Activity: " + act);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoWidget::showFilterTime(const QString& act) {
|
||||||
|
lblFilterTime->setText("Filtering: " + act);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoWidget::showMapViewTime(const QString& act) {
|
||||||
|
lblMapViewTime->setText("MapView: " + act);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InfoWidget::showLog(const QString& info) {
|
||||||
|
lblLog->setText(info);
|
||||||
|
}
|
||||||
|
|
||||||
35
ui/debug/InfoWidget.h
Normal file
35
ui/debug/InfoWidget.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef INFOWIDGET_H
|
||||||
|
#define INFOWIDGET_H
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
|
|
||||||
|
class InfoWidget : public QWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
QLabel* lblActivity;
|
||||||
|
QLabel* lblFilterTime;
|
||||||
|
QLabel* lblMapViewTime;
|
||||||
|
QLabel* lblLog;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit InfoWidget(QWidget *parent = 0);
|
||||||
|
|
||||||
|
Q_INVOKABLE void showActivity(const QString& act);
|
||||||
|
Q_INVOKABLE void showFilterTime(const QString& act);
|
||||||
|
Q_INVOKABLE void showMapViewTime(const QString& act);
|
||||||
|
Q_INVOKABLE void showLog(const QString& info);
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // INFOWIDGET_H
|
||||||
@@ -6,7 +6,9 @@ PlotTurns::PlotTurns(QWidget *parent) : QWidget(parent) {
|
|||||||
setMinimumWidth(96);
|
setMinimumWidth(96);
|
||||||
setMinimumHeight(96);
|
setMinimumHeight(96);
|
||||||
|
|
||||||
resize(96, 96);
|
//setSizeIncrement(QSize(1,1));
|
||||||
|
//setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding));
|
||||||
|
// resize(96, 96);
|
||||||
|
|
||||||
// setMaximumWidth(64);
|
// setMaximumWidth(64);
|
||||||
// setMaximumHeight(64);
|
// setMaximumHeight(64);
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ public:
|
|||||||
|
|
||||||
void add(const Timestamp ts, const TurnData& data);
|
void add(const Timestamp ts, const TurnData& data);
|
||||||
|
|
||||||
|
//QSize sizeHint() const {return QSize(96, 96);}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|||||||
@@ -3,12 +3,18 @@
|
|||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QStaticText>
|
#include <QStaticText>
|
||||||
|
#include "../UIHelper.h"
|
||||||
|
|
||||||
PlotWiFiScan::PlotWiFiScan(QWidget *parent) : QWidget(parent) {
|
PlotWiFiScan::PlotWiFiScan(QWidget *parent) : QWidget(parent) {
|
||||||
|
|
||||||
setMinimumWidth(96);
|
setMinimumWidth(96);
|
||||||
setMinimumHeight(96);
|
setMinimumHeight(96);
|
||||||
|
|
||||||
|
|
||||||
|
//setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
// setMaximumHeight(300);
|
||||||
|
// sets
|
||||||
//setAutoFillBackground(false);
|
//setAutoFillBackground(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -24,13 +30,15 @@ void PlotWiFiScan::paintEvent(QPaintEvent* evt) {
|
|||||||
(void) evt;
|
(void) evt;
|
||||||
QPainter p(this);
|
QPainter p(this);
|
||||||
|
|
||||||
const int x0 = 4; const int xw = 150;
|
const int x0 = 4; const int xw = UIHelper::getWifiLabelDistX(this->parent());
|
||||||
const int y0 = 3;
|
const int y0 = 3;
|
||||||
const int lh = 13;
|
const int lh = UIHelper::getWifiLabelDistY(this->parent());
|
||||||
|
|
||||||
int x = x0;
|
int x = x0;
|
||||||
int y = y0;
|
int y = y0;
|
||||||
|
|
||||||
|
int w = width();
|
||||||
|
int h = height();
|
||||||
|
|
||||||
p.fillRect(0,0,width(),height(),QColor(255,255,255,192));
|
p.fillRect(0,0,width(),height(),QColor(255,255,255,192));
|
||||||
p.setPen(Qt::black);
|
p.setPen(Qt::black);
|
||||||
@@ -45,7 +53,7 @@ void PlotWiFiScan::paintEvent(QPaintEvent* evt) {
|
|||||||
std::string str = mac + ": " + std::to_string((int)m.getRSSI());
|
std::string str = mac + ": " + std::to_string((int)m.getRSSI());
|
||||||
p.drawStaticText(x, y, QStaticText(str.c_str()));
|
p.drawStaticText(x, y, QStaticText(str.c_str()));
|
||||||
y += lh;
|
y += lh;
|
||||||
if (y > 90) {y = y0; x += xw;}
|
if (y > this->height()-10) {y = y0; x += xw;}
|
||||||
}
|
}
|
||||||
|
|
||||||
p.end();
|
p.end();
|
||||||
|
|||||||
@@ -9,10 +9,15 @@
|
|||||||
#include "PlotTurns.h"
|
#include "PlotTurns.h"
|
||||||
#include "PlotWiFiScan.h"
|
#include "PlotWiFiScan.h"
|
||||||
|
|
||||||
|
#include "../Settings.h"
|
||||||
|
#include "../UIHelper.h"
|
||||||
|
|
||||||
template <typename Data> void removeOld(Data& data, const Timestamp limit) {
|
/** helper method to remove old entries */
|
||||||
if (data.size() < 2) {return;}
|
template <typename Data> void removeOld(Data& data, const Data& dataRef, const Timestamp limit) {
|
||||||
while ( (data.back().key - data.front().key) > limit.ms()) {
|
if (data.size() == 0) {return;}
|
||||||
|
if (dataRef.size() == 0) {return;}
|
||||||
|
while ( (dataRef.back().key - data.front().key) > limit.ms()) {
|
||||||
|
if (data.size() == 0) {return;}
|
||||||
data.remove(0);
|
data.remove(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41,7 +46,7 @@ public:
|
|||||||
Timestamp lastRefresh;
|
Timestamp lastRefresh;
|
||||||
bool needsRefresh(const Timestamp ts) {
|
bool needsRefresh(const Timestamp ts) {
|
||||||
const Timestamp diff = ts - lastRefresh;
|
const Timestamp diff = ts - lastRefresh;
|
||||||
return (diff > Timestamp::fromMS(100));
|
return (diff > Settings::SensorDebug::updateEvery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -68,7 +73,7 @@ public:
|
|||||||
steps.setColor(colors[2]);
|
steps.setColor(colors[2]);
|
||||||
steps.setPointSize(8);
|
steps.setPointSize(8);
|
||||||
pc.addPlot(&steps);
|
pc.addPlot(&steps);
|
||||||
const float s = 4.2;
|
const float s = 4.8;
|
||||||
const float ref = 9.81;
|
const float ref = 9.81;
|
||||||
pc.setValRange(Range(ref-s, ref+s));
|
pc.setValRange(Range(ref-s, ref+s));
|
||||||
}
|
}
|
||||||
@@ -89,10 +94,10 @@ public:
|
|||||||
|
|
||||||
void limit() {
|
void limit() {
|
||||||
const Timestamp limit = Timestamp::fromMS(3000);
|
const Timestamp limit = Timestamp::fromMS(3000);
|
||||||
removeOld(line[0].getData(), limit);
|
removeOld(line[0].getData(), line[0].getData(), limit);
|
||||||
removeOld(line[1].getData(), limit);
|
removeOld(line[1].getData(), line[0].getData(), limit);
|
||||||
removeOld(line[2].getData(), limit);
|
removeOld(line[2].getData(), line[0].getData(), limit);
|
||||||
removeOld(steps.getData(), limit - Timestamp::fromMS(100)); // remove steps a little before. prevents errors
|
removeOld( steps.getData(), line[0].getData(), limit); // remove steps a little before. prevents errors
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
@@ -102,7 +107,7 @@ class PlotGyro : public PlotXLines<3> {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
PlotGyro(QWidget* parent) : PlotXLines(parent) {
|
PlotGyro(QWidget* parent) : PlotXLines(parent) {
|
||||||
const float s = 1;
|
const float s = 1.5;
|
||||||
const float ref = 0;
|
const float ref = 0;
|
||||||
pc.setValRange(Range(ref-s, ref+s));
|
pc.setValRange(Range(ref-s, ref+s));
|
||||||
}
|
}
|
||||||
@@ -119,14 +124,14 @@ public:
|
|||||||
|
|
||||||
void limit() {
|
void limit() {
|
||||||
const Timestamp limit = Timestamp::fromMS(3000);
|
const Timestamp limit = Timestamp::fromMS(3000);
|
||||||
removeOld(line[0].getData(), limit);
|
removeOld(line[0].getData(), line[0].getData(), limit);
|
||||||
removeOld(line[1].getData(), limit);
|
removeOld(line[1].getData(), line[0].getData(), limit);
|
||||||
removeOld(line[2].getData(), limit);
|
removeOld(line[2].getData(), line[0].getData(), limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlotBaro : public PlotXLines<1> {
|
class PlotBaro : public PlotXLines<2> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -135,55 +140,92 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void add(const Timestamp ts, const BarometerData& data) {
|
void add(const Timestamp ts, const BarometerData& data) {
|
||||||
|
|
||||||
|
static int skip = 0;
|
||||||
|
if ((++skip % 8) != 0) {return;}
|
||||||
|
|
||||||
addLineNode(ts, data.hPa, 0);
|
addLineNode(ts, data.hPa, 0);
|
||||||
if (needsRefresh(ts)) {
|
if (needsRefresh(ts)) {
|
||||||
limit();
|
limit();
|
||||||
refresh(ts);
|
refresh(ts);
|
||||||
}
|
}
|
||||||
const float s = 0.5;
|
const float s = 1.0;
|
||||||
const float ref = line[0].getData().front().val;
|
const float ref = line[0].getData().front().val;
|
||||||
pc.setValRange(Range(ref-s, ref+s));
|
pc.setValRange(Range(ref-s, ref+s));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add(const Timestamp ts, const ActivityData& data) {
|
||||||
|
|
||||||
|
static int skip = 0;
|
||||||
|
if ((++skip % 8) != 0) {return;}
|
||||||
|
|
||||||
|
float offset = 0;
|
||||||
|
switch(data.curActivity) {
|
||||||
|
case ActivityButterPressure::Activity::DOWN: offset = -0.5; break;
|
||||||
|
case ActivityButterPressure::Activity::UP: offset = +0.5; break;
|
||||||
|
case ActivityButterPressure::Activity::STAY: offset = +0.1; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
addLineNode(ts, line[0].getData().front().val + offset, 1);
|
||||||
|
if (needsRefresh(ts)) {
|
||||||
|
limit();
|
||||||
|
refresh(ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void limit() {
|
void limit() {
|
||||||
removeOld(line[0].getData(), Timestamp::fromMS(8000));
|
// no limit!
|
||||||
|
//removeOld(line[0].getData(), Timestamp::fromMS(15000)); // 15 second values
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class PlotTurn : public QWidget {
|
//class PlotTurn : public QWidget {
|
||||||
|
|
||||||
};
|
//};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SensorDataWidget::SensorDataWidget(QWidget* parent) : QWidget(parent) {
|
SensorDataWidget::SensorDataWidget(QWidget* parent) : QWidget(parent) {
|
||||||
|
|
||||||
QGridLayout* lay = new QGridLayout(this);
|
|
||||||
|
|
||||||
plotGyro = new PlotGyro(this);
|
plotGyro = new PlotGyro(this);
|
||||||
plotAcc = new PlotAcc(this);
|
plotAcc = new PlotAcc(this);
|
||||||
plotBaro = new PlotBaro(this);
|
plotBaro = new PlotBaro(this);
|
||||||
plotTurn = new PlotTurns(this);
|
plotTurn = new PlotTurns(this);
|
||||||
plotWiFi = new PlotWiFiScan(this);
|
plotWiFi = new PlotWiFiScan(this);
|
||||||
|
|
||||||
lay->addWidget(plotGyro, 0, 0, 1, 4, Qt::AlignTop);
|
// layout setup
|
||||||
lay->addWidget(plotAcc, 1, 0, 1, 4, Qt::AlignTop);
|
lay = new QGridLayout(this);
|
||||||
lay->addWidget(plotBaro, 2, 0, 1, 4, Qt::AlignTop);
|
lay->addWidget(plotGyro, 0, 0, 1, 4);
|
||||||
lay->addWidget(plotTurn, 3, 0, 1, 1, Qt::AlignTop);
|
lay->addWidget(plotAcc, 1, 0, 1, 4);
|
||||||
lay->addWidget(plotWiFi, 3, 1, 1, 3, Qt::AlignTop);
|
lay->addWidget(plotBaro, 2, 0, 1, 4);
|
||||||
|
lay->addWidget(plotTurn, 3, 0, 1, 1);
|
||||||
|
lay->addWidget(plotWiFi, 3, 1, 1, 3);
|
||||||
|
|
||||||
|
// lay->setRowStretch(0, 1);
|
||||||
|
// lay->setRowStretch(1, 1);
|
||||||
|
// lay->setRowStretch(2, 10);
|
||||||
|
// lay->setRowStretch(3, 10);
|
||||||
|
// lay->setVerticalSpacing(5);
|
||||||
|
// lay->setHorizontalSpacing(5);
|
||||||
|
// lay->setSizeConstraint(QGridLayout::SetDefaultConstraint);
|
||||||
|
|
||||||
|
// attach as listener to all sensors we want to debug
|
||||||
SensorFactory::get().getAccelerometer().addListener(this);
|
SensorFactory::get().getAccelerometer().addListener(this);
|
||||||
SensorFactory::get().getGyroscope().addListener(this);
|
SensorFactory::get().getGyroscope().addListener(this);
|
||||||
SensorFactory::get().getBarometer().addListener(this);
|
SensorFactory::get().getBarometer().addListener(this);
|
||||||
SensorFactory::get().getSteps().addListener(this);
|
SensorFactory::get().getSteps().addListener(this);
|
||||||
SensorFactory::get().getTurns().addListener(this);
|
SensorFactory::get().getTurns().addListener(this);
|
||||||
SensorFactory::get().getWiFi().addListener(this);
|
SensorFactory::get().getWiFi().addListener(this);
|
||||||
|
SensorFactory::get().getActivity().addListener(this);
|
||||||
//setAutoFillBackground(false);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SensorDataWidget::onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) {
|
void SensorDataWidget::onSensorData(Sensor<AccelerometerData>* sensor, const Timestamp ts, const AccelerometerData& data) {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
((PlotAcc*)plotAcc)->add(ts, data);
|
((PlotAcc*)plotAcc)->add(ts, data);
|
||||||
@@ -205,6 +247,11 @@ void SensorDataWidget::onSensorData(Sensor<BarometerData>* sensor, const Timesta
|
|||||||
((PlotBaro*)plotBaro)->add(ts, data);
|
((PlotBaro*)plotBaro)->add(ts, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SensorDataWidget::onSensorData(Sensor<ActivityData>* sensor, const Timestamp ts, const ActivityData& data) {
|
||||||
|
(void) sensor;
|
||||||
|
((PlotBaro*)plotBaro)->add(ts, data);
|
||||||
|
}
|
||||||
|
|
||||||
void SensorDataWidget::onSensorData(Sensor<TurnData>* sensor, const Timestamp ts, const TurnData& data) {
|
void SensorDataWidget::onSensorData(Sensor<TurnData>* sensor, const Timestamp ts, const TurnData& data) {
|
||||||
(void) sensor;
|
(void) sensor;
|
||||||
((PlotTurns*)plotTurn)->add(ts, data);
|
((PlotTurns*)plotTurn)->add(ts, data);
|
||||||
@@ -214,4 +261,3 @@ void SensorDataWidget::onSensorData(Sensor<WiFiMeasurements>* sensor, const Time
|
|||||||
(void) sensor;
|
(void) sensor;
|
||||||
((PlotWiFiScan*)plotWiFi)->add(ts, data);
|
((PlotWiFiScan*)plotWiFi)->add(ts, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,10 @@
|
|||||||
#include "../sensors/StepSensor.h"
|
#include "../sensors/StepSensor.h"
|
||||||
#include "../sensors/TurnSensor.h"
|
#include "../sensors/TurnSensor.h"
|
||||||
#include "../sensors/WiFiSensor.h"
|
#include "../sensors/WiFiSensor.h"
|
||||||
|
#include "../sensors/ActivitySensor.h"
|
||||||
|
|
||||||
class PlotWidget;
|
class PlotWidget;
|
||||||
|
class QGridLayout;
|
||||||
|
|
||||||
/** debug display for sensor data */
|
/** debug display for sensor data */
|
||||||
class SensorDataWidget :
|
class SensorDataWidget :
|
||||||
@@ -21,6 +23,7 @@ class SensorDataWidget :
|
|||||||
public SensorListener<AccelerometerData>,
|
public SensorListener<AccelerometerData>,
|
||||||
public SensorListener<GyroscopeData>,
|
public SensorListener<GyroscopeData>,
|
||||||
public SensorListener<BarometerData>,
|
public SensorListener<BarometerData>,
|
||||||
|
public SensorListener<ActivityData>,
|
||||||
public SensorListener<StepData>,
|
public SensorListener<StepData>,
|
||||||
public SensorListener<TurnData>,
|
public SensorListener<TurnData>,
|
||||||
public SensorListener<WiFiMeasurements> {
|
public SensorListener<WiFiMeasurements> {
|
||||||
@@ -28,6 +31,7 @@ class SensorDataWidget :
|
|||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
SensorDataWidget(QWidget* parent);
|
SensorDataWidget(QWidget* parent);
|
||||||
@@ -38,6 +42,7 @@ public:
|
|||||||
void onSensorData(Sensor<StepData>* sensor, const Timestamp ts, const StepData& data) override;
|
void onSensorData(Sensor<StepData>* sensor, const Timestamp ts, const StepData& data) override;
|
||||||
void onSensorData(Sensor<TurnData>* sensor, const Timestamp ts, const TurnData& data) override;
|
void onSensorData(Sensor<TurnData>* sensor, const Timestamp ts, const TurnData& data) override;
|
||||||
void onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) override;
|
void onSensorData(Sensor<WiFiMeasurements>* sensor, const Timestamp ts, const WiFiMeasurements& data) override;
|
||||||
|
void onSensorData(Sensor<ActivityData>* sensor, const Timestamp ts, const ActivityData& data) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -47,6 +52,8 @@ private:
|
|||||||
QWidget* plotTurn;
|
QWidget* plotTurn;
|
||||||
QWidget* plotWiFi;
|
QWidget* plotWiFi;
|
||||||
|
|
||||||
|
QGridLayout* lay;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "LoadSetupDialog.h"
|
#include "LoadSetupDialog.h"
|
||||||
|
#include "../misc/fixc11.h"
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
@@ -10,13 +11,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <Indoor/Assertions.h>
|
#include <Indoor/Assertions.h>
|
||||||
|
#include "../Settings.h"
|
||||||
#include "../Config.h"
|
|
||||||
|
|
||||||
LoadSetupDialog::LoadSetupDialog() {
|
LoadSetupDialog::LoadSetupDialog() {
|
||||||
|
|
||||||
// the folder all map-setups reside within
|
// the folder all map-setups reside within
|
||||||
const std::string base = Config::getMapDir();
|
const std::string base = Settings::Data::getMapDir();
|
||||||
QDir mapFolder(QString(base.c_str()));
|
QDir mapFolder(QString(base.c_str()));
|
||||||
|
|
||||||
// sanity check. folder must exist
|
// sanity check. folder must exist
|
||||||
|
|||||||
120
ui/map/2D/ColorPoints2D.h
Normal file
120
ui/map/2D/ColorPoints2D.h
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
#ifndef COLORPOINTS2D_H
|
||||||
|
#define COLORPOINTS2D_H
|
||||||
|
|
||||||
|
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||||
|
#include "Renderable2D.h"
|
||||||
|
#include <Indoor/geo/Point3.h>
|
||||||
|
|
||||||
|
#include <Indoor/grid/Grid.h>
|
||||||
|
|
||||||
|
#include <KLib/math/filter/particles/Particle.h>
|
||||||
|
#include "../nav/Node.h"
|
||||||
|
#include "../nav/State.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debug color points
|
||||||
|
*/
|
||||||
|
class ColorPoints2D : public Renderable2D {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
struct PT {
|
||||||
|
Point3 pos;
|
||||||
|
QColor color;
|
||||||
|
PT(const Point3 pos, const QColor color) : pos(pos), color(color) {;}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<PT> points;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
ColorPoints2D() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void showGridImportance(Grid<MyGridNode>* grid) {
|
||||||
|
|
||||||
|
float min = +INFINITY;
|
||||||
|
float max = -INFINITY;
|
||||||
|
|
||||||
|
for (const MyGridNode& n : *grid) {
|
||||||
|
const float f = n.getWalkImportance();
|
||||||
|
if (f < min) {min = f;}
|
||||||
|
if (f > max) {max = f;}
|
||||||
|
}
|
||||||
|
|
||||||
|
max = 1.2;
|
||||||
|
|
||||||
|
for (const MyGridNode& n : *grid) {
|
||||||
|
const Point3 pt(n.x_cm/100.0f, n.y_cm/100.0f + 0.1f, n.z_cm/100.0f);
|
||||||
|
const float f = n.getWalkImportance();
|
||||||
|
float h = 0.66 - ((f-min)/(max-min)) * 0.66; // 0.66 is blue on the HSV-scale
|
||||||
|
if (h < 0) {h = 0;}
|
||||||
|
if (h > 1) {h = 1;}
|
||||||
|
const QColor color = QColor::fromHsvF(h, 1, 1);
|
||||||
|
points.push_back(PT(pt, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** NOTE: must be called from Qt's main thread! */
|
||||||
|
template <typename T> void setFromParticles(const std::vector<K::Particle<T>>& particles) {
|
||||||
|
|
||||||
|
points.clear();
|
||||||
|
|
||||||
|
// group particles by grid-point
|
||||||
|
std::unordered_map<GridPoint, float> weights;
|
||||||
|
for (const K::Particle<T>& p : particles) {
|
||||||
|
const GridPoint gp = p.state.position;
|
||||||
|
if (weights.find(gp) != weights.end()) {continue;}
|
||||||
|
weights[gp] += p.weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find min/max
|
||||||
|
float min = +INFINITY;
|
||||||
|
float max = -INFINITY;
|
||||||
|
for (auto it : weights) {
|
||||||
|
if (it.second > max) {max = it.second;}
|
||||||
|
if (it.second < min) {min = it.second;}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw colored
|
||||||
|
for (auto it : weights) {
|
||||||
|
const GridPoint gp = it.first;
|
||||||
|
const float w = it.second;
|
||||||
|
const float p = (w-min) / (max-min); // [0:1]
|
||||||
|
const Point3 pt(gp.x_cm/100.0f, gp.y_cm/100.0f + 0.1f, gp.z_cm/100.0f);
|
||||||
|
float h = 0.66 - (p*0.66); // 0.66 is blue on the HSV-scale
|
||||||
|
const QColor color = QColor::fromHsvF(h, 1, 1);
|
||||||
|
points.push_back(PT(pt, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void doRender(QPainter& qp, const Scaler2D& s, const RenderParams2D& r) override {
|
||||||
|
|
||||||
|
QPen pen;
|
||||||
|
pen.setWidth(4);
|
||||||
|
|
||||||
|
for (const PT& pt : points) {
|
||||||
|
|
||||||
|
if (pt.pos.z < r.clip.belowHeight_m) {continue;}
|
||||||
|
if (pt.pos.z > r.clip.aboveHeight_m) {continue;}
|
||||||
|
|
||||||
|
const Point2 p2 = s.mapToScreen(pt.pos.xy());
|
||||||
|
|
||||||
|
pen.setColor(pt.color);
|
||||||
|
qp.setPen(pen);
|
||||||
|
qp.drawPoint(p2.x, p2.y);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COLORPOINTS2D_H
|
||||||
62
ui/map/2D/Floor2D.h
Normal file
62
ui/map/2D/Floor2D.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#ifndef FLOOR2D_H
|
||||||
|
#define FLOOR2D_H
|
||||||
|
|
||||||
|
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||||
|
#include "Renderable2D.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* draw the floor itself (outline, obstacles)
|
||||||
|
*/
|
||||||
|
class Floor2D : public Renderable2D {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Floorplan::Floor* floor;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
Floor2D(Floorplan::Floor* floor) : floor(floor) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void doRender(QPainter& qp, const Scaler2D& s, const RenderParams2D& r) override {
|
||||||
|
|
||||||
|
if (floor->atHeight < r.clip.belowHeight_m) {return;}
|
||||||
|
if (floor->atHeight > r.clip.aboveHeight_m) {return;}
|
||||||
|
|
||||||
|
qp.setPen(Qt::black);
|
||||||
|
for (const Floorplan::FloorObstacle* obs : floor->obstacles) {
|
||||||
|
const Floorplan::FloorObstacleLine* line = dynamic_cast<const Floorplan::FloorObstacleLine*>(obs);
|
||||||
|
if (line) {drawLine(qp, s, line);}
|
||||||
|
}
|
||||||
|
|
||||||
|
qp.setPen(Qt::gray);
|
||||||
|
for (const Floorplan::FloorOutlinePolygon* poly : floor->outline) {
|
||||||
|
drawOutline(qp, s, poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void drawLine(QPainter& qp, const Scaler2D& s, const Floorplan::FloorObstacleLine* line) {
|
||||||
|
const Point2 pt1 = s.mapToScreen(line->from);
|
||||||
|
const Point2 pt2 = s.mapToScreen(line->to);
|
||||||
|
qp.drawLine(pt1.x, pt1.y, pt2.x, pt2.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawOutline(QPainter& qp, const Scaler2D& s, const Floorplan::FloorOutlinePolygon* poly) {
|
||||||
|
const int num = poly->poly.points.size();
|
||||||
|
for (int i = 0; i < num; ++i) {
|
||||||
|
const Point2 pt1 = s.mapToScreen(poly->poly.points[(i+0)]);
|
||||||
|
const Point2 pt2 = s.mapToScreen(poly->poly.points[(i+1)%num]);
|
||||||
|
qp.drawLine(pt1.x, pt1.y, pt2.x, pt2.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FLOOR2D_H
|
||||||
20
ui/map/2D/HasSelectableNodes.h
Normal file
20
ui/map/2D/HasSelectableNodes.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#ifndef HASSELECTABLENODES_H
|
||||||
|
#define HASSELECTABLENODES_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <KLib/geo/Point2.h>
|
||||||
|
|
||||||
|
class HasSelectableNodes {
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~HasSelectableNodes() {;}
|
||||||
|
|
||||||
|
virtual std::vector<Point2> getNodes() const = 0;
|
||||||
|
|
||||||
|
virtual void selectNode(const int idx) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // HASSELECTABLENODES_H
|
||||||
184
ui/map/2D/MapView2D.cpp
Normal file
184
ui/map/2D/MapView2D.cpp
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
#include "MapView2D.h"
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QGridLayout>
|
||||||
|
|
||||||
|
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||||
|
|
||||||
|
#include "Floor2D.h"
|
||||||
|
#include "ColorPoints2D.h"
|
||||||
|
#include "Path2D.h"
|
||||||
|
#include "WiFiCalibTool.h"
|
||||||
|
|
||||||
|
#include "../../Icons.h"
|
||||||
|
#include "../../UIHelper.h"
|
||||||
|
|
||||||
|
|
||||||
|
MapView2D::MapView2D(QWidget *parent) : QWidget(parent) {
|
||||||
|
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
setRenderHeight(0);
|
||||||
|
|
||||||
|
colorPoints = new ColorPoints2D();
|
||||||
|
elements.push_back(colorPoints);
|
||||||
|
|
||||||
|
pathToDest = new Path2D();
|
||||||
|
pathToDest->setColor(Qt::blue);
|
||||||
|
pathToDest->setWidth(10);
|
||||||
|
elements.push_back(pathToDest);
|
||||||
|
|
||||||
|
pathWalked = new Path2D();
|
||||||
|
pathToDest->setColor(Qt::black);
|
||||||
|
pathToDest->setWidth(5);
|
||||||
|
elements.push_back(pathWalked);
|
||||||
|
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
//menu = new QWidget(this);
|
||||||
|
QGridLayout* lay = new QGridLayout(this);
|
||||||
|
int row = 0;
|
||||||
|
|
||||||
|
|
||||||
|
lay->addItem(new QSpacerItem(0,0,QSizePolicy::Minimum,QSizePolicy::Expanding), row, 0, 1, 1);
|
||||||
|
|
||||||
|
++ row;
|
||||||
|
|
||||||
|
// // map-layer slider
|
||||||
|
// sldLayer = new QSlider();
|
||||||
|
// sldLayer->setOrientation(Qt::Horizontal);
|
||||||
|
// connect(sldLayer, &QSlider::sliderMoved, this, &MapView2D::onLayerSelect);
|
||||||
|
// connect(sldLayer, &QSlider::sliderReleased, this, &MapView2D::onLayerSelect);
|
||||||
|
// lay->addWidget(sldLayer, row, 0, 1, 1);
|
||||||
|
|
||||||
|
// show/hide button
|
||||||
|
const int bs = UIHelper::getButtonSize(this);
|
||||||
|
btnColorPoints = new QPushButton(Icons::getIcon("dots", bs), "");
|
||||||
|
btnColorPoints->connect(btnColorPoints, &QPushButton::clicked, [&] () {colorPoints->setVisible(!colorPoints->isVisible()); emit update();} );
|
||||||
|
lay->addWidget(btnColorPoints, row, 0, 1, 1);
|
||||||
|
|
||||||
|
btnLayerMinus = new QPushButton("-");
|
||||||
|
connect(btnLayerMinus, &QPushButton::clicked, this, &MapView2D::onLayerMinus);
|
||||||
|
lay->addWidget(btnLayerMinus, row, 1, 1, 1);
|
||||||
|
|
||||||
|
btnLayerPlus = new QPushButton("+");
|
||||||
|
connect(btnLayerPlus, &QPushButton::clicked, this, &MapView2D::onLayerPlus);
|
||||||
|
lay->addWidget(btnLayerPlus, row, 2, 1, 1);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::onLayerSelect() {
|
||||||
|
setRenderHeight(sldLayer->value());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::onLayerMinus() {
|
||||||
|
if (layerHeight_m <= 0) {return;}
|
||||||
|
layerHeight_m -= 1;
|
||||||
|
setRenderHeight(layerHeight_m);
|
||||||
|
}
|
||||||
|
void MapView2D::onLayerPlus() {
|
||||||
|
if (layerHeight_m >= 16) {return;}
|
||||||
|
layerHeight_m += 1;
|
||||||
|
setRenderHeight(layerHeight_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::setMap(WiFiCalibrationDataModel* mdl, Floorplan::IndoorMap* map) {
|
||||||
|
|
||||||
|
for (Floorplan::Floor* floor : map->floors) {
|
||||||
|
Floor2D* f = new Floor2D(floor);
|
||||||
|
elements.push_back(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
wifiCalib = new WiFiCalibTool(mdl, map);
|
||||||
|
elements.push_back(wifiCalib);
|
||||||
|
|
||||||
|
scaler.setCenterM(Point2(70, 35));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::showParticles(const std::vector<K::Particle<MyState>>* particles) {
|
||||||
|
this->colorPoints->setFromParticles(*particles);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::setCurrentEstimation(const Point3 pos_m, const Point3 dir) {
|
||||||
|
(void) dir;
|
||||||
|
setRenderHeight(pos_m.z);
|
||||||
|
scaler.setCenterM(pos_m.xy());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::setRenderHeight(const float height_m) {
|
||||||
|
renderParams.clip.aboveHeight_m = height_m + 1.5;
|
||||||
|
renderParams.clip.belowHeight_m = height_m - 1.5;
|
||||||
|
emit update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::showGridImportance(Grid<MyGridNode>* grid) {
|
||||||
|
colorPoints->showGridImportance(grid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::resizeEvent(QResizeEvent* evt) {
|
||||||
|
(void) evt;
|
||||||
|
int s = UIHelper::getButtonSize(this->parent()) * 1.5;
|
||||||
|
//sldLayer->setMinimumHeight(s);
|
||||||
|
//sldLayer->setMinimum(0);
|
||||||
|
//sldLayer->setMaximum(16);
|
||||||
|
btnColorPoints->setMinimumHeight(s);
|
||||||
|
btnColorPoints->setMinimumWidth(s);
|
||||||
|
btnLayerMinus->setMinimumHeight(s);
|
||||||
|
btnLayerMinus->setMinimumWidth(s);
|
||||||
|
btnLayerPlus->setMinimumHeight(s);
|
||||||
|
btnLayerPlus->setMinimumWidth(s);
|
||||||
|
|
||||||
|
scaler.setScreenSize(width(), height());
|
||||||
|
scaler.setScale( UIHelper::isLarge(this->parent()) ? 2 : 1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::mousePressEvent(QMouseEvent* evt) {
|
||||||
|
move.startCenter_px = scaler.getCenterPX();
|
||||||
|
move.startMouse_px = Point2(evt->x(), evt->y());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::mouseMoveEvent(QMouseEvent* evt) {
|
||||||
|
Point2 pt(evt->x(), evt->y());
|
||||||
|
pt -= move.startMouse_px;
|
||||||
|
pt.x = -pt.x;
|
||||||
|
pt += move.startCenter_px;
|
||||||
|
scaler.setCenterPX(pt);
|
||||||
|
emit update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::mouseReleaseEvent(QMouseEvent* evt) {
|
||||||
|
|
||||||
|
if (!wifiCalib) {return;}
|
||||||
|
|
||||||
|
const Point2 p1(evt->x(), evt->y());
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
for (const Point2 p2 : wifiCalib->getNodes()) {
|
||||||
|
const float dist = p1.getDistance(p2);
|
||||||
|
if (dist < 25) { wifiCalib->selectNode(idx); emit update(); break; }
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView2D::paintEvent(QPaintEvent*) {
|
||||||
|
|
||||||
|
QPainter qp(this);
|
||||||
|
|
||||||
|
// clear
|
||||||
|
qp.fillRect(0, 0, width(), height(), Qt::white);
|
||||||
|
|
||||||
|
// render elements
|
||||||
|
for (Renderable2D* r : elements) {
|
||||||
|
r->render(qp, scaler, renderParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
qp.end();
|
||||||
|
|
||||||
|
}
|
||||||
131
ui/map/2D/MapView2D.h
Normal file
131
ui/map/2D/MapView2D.h
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#ifndef MAPVIEW2D_H
|
||||||
|
#define MAPVIEW2D_H
|
||||||
|
|
||||||
|
#include "../misc/fixc11.h"
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "Scaler2D.h"
|
||||||
|
#include "Path2D.h"
|
||||||
|
#include "Renderable2D.h"
|
||||||
|
|
||||||
|
#include <Indoor/nav/dijkstra/DijkstraPath.h>
|
||||||
|
#include <Indoor/geo/Point3.h>
|
||||||
|
|
||||||
|
namespace Floorplan {
|
||||||
|
class IndoorMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> class Grid;
|
||||||
|
class MyGridNode;
|
||||||
|
class Renderable2D;
|
||||||
|
class QSlider;
|
||||||
|
class QPushButton;
|
||||||
|
class ColorPoints2D;
|
||||||
|
class Path2D;
|
||||||
|
|
||||||
|
template <typename T> class DijkstraPath;
|
||||||
|
namespace K {
|
||||||
|
template <typename T> class Particle;
|
||||||
|
}
|
||||||
|
class MyState;
|
||||||
|
|
||||||
|
class WiFiCalibTool;
|
||||||
|
class WiFiCalibrationDataModel;
|
||||||
|
|
||||||
|
class MapView2D : public QWidget {
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::vector<Renderable2D*> elements;
|
||||||
|
ColorPoints2D* colorPoints = nullptr;
|
||||||
|
Path2D* pathToDest = nullptr;
|
||||||
|
Path2D* pathWalked = nullptr;
|
||||||
|
WiFiCalibTool* wifiCalib = nullptr;
|
||||||
|
|
||||||
|
Scaler2D scaler;
|
||||||
|
RenderParams2D renderParams;
|
||||||
|
float layerHeight_m = 0;
|
||||||
|
|
||||||
|
struct Move {
|
||||||
|
Point2 startCenter_px;
|
||||||
|
Point2 startMouse_px;
|
||||||
|
} move;
|
||||||
|
|
||||||
|
QWidget* menu = nullptr;
|
||||||
|
QSlider* sldLayer = nullptr;
|
||||||
|
QPushButton* btnColorPoints = nullptr;
|
||||||
|
QPushButton* btnLayerPlus = nullptr;
|
||||||
|
QPushButton* btnLayerMinus = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit MapView2D(QWidget *parent = 0);
|
||||||
|
|
||||||
|
/** set the to-be-shown map */
|
||||||
|
void setMap(WiFiCalibrationDataModel* mdl, Floorplan::IndoorMap* map);
|
||||||
|
|
||||||
|
/** show importance factors for the grid */
|
||||||
|
void showGridImportance(Grid<MyGridNode>* grid);
|
||||||
|
|
||||||
|
/** set the height-slice to be visible */
|
||||||
|
void setRenderHeight(const float height_m);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** set the path to the destination MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
|
void setPathToDestination(const std::vector<Point3>& path);
|
||||||
|
|
||||||
|
/** set the path to disply. MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
|
template <typename Node> void setPathToDestination(const DijkstraPath<Node>* path) {this->pathToDest->set(*path);}
|
||||||
|
|
||||||
|
/** set the path to disply. MUST BE CALLED FROM THE MAIN THREAD*/
|
||||||
|
Q_INVOKABLE void setPathToDestination(const void* path) { setPathToDestination( (const DijkstraPath<MyGridNode>*) path); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** set the walked path. MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
|
void setPathWalked(const std::vector<Point3>& path) {this->pathWalked->set(path);}
|
||||||
|
|
||||||
|
/** set the walked path. MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
|
Q_INVOKABLE void setPathWalked(const void* path) { this->pathWalked->set( *((const std::vector<Point3>*) path)); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** NOTE: must be called from Qt's main thread! */
|
||||||
|
Q_INVOKABLE void showParticles(const void* particles) {
|
||||||
|
showParticles((const std::vector<K::Particle<MyState>>*) particles);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** NOTE: must be called from Qt's main thread! */
|
||||||
|
void showParticles(const std::vector<K::Particle<MyState>>* particles);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** set the currently estimated position */
|
||||||
|
void setCurrentEstimation(const Point3 pos, const Point3 dir);
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
|
||||||
|
void onLayerSelect();
|
||||||
|
void onLayerPlus();
|
||||||
|
void onLayerMinus();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void resizeEvent(QResizeEvent*);
|
||||||
|
|
||||||
|
void paintEvent(QPaintEvent*);
|
||||||
|
|
||||||
|
void mousePressEvent(QMouseEvent*);
|
||||||
|
void mouseMoveEvent(QMouseEvent*);
|
||||||
|
void mouseReleaseEvent(QMouseEvent*);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAPVIEW2D_H
|
||||||
123
ui/map/2D/Path2D.h
Normal file
123
ui/map/2D/Path2D.h
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
#ifndef PATH2D_H
|
||||||
|
#define PATH2D_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||||
|
#include "Renderable2D.h"
|
||||||
|
#include <Indoor/geo/Point3.h>
|
||||||
|
#include <Indoor/nav/dijkstra/DijkstraPath.h>
|
||||||
|
#include <Indoor/grid/Grid.h>
|
||||||
|
|
||||||
|
#include "../nav/Node.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Path2D : public Renderable2D {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** the path */
|
||||||
|
std::vector<Point3> path;
|
||||||
|
|
||||||
|
float width = 8;
|
||||||
|
QColor color = Qt::blue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
Path2D() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Node> void set(const DijkstraPath<Node>& path) {
|
||||||
|
|
||||||
|
std::vector<Point3> out;
|
||||||
|
for (const DijkstraNode<Node>* node : path.getVector()) {
|
||||||
|
if (!node) {break;}
|
||||||
|
const Node* elem = node->element;
|
||||||
|
out.push_back(Point3(elem->x_cm/100.0f, elem->y_cm/100.0f, elem->z_cm/100.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
set(out);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
|
void set(const std::vector<Point3>& path) {
|
||||||
|
this->path = simplify(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** combine nodes while the direction stays the same (many small quads -> one large quad) */
|
||||||
|
std::vector<Point3> simplify(const std::vector<Point3>& path) {
|
||||||
|
|
||||||
|
// copy
|
||||||
|
std::vector<Point3> out = path;
|
||||||
|
|
||||||
|
// remove unneccesary nodes
|
||||||
|
for (int i = 1; i < (int) out.size() - 1; ++i) {
|
||||||
|
|
||||||
|
const Point3 pa = out[i-1];
|
||||||
|
const Point3 pb = out[i-0];
|
||||||
|
const Point3 pc = out[i+1];
|
||||||
|
|
||||||
|
// same direction as last segment? combine segments!
|
||||||
|
const float dir1 = std::atan2(pb.y-pa.y, pb.x-pa.x); // last edge
|
||||||
|
const float dir2 = std::atan2(pc.y-pb.y, pc.x-pb.x); // next edge
|
||||||
|
const bool isSameDir = std::abs(dir1-dir2) < 0.03; // last-edge and next-edge have (approx) the same direction?
|
||||||
|
if (isSameDir) {out.erase(out.begin()+i); --i; continue;} // no additional information! remove the center node
|
||||||
|
|
||||||
|
// too many changes in a small space? -> remove some!
|
||||||
|
const float d1 = pb.getDistance(pa); // distance to last node
|
||||||
|
const float d2 = pb.getDistance(pc); // distance to next node
|
||||||
|
const float min = 1.0;
|
||||||
|
const bool isPackedChange = d1 < min && d2 < min; // both distances below a threshold?
|
||||||
|
if (isPackedChange) {out.erase(out.begin()+i); --i; continue;} // -> many changes in a small area -> remove current node!
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** the color to use */
|
||||||
|
void setColor(const QColor color) {
|
||||||
|
this->color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** the width to use */
|
||||||
|
void setWidth(const float w) {
|
||||||
|
this->width = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void doRender(QPainter& qp, const Scaler2D& s, const RenderParams2D& r) override {
|
||||||
|
|
||||||
|
QPen pen;
|
||||||
|
pen.setWidth(this->width);
|
||||||
|
pen.setColor(color);
|
||||||
|
qp.setPen(pen);
|
||||||
|
|
||||||
|
for (int i = 0; i < (int)path.size() - 1; ++i) {
|
||||||
|
|
||||||
|
const Point3 p1 = path[i];
|
||||||
|
const Point3 p2 = path[i+1];
|
||||||
|
|
||||||
|
if (p1.z < r.clip.belowHeight_m && p2.z < r.clip.belowHeight_m) {continue;}
|
||||||
|
if (p1.z > r.clip.aboveHeight_m && p2.z > r.clip.aboveHeight_m) {continue;}
|
||||||
|
|
||||||
|
const Point2 pa1 = s.mapToScreen(p1.xy());
|
||||||
|
const Point2 pa2 = s.mapToScreen(p2.xy());
|
||||||
|
|
||||||
|
qp.drawLine(pa1.x, pa1.y, pa2.x, pa2.y);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PATH2D_H
|
||||||
13
ui/map/2D/RenderParams2D.h
Normal file
13
ui/map/2D/RenderParams2D.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef RENDERPARAMS2D_H
|
||||||
|
#define RENDERPARAMS2D_H
|
||||||
|
|
||||||
|
struct RenderParams2D {
|
||||||
|
|
||||||
|
struct Clipping {
|
||||||
|
float belowHeight_m;
|
||||||
|
float aboveHeight_m;
|
||||||
|
} clip;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RENDERPARAMS2D_H
|
||||||
37
ui/map/2D/Renderable2D.h
Normal file
37
ui/map/2D/Renderable2D.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef RENDERABLE2D_H
|
||||||
|
#define RENDERABLE2D_H
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include "Scaler2D.h"
|
||||||
|
#include "RenderParams2D.h"
|
||||||
|
|
||||||
|
class Renderable2D {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool visible = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~Renderable2D() {;}
|
||||||
|
|
||||||
|
/** show/hide this element */
|
||||||
|
void setVisible(const bool visible) {this->visible = visible;}
|
||||||
|
|
||||||
|
/** is this element currently visible? */
|
||||||
|
bool isVisible() const {return this->visible;}
|
||||||
|
|
||||||
|
/** render this element */
|
||||||
|
void render(QPainter& qp, const Scaler2D& s, const RenderParams2D& p) {
|
||||||
|
if (!visible) {return;}
|
||||||
|
doRender(qp, s, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** subclasses render themselves here */
|
||||||
|
virtual void doRender(QPainter& qp, const Scaler2D& s, const RenderParams2D& p) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RENDERABLE2D_H
|
||||||
106
ui/map/2D/Scaler2D.h
Normal file
106
ui/map/2D/Scaler2D.h
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#ifndef SCALER2D_H
|
||||||
|
#define SCALER2D_H
|
||||||
|
|
||||||
|
#include <QPoint>
|
||||||
|
#include <Indoor/geo/Point2.h>
|
||||||
|
|
||||||
|
class Scaler2D {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
Point2 screenSize = Point2(400,400);
|
||||||
|
Point2 center_m = Point2(0,0);
|
||||||
|
float rotation_rad = 0.0f;
|
||||||
|
float scaleFactor = 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Scaler2D() {
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set the screen's size (in pixel) */
|
||||||
|
void setScreenSize(const float w_px, const float h_px) {
|
||||||
|
this->screenSize = Point2(w_px, h_px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** change the point displayed within the center of the screen */
|
||||||
|
void setCenter(const float x_m, const float y_m) {
|
||||||
|
this->center_m = Point2(x_m, y_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** change the point displayed within the center of the screen */
|
||||||
|
void setCenterM(const Point2 center_m) {
|
||||||
|
this->center_m = center_m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** change the point displayed within the center of the screen */
|
||||||
|
void setCenterPX(const Point2 center_px) {
|
||||||
|
this->center_m = pxToM(center_px);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2 getCenterPX() const {
|
||||||
|
return mToPX(this->center_m);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set the map's rotation in radians */
|
||||||
|
void setRotation(const float rad) {
|
||||||
|
this->rotation_rad = rad;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setScale(const float scale) {
|
||||||
|
this->scaleFactor = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
float mToPX(const float m) const {
|
||||||
|
return m * scaleFactor * (screenSize.x * 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
float pxToM(const float px) const {
|
||||||
|
return px / scaleFactor / (screenSize.x * 0.01);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2 pxToM(const Point2 pt) const {
|
||||||
|
return Point2(pxToM(pt.x), pxToM(pt.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
Point2 mToPX(const Point2 pt) const {
|
||||||
|
return Point2(mToPX(pt.x), mToPX(pt.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** convert map to screen coordinates */
|
||||||
|
Point2 mapToScreen(const Point2 pt_m) const {
|
||||||
|
|
||||||
|
Point2 pt = pt_m;
|
||||||
|
|
||||||
|
// move to (0,0)
|
||||||
|
pt -= center_m;
|
||||||
|
|
||||||
|
// rotate
|
||||||
|
pt = Point2(
|
||||||
|
std::cos(rotation_rad) * pt.x - std::sin(rotation_rad) * pt.y,
|
||||||
|
std::sin(rotation_rad) * pt.x + std::cos(rotation_rad) * pt.y
|
||||||
|
);
|
||||||
|
|
||||||
|
// scale
|
||||||
|
pt.x = mToPX(pt.x);
|
||||||
|
pt.y = mToPX(pt.y);
|
||||||
|
|
||||||
|
|
||||||
|
// add screen-center
|
||||||
|
pt += screenSize/2;
|
||||||
|
|
||||||
|
// negate y
|
||||||
|
pt.y = screenSize.y - pt.y;
|
||||||
|
|
||||||
|
// done
|
||||||
|
return pt;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SCALER2D_H
|
||||||
129
ui/map/2D/WiFiCalibTool.h
Normal file
129
ui/map/2D/WiFiCalibTool.h
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
#ifndef WIFICALIBTOOL_H
|
||||||
|
#define WIFICALIBTOOL_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Indoor/floorplan/v2/Floorplan.h>
|
||||||
|
#include "Renderable2D.h"
|
||||||
|
|
||||||
|
#include "../../../Settings.h"
|
||||||
|
#include "HasSelectableNodes.h"
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include "../../../tools/calibration/WiFiCalibrationDataModel.h"
|
||||||
|
#include "../../../tools/calibration/WiFiCalibrationScanDialog.h"
|
||||||
|
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include "../ui/UIHelper.h"
|
||||||
|
|
||||||
|
#include "../../../sensors/SensorFactory.h"
|
||||||
|
|
||||||
|
struct WiFiCalibPoint {
|
||||||
|
std::string name; // title
|
||||||
|
Point3 pos_m; // map position + smartphone height
|
||||||
|
Point2 pos_px; // screen position
|
||||||
|
WiFiCalibPoint(const std::string& name, const Point3 pos_m, const Point2 pos_px) : name(name), pos_m(pos_m), pos_px(pos_px) {;}
|
||||||
|
WiFiCalibPoint() {;}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper for wifi calibration
|
||||||
|
*/
|
||||||
|
class WiFiCalibTool : public Renderable2D {
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
WiFiCalibrationDataModel* mdl;
|
||||||
|
Floorplan::IndoorMap* map;
|
||||||
|
|
||||||
|
std::vector<WiFiCalibPoint> currentlyVisible;
|
||||||
|
WiFiCalibPoint currentlySelected;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/** ctor */
|
||||||
|
WiFiCalibTool(WiFiCalibrationDataModel* mdl, Floorplan::IndoorMap* map) : mdl(mdl), map(map) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void selectNode(const int idx) {
|
||||||
|
currentlySelected = currentlyVisible[idx];
|
||||||
|
showCalib(currentlySelected);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get all selectable caliration nodes */
|
||||||
|
virtual std::vector<Point2> getNodes() const {
|
||||||
|
std::vector<Point2> pts;
|
||||||
|
for (const WiFiCalibPoint& cp : currentlyVisible) {pts.push_back(cp.pos_px);}
|
||||||
|
return pts;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void doRender(QPainter& qp, const Scaler2D& s, const RenderParams2D& r) override {
|
||||||
|
|
||||||
|
currentlyVisible.clear();
|
||||||
|
const QFont font("Arial", 10);
|
||||||
|
qp.setFont(font);
|
||||||
|
|
||||||
|
for (const Floorplan::Floor* floor : map->floors) {
|
||||||
|
for (const Floorplan::Beacon* beacon : floor->beacons) {
|
||||||
|
|
||||||
|
const Point3 p = beacon->pos + Point3(0,0,floor->atHeight) + Point3(0,0,Settings::smartphoneAboveGround);
|
||||||
|
const Point2 pt = s.mapToScreen(p.xy());
|
||||||
|
|
||||||
|
if (floor->atHeight < r.clip.belowHeight_m) {continue;}
|
||||||
|
if (floor->atHeight > r.clip.aboveHeight_m) {continue;}
|
||||||
|
|
||||||
|
const WiFiCalibPoint cp(beacon->name, p, pt);
|
||||||
|
currentlyVisible.push_back(cp);
|
||||||
|
|
||||||
|
const WiFiFingerprint& fp = mdl->getFingerprint(cp.pos_m);
|
||||||
|
const QString txt1(beacon->name.c_str());
|
||||||
|
const QString txt2 = QString::number(fp.measurements.entries.size());
|
||||||
|
qp.setPen(Qt::black);
|
||||||
|
|
||||||
|
if (currentlySelected.name == cp.name) {
|
||||||
|
qp.setBrush(Qt::blue);
|
||||||
|
} else {
|
||||||
|
qp.setBrush(Qt::NoBrush);
|
||||||
|
}
|
||||||
|
|
||||||
|
//FONT SIZE??
|
||||||
|
|
||||||
|
|
||||||
|
int s = 20;
|
||||||
|
qp.drawEllipse(pt.x-s, pt.y-s, s*2, s*2);
|
||||||
|
qp.drawText(pt.x+s*2, pt.y-s, txt1);
|
||||||
|
qp.drawText(pt.x+s*2, pt.y+s, txt2);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void showCalib(const WiFiCalibPoint& cp) {
|
||||||
|
|
||||||
|
// get (or create an empty one) the fingerprint for this location
|
||||||
|
WiFiFingerprint& fp = mdl->getFingerprint(cp.pos_m);
|
||||||
|
|
||||||
|
// edit it (blocking!)
|
||||||
|
WiFiCalibrationScanDialog::get(fp);
|
||||||
|
|
||||||
|
// save the model
|
||||||
|
mdl->save();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // WIFICALIBTOOL_H
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
#include "MapView.h"
|
#include "MapView3D.h"
|
||||||
|
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QGLShaderProgram>
|
#include <QGLShaderProgram>
|
||||||
@@ -12,6 +12,8 @@
|
|||||||
#include "elements/ColorPoints.h"
|
#include "elements/ColorPoints.h"
|
||||||
#include "elements/Object.h"
|
#include "elements/Object.h"
|
||||||
|
|
||||||
|
#include "../Settings.h"
|
||||||
|
|
||||||
#include <Indoor/data/Timestamp.h>
|
#include <Indoor/data/Timestamp.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
@@ -22,34 +24,47 @@
|
|||||||
* which is already visible!
|
* which is already visible!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
MapView::MapView(QWidget* parent) : QOpenGLWidget(parent) {
|
MapView3D::MapView3D(QWidget* parent) : QOpenGLWidget(parent) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void MapView::clear() {
|
void MapView3D::clear() {
|
||||||
|
|
||||||
for (Renderable* r : elements) {delete r;}
|
for (Renderable* r : elements) {delete r;}
|
||||||
elements.clear();
|
elements.clear();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::setMap(Floorplan::IndoorMap* map) {
|
void MapView3D::setMap(Floorplan::IndoorMap* map) {
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
if (!isGLInitialized) {throw Exception("openGL is not yet initialized. add mapView to a visible window!");}
|
if (!isGLInitialized) {throw Exception("openGL is not yet initialized. add mapView to a visible window!");}
|
||||||
|
|
||||||
// first to be rendered
|
// first to be rendered -> the colored debug points
|
||||||
this->colorPoints = new ColorPoints();
|
this->colorPoints = new ColorPoints();
|
||||||
elements.push_back(this->colorPoints);
|
elements.push_back(this->colorPoints);
|
||||||
|
|
||||||
//leDude = new Object("/mnt/firma/tmp/3D/minion/minion.obj", "/mnt/firma/tmp/3D/minion/minion.png", "", 0.35);
|
// 2nd is the path to the destination (if any)
|
||||||
leDude = new Object("/mnt/firma/tmp/3D/gnome/gnome.obj", "/mnt/firma/tmp/3D/gnome/gnome_diffuse.jpg", "/mnt/firma/tmp/3D/gnome/gnome_normal.jpg", 0.033);
|
this->pathToDest = new Path();
|
||||||
//leDude = new Object("/mnt/firma/tmp/3D/squirrel/squirrel.obj", "/mnt/firma/tmp/3D/squirrel/squirrel.jpg", "/mnt/firma/tmp/3D/squirrel/squirrel_normal.jpg", 0.033);
|
elements.push_back(this->pathToDest);
|
||||||
elements.push_back(leDude);
|
|
||||||
|
|
||||||
|
this->pathWalked = new Path();
|
||||||
|
this->pathWalked->setWidth(0.3);
|
||||||
|
this->pathWalked->setColor(Qt::yellow);
|
||||||
|
elements.push_back(this->pathWalked);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 3rd is the dude, walking along the path
|
||||||
|
//leDude = new Object("/mnt/firma/tmp/3D/minion/minion.obj", "/mnt/firma/tmp/3D/minion/minion.png", "", 0.35);
|
||||||
|
//leDude = new Object("/mnt/firma/tmp/3D/gnome/gnome.obj", "/mnt/firma/tmp/3D/gnome/gnome_diffuse.jpg", "/mnt/firma/tmp/3D/gnome/gnome_normal.jpg", 0.033);
|
||||||
|
//leDude = new Object("/mnt/firma/tmp/3D/squirrel/squirrel.obj", "/mnt/firma/tmp/3D/squirrel/squirrel.jpg", "/mnt/firma/tmp/3D/squirrel/squirrel_normal.jpg", 0.033);
|
||||||
|
//elements.push_back(leDude);
|
||||||
|
|
||||||
|
// hereafter follows the floorplan (floors, doors, walls, stairs, ..)
|
||||||
for (Floorplan::Floor* floor : map->floors) {
|
for (Floorplan::Floor* floor : map->floors) {
|
||||||
elements.push_back(new Ground(floor));
|
elements.push_back(new Ground(floor));
|
||||||
elements.push_back(new Walls(floor));
|
elements.push_back(new Walls(floor));
|
||||||
@@ -58,8 +73,7 @@ void MapView::setMap(Floorplan::IndoorMap* map) {
|
|||||||
elements.push_back(new Doors(floor));
|
elements.push_back(new Doors(floor));
|
||||||
}
|
}
|
||||||
|
|
||||||
this->path = new Path();
|
|
||||||
elements.push_back(this->path);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -73,16 +87,20 @@ void MapView::setMap(Floorplan::IndoorMap* map) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::setPath(const std::vector<Point3>& path) {
|
void MapView3D::setPathToDestination(const std::vector<Point3>& path) {
|
||||||
this->path->set(path);
|
this->pathToDest->set(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MapView3D::setPathWalked(const std::vector<Point3>& path) {
|
||||||
|
this->pathWalked->set(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MapView::timerEvent(QTimerEvent *) {
|
void MapView3D::timerEvent(QTimerEvent *) {
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::initializeGL() {
|
void MapView3D::initializeGL() {
|
||||||
|
|
||||||
initializeOpenGLFunctions();
|
initializeOpenGLFunctions();
|
||||||
|
|
||||||
@@ -91,21 +109,19 @@ void MapView::initializeGL() {
|
|||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
// start background update timer
|
// start background update timer
|
||||||
const int fps = 25;
|
timer.start(Settings::MapView::msPerFrame.ms(), this);
|
||||||
const int interval = 1000 / fps;
|
|
||||||
timer.start(interval, this);
|
|
||||||
|
|
||||||
// OpenGL is now initialized
|
// OpenGL is now initialized
|
||||||
isGLInitialized = true;
|
isGLInitialized = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::paintGL() {
|
void MapView3D::paintGL() {
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
draw();
|
draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::resizeGL(int w, int h) {
|
void MapView3D::resizeGL(int w, int h) {
|
||||||
|
|
||||||
// Calculate aspect ratio
|
// Calculate aspect ratio
|
||||||
qreal aspect = qreal(w) / qreal(h ? h : 1);
|
qreal aspect = qreal(w) / qreal(h ? h : 1);
|
||||||
@@ -123,7 +139,7 @@ void MapView::resizeGL(int w, int h) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::rebuildLookat() {
|
void MapView3D::rebuildLookat() {
|
||||||
// QVector3D qDir(lookAt.dir.x, lookAt.dir.z, lookAt.dir.y);
|
// QVector3D qDir(lookAt.dir.x, lookAt.dir.z, lookAt.dir.y);
|
||||||
// QVector3D at = QVector3D(lookAt.pos.x, lookAt.pos.z, lookAt.pos.y);
|
// QVector3D at = QVector3D(lookAt.pos.x, lookAt.pos.z, lookAt.pos.y);
|
||||||
// QVector3D eye = at + qDir * 0.1;
|
// QVector3D eye = at + qDir * 0.1;
|
||||||
@@ -136,12 +152,12 @@ void MapView::rebuildLookat() {
|
|||||||
// lightPos = eye + QVector3D(0.0, 4.0, 0.0);
|
// lightPos = eye + QVector3D(0.0, 4.0, 0.0);
|
||||||
// eyePos = eye;
|
// eyePos = eye;
|
||||||
|
|
||||||
const Point3 dir = lookAt.getDir();
|
const QVector3D qDir = lookAt.getDir();
|
||||||
|
|
||||||
QVector3D qDir(dir.x, dir.z, dir.y);
|
//QVector3D qDir(dir.x, dir.z, dir.y);
|
||||||
QVector3D eye(lookAt.eye_m.x, lookAt.eye_m.z, lookAt.eye_m.y);
|
const QVector3D eye = lookAt.eye_m;//(lookAt.eye_m.x, lookAt.eye_m.z, lookAt.eye_m.y);
|
||||||
QVector3D at = eye + qDir * 0.5;
|
const QVector3D at = eye + qDir * 0.5;
|
||||||
QVector3D up = QVector3D(0,1,0);
|
const QVector3D up = QVector3D(0,1,0);
|
||||||
matView.setToIdentity();
|
matView.setToIdentity();
|
||||||
matView.lookAt(eye, at, up);
|
matView.lookAt(eye, at, up);
|
||||||
lightPos = eye + QVector3D(0.0, 0.5, 0.0) + qDir * 1.2;
|
lightPos = eye + QVector3D(0.0, 0.5, 0.0) + qDir * 1.2;
|
||||||
@@ -151,7 +167,7 @@ void MapView::rebuildLookat() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::setCurrentEstimation(const Point3 pos, const Point3 dir) {
|
void MapView3D::setCurrentEstimation(const Point3 pos, const Point3 dir) {
|
||||||
const float angle = std::atan2(dir.y, dir.x) * 180 / M_PI;
|
const float angle = std::atan2(dir.y, dir.x) * 180 / M_PI;
|
||||||
if (leDude) {
|
if (leDude) {
|
||||||
leDude->setPosition(pos.x, pos.y, pos.z);
|
leDude->setPosition(pos.x, pos.y, pos.z);
|
||||||
@@ -159,72 +175,100 @@ void MapView::setCurrentEstimation(const Point3 pos, const Point3 dir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::setLookAt(const Point3 pos_m, const Point3 dir) {
|
void MapView3D::setLookAt(const Point3 pos_m, const Point3 dir) {
|
||||||
lookAt.eye_m = pos_m + dir * 0.1;
|
lookAt.eye_m = QVector3D(pos_m.x, pos_m.z, pos_m.y) + QVector3D(dir.x, dir.z, dir.y) * 0.1;
|
||||||
lookAt.dir = dir;
|
lookAt.dir = QVector3D(dir.x, dir.z, dir.y);
|
||||||
rebuildLookat();
|
rebuildLookat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::setLookDir(const Point3 dir) {
|
void MapView3D::setLookDir(const Point3 dir) {
|
||||||
lookAt.dir = dir;
|
lookAt.dir = QVector3D(dir.x, dir.z, dir.y);
|
||||||
rebuildLookat();
|
rebuildLookat();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::setLookEye(const Point3 eye_m) {
|
void MapView3D::setLookEye(const Point3 eye_m) {
|
||||||
lookAt.eye_m = eye_m;
|
lookAt.eye_m = QVector3D(eye_m.x, eye_m.z, eye_m.y);
|
||||||
rebuildLookat();
|
rebuildLookat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void MapView::mousePressEvent(QMouseEvent* evt) {
|
void MapView3D::mousePressEvent(QMouseEvent* evt) {
|
||||||
mouseState.down = true;
|
mouseState.down = true;
|
||||||
mouseState.x = evt->x();
|
mouseState.x = evt->x();
|
||||||
mouseState.y = evt->y();
|
mouseState.y = evt->y();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::mouseMoveEvent(QMouseEvent* evt) {
|
void MapView3D::mouseMoveEvent(QMouseEvent* evt) {
|
||||||
|
|
||||||
const float dx = evt->x() - mouseState.x;
|
const float dx = evt->x() - mouseState.x;
|
||||||
const float dy = evt->y() - mouseState.y;
|
const float dy = evt->y() - mouseState.y;
|
||||||
|
mouseState.x = evt->x();
|
||||||
|
mouseState.y = evt->y();
|
||||||
|
|
||||||
// PI*0.3 head movement left/right and up/down
|
// PI*0.3 head movement left/right and up/down
|
||||||
const float yFac = (this->height() / 2) / (M_PI * 0.3);
|
//const float yFac = (this->height() / 2) / (M_PI * 0.3);
|
||||||
const float xFac = (this->width() / 2) / (M_PI * 0.3);
|
//const float xFac = (this->width() / 2) / (M_PI * 0.3);
|
||||||
|
|
||||||
|
|
||||||
|
const float angleX = dx/3.0f;
|
||||||
|
const float angleY = dy/3.0f;
|
||||||
|
lookAt.ax += angleX;
|
||||||
|
lookAt.ay += angleY;
|
||||||
|
lookAt.dirRot.setToIdentity();
|
||||||
|
lookAt.dirRot.rotate(lookAt.ax, QVector3D(0,1,0));
|
||||||
|
lookAt.dirRot.rotate(lookAt.ay, QVector3D(0,0,1));
|
||||||
|
|
||||||
|
//lookAt.dirRot.rotate(angleX, QVector3D(0,1,0));
|
||||||
|
//lookAt.dirRot.rotate(angleY, QVector3D(0,0,1));
|
||||||
|
|
||||||
lookAt.dirOffset = Point3(0, std::sin(dx/xFac), std::sin(-dy/yFac));
|
|
||||||
rebuildLookat();
|
rebuildLookat();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::mouseReleaseEvent(QMouseEvent* evt) {
|
void MapView3D::mouseReleaseEvent(QMouseEvent* evt) {
|
||||||
|
(void) evt;
|
||||||
mouseState.down = false;
|
mouseState.down = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MapView::keyPressEvent(QKeyEvent* evt) {
|
void MapView3D::keyPressEvent(QKeyEvent* evt) {
|
||||||
|
|
||||||
if (evt->key() == Qt::Key_W) {lookAt.eye_m += lookAt.getDir(); rebuildLookat();}
|
const QVector3D dir = lookAt.getDir() * 0.5;
|
||||||
if (evt->key() == Qt::Key_S) {lookAt.eye_m -= lookAt.getDir(); rebuildLookat();}
|
const QVector3D side(-dir.z(), 0, dir.x());
|
||||||
|
|
||||||
|
if (evt->key() == Qt::Key_W) {lookAt.eye_m += dir; rebuildLookat();}
|
||||||
|
if (evt->key() == Qt::Key_S) {lookAt.eye_m -= dir; rebuildLookat();}
|
||||||
|
|
||||||
|
if (evt->key() == Qt::Key_A) {lookAt.eye_m += side; rebuildLookat();}
|
||||||
|
if (evt->key() == Qt::Key_D) {lookAt.eye_m -= side; rebuildLookat();}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::toggleRenderMode() {
|
void MapView3D::toggleRenderMode() {
|
||||||
|
|
||||||
renderMode = (RenderMode) (((int)renderMode + 1) % 3);
|
renderMode = (RenderMode) (((int)renderMode + 1) % 2); // normally %3 but lines crash the smartphone
|
||||||
|
|
||||||
for (Renderable* r : elements) {
|
for (Renderable* r : elements) {
|
||||||
if (renderMode == RenderMode::OUTLINE) {
|
switch (renderMode) {
|
||||||
r->setOutlineOnly(true);
|
case RenderMode::OUTLINE:
|
||||||
} else {
|
r->setOutlineOnly(true);
|
||||||
r->setOutlineOnly(false);
|
r->setTransparent(false);
|
||||||
|
break;
|
||||||
|
case RenderMode::TRANSPARENT:
|
||||||
|
r->setOutlineOnly(false);
|
||||||
|
r->setTransparent(true);
|
||||||
|
break;
|
||||||
|
case RenderMode::NORMAL:
|
||||||
|
r->setOutlineOnly(false);
|
||||||
|
r->setTransparent(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MapView::draw() {
|
void MapView3D::draw() {
|
||||||
|
|
||||||
//const Timestamp ts1 = Timestamp::fromUnixTime();
|
//const Timestamp ts1 = Timestamp::fromUnixTime();
|
||||||
|
|
||||||
@@ -232,17 +276,9 @@ void MapView::draw() {
|
|||||||
glClearColor(0,0,0,1);
|
glClearColor(0,0,0,1);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
if (renderMode == RenderMode::TRANSPARENT) {
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
} else {
|
|
||||||
glDisable(GL_BLEND);
|
|
||||||
}
|
|
||||||
|
|
||||||
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD);
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (Renderable* r : elements) {
|
for (Renderable* r : elements) {
|
||||||
|
|
||||||
QOpenGLShaderProgram& program = r->getProgram();
|
QOpenGLShaderProgram& program = r->getProgram();
|
||||||
@@ -255,7 +291,7 @@ void MapView::draw() {
|
|||||||
program.setUniformValue("lightWorldPos", lightPos);
|
program.setUniformValue("lightWorldPos", lightPos);
|
||||||
program.setUniformValue("eyeWorldPos", eyePos);
|
program.setUniformValue("eyeWorldPos", eyePos);
|
||||||
|
|
||||||
r->render();
|
r->render(renderParams);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ class Renderable;
|
|||||||
class Path;
|
class Path;
|
||||||
|
|
||||||
|
|
||||||
class MapView : public QOpenGLWidget, protected QOpenGLFunctions {
|
class MapView3D : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -38,19 +38,26 @@ private:
|
|||||||
QVector3D lightPos;
|
QVector3D lightPos;
|
||||||
QVector3D eyePos;
|
QVector3D eyePos;
|
||||||
|
|
||||||
|
RenderParams renderParams;
|
||||||
|
|
||||||
QBasicTimer timer;
|
QBasicTimer timer;
|
||||||
|
|
||||||
std::vector<Renderable*> elements;
|
std::vector<Renderable*> elements;
|
||||||
Path* path = nullptr;
|
Path* pathToDest = nullptr;
|
||||||
|
Path* pathWalked = nullptr;
|
||||||
ColorPoints* colorPoints = nullptr;
|
ColorPoints* colorPoints = nullptr;
|
||||||
Object* leDude = nullptr;
|
Object* leDude = nullptr;
|
||||||
|
|
||||||
struct LookAt {
|
struct LookAt {
|
||||||
Point3 eye_m = Point3(0,0,1);
|
QVector3D eye_m = QVector3D(0,0,1);
|
||||||
Point3 dir = Point3(1,0,-0.1);
|
QVector3D dir = QVector3D(1,0,-0.1);
|
||||||
Point3 dirOffset = Point3(0,0,0);
|
float ax = 0;
|
||||||
Point3 getDir() const {return dir + dirOffset;}
|
float ay = 0;
|
||||||
|
QMatrix4x4 dirRot;
|
||||||
|
QVector3D getDir() const {return this->dirRot * this->dir;}
|
||||||
|
LookAt() {
|
||||||
|
dirRot.setToIdentity();
|
||||||
|
}
|
||||||
} lookAt;
|
} lookAt;
|
||||||
|
|
||||||
struct MouseState {
|
struct MouseState {
|
||||||
@@ -63,9 +70,10 @@ private:
|
|||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MapView(QWidget* parent = 0);
|
MapView3D(QWidget* parent = 0);
|
||||||
|
|
||||||
/** set the map to display */
|
/** set the map to display */
|
||||||
void setMap(Floorplan::IndoorMap* map);
|
void setMap(Floorplan::IndoorMap* map);
|
||||||
@@ -79,24 +87,33 @@ public:
|
|||||||
/** set the eye's position (looking from here) */
|
/** set the eye's position (looking from here) */
|
||||||
void setLookEye(const Point3 eye_m);
|
void setLookEye(const Point3 eye_m);
|
||||||
|
|
||||||
|
/** do not render elements higher than the given height */
|
||||||
|
void setClipAbove(const float height_m) {renderParams.clipAboveHeight_m = height_m;}
|
||||||
|
|
||||||
|
|
||||||
/** set the currently estimated position */
|
/** set the currently estimated position */
|
||||||
void setCurrentEstimation(const Point3 pos, const Point3 dir);
|
void setCurrentEstimation(const Point3 pos, const Point3 dir);
|
||||||
|
|
||||||
/** set the path to disply */
|
|
||||||
void setPath(const std::vector<Point3>& path);
|
|
||||||
|
|
||||||
/** NOTE: must be called from Qt's main thread! */
|
/** set the path to the destination MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
/** set the path to disply */
|
void setPathToDestination(const std::vector<Point3>& path);
|
||||||
Q_INVOKABLE void setPath(const void* path) {
|
|
||||||
setPath( (const DijkstraPath<MyGridNode>*) path);
|
/** set the path to disply. MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
}
|
template <typename Node> void setPathToDestination(const DijkstraPath<Node>* path) {this->pathToDest->set(*path);}
|
||||||
|
|
||||||
|
/** set the path to disply. MUST BE CALLED FROM THE MAIN THREAD*/
|
||||||
|
Q_INVOKABLE void setPathToDestination(const void* path) { setPathToDestination( (const DijkstraPath<MyGridNode>*) path); }
|
||||||
|
|
||||||
|
|
||||||
|
/** set the walked path. MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
|
void setPathWalked(const std::vector<Point3>& path);
|
||||||
|
|
||||||
|
/** set the walked path. MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
|
Q_INVOKABLE void setPathWalked(const void* path) { this->pathWalked->set( *((const std::vector<Point3>*) path)); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** NOTE: must be called from Qt's main thread! */
|
|
||||||
/** set the path to disply */
|
|
||||||
template <typename Node> void setPath(const DijkstraPath<Node>* path) {
|
|
||||||
this->path->set(*path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** NOTE: must be called from Qt's main thread! */
|
/** NOTE: must be called from Qt's main thread! */
|
||||||
void showGridImportance(Grid<MyGridNode>* grid) {
|
void showGridImportance(Grid<MyGridNode>* grid) {
|
||||||
11
ui/map/3D/RenderParams.h
Normal file
11
ui/map/3D/RenderParams.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef RENDERPARAMS_H
|
||||||
|
#define RENDERPARAMS_H
|
||||||
|
|
||||||
|
struct RenderParams {
|
||||||
|
|
||||||
|
/** clip (do not render) everything above this height */
|
||||||
|
float clipAboveHeight_m = 99999;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // RENDERPARAMS_H
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
#define RENDERABLE_H
|
#define RENDERABLE_H
|
||||||
|
|
||||||
#include <QOpenGLShaderProgram>
|
#include <QOpenGLShaderProgram>
|
||||||
|
#include "RenderParams.h"
|
||||||
|
|
||||||
class Renderable {
|
class Renderable {
|
||||||
|
|
||||||
@@ -18,9 +19,9 @@ public:
|
|||||||
QOpenGLShaderProgram& getProgram() {return program;}
|
QOpenGLShaderProgram& getProgram() {return program;}
|
||||||
|
|
||||||
/** render the renderable */
|
/** render the renderable */
|
||||||
void render() {
|
void render(const RenderParams& params) {
|
||||||
program.bind();
|
program.bind();
|
||||||
_render();
|
_render(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModelMatrix {
|
struct ModelMatrix {
|
||||||
@@ -54,11 +55,13 @@ public:
|
|||||||
modelMatrix.update();
|
modelMatrix.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void setOutlineOnly(const bool outline) {;}
|
virtual void setOutlineOnly(const bool outline) { (void) outline; }
|
||||||
|
|
||||||
|
virtual void setTransparent(const bool transparent) { (void) transparent; }
|
||||||
|
|
||||||
virtual void initGL() = 0;
|
virtual void initGL() = 0;
|
||||||
|
|
||||||
virtual void _render() = 0;
|
virtual void _render(const RenderParams& params) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -7,9 +7,10 @@
|
|||||||
|
|
||||||
#include "../gl/GLHelper.h"
|
#include "../gl/GLHelper.h"
|
||||||
#include "../gl/GLPoints.h"
|
#include "../gl/GLPoints.h"
|
||||||
|
//#include "../gl/GLTriangles.h"
|
||||||
#include "../Renderable.h"
|
#include "../Renderable.h"
|
||||||
|
|
||||||
#include "../../../nav/Node.h"
|
#include "../../../../nav/Node.h"
|
||||||
|
|
||||||
class ColorPoints : public Renderable {
|
class ColorPoints : public Renderable {
|
||||||
|
|
||||||
@@ -30,17 +31,28 @@ public:
|
|||||||
|
|
||||||
points.clear();
|
points.clear();
|
||||||
|
|
||||||
|
float min = +INFINITY;
|
||||||
|
float max = -INFINITY;
|
||||||
|
|
||||||
|
for (const MyGridNode& n : *grid) {
|
||||||
|
const float f = n.getWalkImportance();
|
||||||
|
if (f < min) {min = f;}
|
||||||
|
if (f > max) {max = f;}
|
||||||
|
}
|
||||||
|
|
||||||
|
max = 1.2;
|
||||||
|
|
||||||
for (const MyGridNode& n : *grid) {
|
for (const MyGridNode& n : *grid) {
|
||||||
const QVector3D pt(n.x_cm/100.0f, n.z_cm/100.0f + 0.1f, n.y_cm/100.0f); // swap z and y
|
const QVector3D pt(n.x_cm/100.0f, n.z_cm/100.0f + 0.1f, n.y_cm/100.0f); // swap z and y
|
||||||
const float f = n.getNavImportance();
|
const float f = n.getWalkImportance();
|
||||||
float h = 0.66 - (f*0.20); // 0.66 is blue on the HSV-scale
|
float h = 0.66 - ((f-min)/(max-min)) * 0.66; // 0.66 is blue on the HSV-scale
|
||||||
if (h < 0) {h = 0;}
|
if (h < 0) {h = 0;}
|
||||||
if (h > 1) {h = 1;}
|
if (h > 1) {h = 1;}
|
||||||
const QColor color = QColor::fromHsvF(h, 1, 1);
|
const QColor color = QColor::fromHsvF(h, 1, 1);
|
||||||
points.addPoint(pt, color);
|
points.addPoint(pt, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
size = 3.0f;
|
size = 8.0f;
|
||||||
points.rebuild();
|
points.rebuild();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,6 +66,7 @@ public:
|
|||||||
std::unordered_map<GridPoint, float> weights;
|
std::unordered_map<GridPoint, float> weights;
|
||||||
for (const K::Particle<T>& p : particles) {
|
for (const K::Particle<T>& p : particles) {
|
||||||
const GridPoint gp = p.state.position;
|
const GridPoint gp = p.state.position;
|
||||||
|
if (weights.find(gp) != weights.end()) {continue;}
|
||||||
weights[gp] += p.weight;
|
weights[gp] += p.weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,11 +97,23 @@ public:
|
|||||||
// points.addPoint(pt, color);
|
// points.addPoint(pt, color);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
size = 6.0f;
|
size = 8.0f;
|
||||||
points.rebuild();
|
points.rebuild();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void addPoint(const QVector3D pt, const QColor color) {
|
||||||
|
|
||||||
|
// const float s = 5 / 100.0f;
|
||||||
|
// const QVector3D col(color.redF(), color.greenF(), color.blueF());
|
||||||
|
// const VertColor vc1(pt + QVector3D(-s, -s, 0), col);
|
||||||
|
// const VertColor vc2(pt + QVector3D(+s, -s, 0), col);
|
||||||
|
// const VertColor vc3(pt + QVector3D(+s, +s, 0), col);
|
||||||
|
// const VertColor vc4(pt + QVector3D(-s, +s, 0), col);
|
||||||
|
|
||||||
|
// points.addQuad(vc1, vc2, vc3, vc4);
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
void initGL() override {
|
void initGL() override {
|
||||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentColorPoint.glsl");
|
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentColorPoint.glsl");
|
||||||
@@ -97,9 +122,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** render the floor */
|
/** render the floor */
|
||||||
void _render() override {
|
void _render(const RenderParams& params) override {
|
||||||
|
|
||||||
|
(void) params;
|
||||||
//glDisable(GL_DEPTH_TEST);
|
//glDisable(GL_DEPTH_TEST);
|
||||||
//glPointSize()
|
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
glPointSize(size);
|
glPointSize(size);
|
||||||
#endif
|
#endif
|
||||||
@@ -37,8 +37,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** render the floor */
|
/** render the floor */
|
||||||
void _render() override {
|
void _render(const RenderParams& params) override {
|
||||||
|
|
||||||
|
// skip me?
|
||||||
|
if (params.clipAboveHeight_m < floor->atHeight) {return;}
|
||||||
|
|
||||||
doors.render(&program);
|
doors.render(&program);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
#include "../gl/GLLines.h"
|
#include "../gl/GLLines.h"
|
||||||
#include "../Renderable.h"
|
#include "../Renderable.h"
|
||||||
|
|
||||||
#include "../../../lib/gpc/Polygon.h"
|
#include "../../../../lib/gpc/Polygon.h"
|
||||||
|
|
||||||
class Ground : public Renderable {
|
class Ground : public Renderable {
|
||||||
|
|
||||||
@@ -19,7 +19,9 @@ private:
|
|||||||
GLTriangles<VertNormTexTan> ceiling;
|
GLTriangles<VertNormTexTan> ceiling;
|
||||||
|
|
||||||
GLLines outline;
|
GLLines outline;
|
||||||
|
|
||||||
bool outlineOnly = false;
|
bool outlineOnly = false;
|
||||||
|
bool transparent = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -50,7 +52,19 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** render the floor */
|
/** render the floor */
|
||||||
void _render() override {
|
void _render(const RenderParams& params) override {
|
||||||
|
|
||||||
|
// skip me?
|
||||||
|
if (params.clipAboveHeight_m < floor->atHeight) {return;}
|
||||||
|
|
||||||
|
if (transparent) {
|
||||||
|
program.setUniformValue("alpha", 0.5f);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
} else {
|
||||||
|
program.setUniformValue("alpha", 1.0f);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
if (outlineOnly) {
|
if (outlineOnly) {
|
||||||
glLineWidth(5);
|
glLineWidth(5);
|
||||||
outline.render(&program);
|
outline.render(&program);
|
||||||
@@ -58,10 +72,14 @@ public:
|
|||||||
flooring.render(&program);
|
flooring.render(&program);
|
||||||
ceiling.render(&program);
|
ceiling.render(&program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** render only the outline? */
|
/** render only the outline? */
|
||||||
void setOutlineOnly(const bool outline) override {
|
void setOutlineOnly(const bool outline) override {
|
||||||
|
(void) outline;
|
||||||
// this->outlineOnly = outline;
|
// this->outlineOnly = outline;
|
||||||
// if (outlineOnly) {
|
// if (outlineOnly) {
|
||||||
// loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
|
// loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
|
||||||
@@ -73,6 +91,10 @@ public:
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTransparent(const bool transparent) override {
|
||||||
|
this->transparent = transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -32,7 +32,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** render the floor */
|
/** render the floor */
|
||||||
void _render() override {
|
void _render(const RenderParams& params) override {
|
||||||
|
if (params.clipAboveHeight_m < floor->atHeight) {return;}
|
||||||
glLineWidth(2);
|
glLineWidth(2);
|
||||||
lines.render(&program);
|
lines.render(&program);
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** render the floor */
|
/** render the floor */
|
||||||
void _render() override {
|
void _render(const RenderParams& params) override {
|
||||||
|
(void) params;
|
||||||
triangles.render(&program);
|
triangles.render(&program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,19 +16,24 @@ private:
|
|||||||
|
|
||||||
GLTriangles<VertNormTex> lines;
|
GLTriangles<VertNormTex> lines;
|
||||||
|
|
||||||
|
/** path's width (in meter) */
|
||||||
|
float width;
|
||||||
|
|
||||||
|
/** the path's color */
|
||||||
|
QVector4D color;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** ctor */
|
/** ctor */
|
||||||
Path() {
|
Path() {
|
||||||
;
|
setColor(QVector4D(0.0, 0.4, 1.0, 0.6));
|
||||||
|
setWidth(0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void initGL() override {
|
void initGL() override {
|
||||||
|
|
||||||
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
|
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
|
||||||
program.setUniformValue("color", QVector4D(0.0, 0.4, 1.0, 0.6));
|
|
||||||
|
|
||||||
//loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTexSimple.glsl");
|
//loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTexSimple.glsl");
|
||||||
|
|
||||||
lines.setDiffuse(":/res/gl/tex/arrows.png");
|
lines.setDiffuse(":/res/gl/tex/arrows.png");
|
||||||
@@ -36,15 +41,32 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** set the path's color */
|
||||||
|
void setColor(const QVector4D& color) {
|
||||||
|
this->color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set the path's color */
|
||||||
|
void setColor(const QColor& color) {
|
||||||
|
setColor(QVector4D(color.redF(), color.greenF(), color.blueF(), color.alphaF()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set the path's width (in meter) */
|
||||||
|
void setWidth(const float width) {
|
||||||
|
this->width = width;
|
||||||
|
}
|
||||||
|
|
||||||
/** render the floor */
|
/** render the floor */
|
||||||
void _render() override {
|
void _render(const RenderParams& params) override {
|
||||||
lines.rebuild();
|
|
||||||
glLineWidth(30);
|
(void) params;
|
||||||
glEnable(GL_BLEND);
|
program.setUniformValue("color", color);
|
||||||
|
|
||||||
|
//glEnable(GL_BLEND);
|
||||||
glDisable(GL_CULL_FACE);
|
glDisable(GL_CULL_FACE);
|
||||||
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
//glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
lines.render(&program);
|
lines.render(&program);
|
||||||
glDisable(GL_BLEND);
|
//glDisable(GL_BLEND);
|
||||||
glEnable(GL_CULL_FACE);
|
glEnable(GL_CULL_FACE);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -59,95 +81,15 @@ public:
|
|||||||
out.push_back(Point3(elem->x_cm/100.0f, elem->y_cm/100.0f, elem->z_cm/100.0f));
|
out.push_back(Point3(elem->x_cm/100.0f, elem->y_cm/100.0f, elem->z_cm/100.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
out = simplify(out);
|
|
||||||
set(out);
|
set(out);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void setSimple(const std::vector<Point3>& path) {
|
|
||||||
|
|
||||||
|
|
||||||
lines.clear();
|
|
||||||
const float s = 0.5;
|
|
||||||
|
|
||||||
Point3 lastDir(0,0,0);
|
|
||||||
std::vector<Floorplan::Quad3> quads;
|
|
||||||
|
|
||||||
for (int i = 1; i < (int) path.size(); ++i) {
|
|
||||||
|
|
||||||
Point3 pa = path[i-1];
|
|
||||||
Point3 pb = path[i-0];
|
|
||||||
const Point3 pc(0, 0, 1);
|
|
||||||
|
|
||||||
Point3 dir = pb - pa; dir /= dir.length();
|
|
||||||
Point3 perb = cross(pa-pb, pc); perb /= perb.length();
|
|
||||||
|
|
||||||
const Point3 p1 = pa - perb*s;
|
|
||||||
const Point3 p2 = pa + perb*s;
|
|
||||||
const Point3 p3 = pb + perb*s;
|
|
||||||
const Point3 p4 = pb - perb*s;
|
|
||||||
|
|
||||||
if (dir == lastDir) {
|
|
||||||
quads.back().p3 = p3;
|
|
||||||
quads.back().p4 = p4;
|
|
||||||
} else {
|
|
||||||
quads.push_back(Floorplan::Quad3(p1,p2,p3,p4));
|
|
||||||
}
|
|
||||||
|
|
||||||
lastDir = dir;
|
|
||||||
|
|
||||||
// // produce a small gap between path-lines [will be filled with another quad!]
|
|
||||||
// pa += dir * 0.6;
|
|
||||||
// pb -= dir * 0.6;
|
|
||||||
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < (int) quads.size(); ++i) {
|
|
||||||
|
|
||||||
// add the line-segment
|
|
||||||
const Floorplan::Quad3 q1 = quads[i];
|
|
||||||
addQuad(q1);
|
|
||||||
|
|
||||||
// // construct the quad between adjacent segments
|
|
||||||
// if (i < (int) quads.size() - 1) {
|
|
||||||
// const Floorplan::Quad3 q2 = quads[i+1];
|
|
||||||
// const Floorplan::Quad3 q3(q1.p3, q2.p2, q2.p1, q1.p4);
|
|
||||||
// addQuad(q3);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** combine nodes while the direction stays the same (many small quads -> one large quad) */
|
/** combine nodes while the direction stays the same (many small quads -> one large quad) */
|
||||||
std::vector<Point3> simplify(const std::vector<Point3>& path) {
|
std::vector<Point3> simplify(const std::vector<Point3>& path) {
|
||||||
|
|
||||||
std::vector<Point3> out;
|
// copy
|
||||||
|
std::vector<Point3> out = path;
|
||||||
Point3 lastDir(0,0,0);
|
|
||||||
if (!path.empty()) {
|
|
||||||
out.push_back(path.back());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = path.size() - 1; i >= 1; --i) {
|
|
||||||
|
|
||||||
const Point3 pa = path[i-0];
|
|
||||||
const Point3 pb = path[i-1];
|
|
||||||
const Point3 dir = (pb - pa).normalized();
|
|
||||||
|
|
||||||
if (dir == lastDir) {
|
|
||||||
out[out.size()-1] = pb;
|
|
||||||
} else {
|
|
||||||
out.push_back(pb);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastDir = dir;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove unneccesary nodes
|
// remove unneccesary nodes
|
||||||
for (int i = 1; i < (int) out.size() - 1; ++i) {
|
for (int i = 1; i < (int) out.size() - 1; ++i) {
|
||||||
@@ -156,13 +98,18 @@ public:
|
|||||||
const Point3 pb = out[i-0];
|
const Point3 pb = out[i-0];
|
||||||
const Point3 pc = out[i+1];
|
const Point3 pc = out[i+1];
|
||||||
|
|
||||||
const float min = 0.6;
|
// same direction as last segment? combine segments!
|
||||||
const float d1 = pb.getDistance(pa);
|
const float dir1 = std::atan2(pb.y-pa.y, pb.x-pa.x); // last edge
|
||||||
const float d2 = pb.getDistance(pc);
|
const float dir2 = std::atan2(pc.y-pb.y, pc.x-pb.x); // next edge
|
||||||
|
const bool isSameDir = std::abs(dir1-dir2) < 0.03; // last-edge and next-edge have (approx) the same direction?
|
||||||
|
if (isSameDir) {out.erase(out.begin()+i); --i; continue;} // no additional information! remove the center node
|
||||||
|
|
||||||
if (d1 < min || d2 < min) {
|
// too many changes in a small space? -> remove some!
|
||||||
out.erase(out.begin() + i);
|
const float d1 = pb.getDistance(pa); // distance to last node
|
||||||
}
|
const float d2 = pb.getDistance(pc); // distance to next node
|
||||||
|
const float min = 0.8;
|
||||||
|
const bool isPackedChange = d1 < min && d2 < min; // both distances below a threshold?
|
||||||
|
if (isPackedChange) {out.erase(out.begin()+i); --i; continue;} // -> many changes in a small area -> remove current node!
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,61 +117,16 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// void set(const std::vector<Point3>& path) {
|
/** MUST BE CALLED FROM THE MAIN THREAD */
|
||||||
|
void set(const std::vector<Point3>& _path) {
|
||||||
// lines.clear();
|
|
||||||
|
|
||||||
// const float s = 0.4;
|
|
||||||
// std::vector<Point3> pts;
|
|
||||||
|
|
||||||
// for (int i = 0; i < (int) path.size(); ++i) {
|
|
||||||
|
|
||||||
// const Point3 pa = path[i-1];
|
|
||||||
// const Point3 pb = path[i-0];
|
|
||||||
// const Point3 pc(0, 0, 1);
|
|
||||||
|
|
||||||
// const Point3 perb = cross(pa-pb, pc).normalized();
|
|
||||||
|
|
||||||
// // quad's edges
|
|
||||||
// const Point3 p1 = pa - perb*s;
|
|
||||||
// const Point3 p2 = pa + perb*s;
|
|
||||||
// const Point3 p3 = pb + perb*s;
|
|
||||||
// const Point3 p4 = pb - perb*s;
|
|
||||||
|
|
||||||
// pts.push_back(p1);
|
|
||||||
// pts.push_back(p2);
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// std::vector<Floorplan::Quad3> quads;
|
|
||||||
// for (int i = 0; i < (int) pts.size(); i+=2) {
|
|
||||||
// quads.push_back(Floorplan::Quad3(pts[i+0], pts[i+1], pts[i+3], pts[i+2]));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// float l1 = 0;
|
|
||||||
// float l2 = 0;
|
|
||||||
|
|
||||||
// for (int i = 0; i < (int) quads.size(); ++i) {
|
|
||||||
|
|
||||||
// // add the line-segment
|
|
||||||
// const Floorplan::Quad3 q1 = quads[i];
|
|
||||||
// l2 += ((q1.p1 + q1.p2) / 2).getDistance( (q1.p3 + q1.p4) / 2 );
|
|
||||||
// addQuad(q1, l1, l2);
|
|
||||||
// l1 = l2;
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void set(const std::vector<Point3>& path) {
|
|
||||||
|
|
||||||
|
std::vector<Point3> path = simplify(_path);
|
||||||
|
|
||||||
|
// reset
|
||||||
lines.clear();
|
lines.clear();
|
||||||
|
|
||||||
// half the width of the path
|
// half the width of the path
|
||||||
const float s = 0.4;
|
const float s = this->width * 0.5;
|
||||||
std::vector<Floorplan::Quad3> quads;
|
std::vector<Floorplan::Quad3> quads;
|
||||||
|
|
||||||
for (int i = 1; i < (int) path.size(); ++i) {
|
for (int i = 1; i < (int) path.size(); ++i) {
|
||||||
@@ -275,6 +177,8 @@ public:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lines.rebuild();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -306,7 +210,6 @@ private:
|
|||||||
const VertNormTex vnt3(v3, n, tex3);
|
const VertNormTex vnt3(v3, n, tex3);
|
||||||
const VertNormTex vnt4(v4, n, tex4);
|
const VertNormTex vnt4(v4, n, tex4);
|
||||||
|
|
||||||
|
|
||||||
lines.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
|
lines.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -40,7 +40,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** render the floor */
|
/** render the floor */
|
||||||
void _render() override {
|
void _render(const RenderParams& params) override {
|
||||||
|
(void) params;
|
||||||
parts.render(&program);
|
parts.render(&program);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,15 +17,15 @@ private:
|
|||||||
|
|
||||||
GLTriangles<VertNormTexTan> triangles;
|
GLTriangles<VertNormTexTan> triangles;
|
||||||
GLLines outlines;
|
GLLines outlines;
|
||||||
|
|
||||||
bool outlineOnly = false;
|
bool outlineOnly = false;
|
||||||
|
bool transparent = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** ctor */
|
/** ctor */
|
||||||
Walls(Floorplan::Floor* floor) : floor(floor) {
|
Walls(Floorplan::Floor* floor) : floor(floor) {
|
||||||
|
|
||||||
setOutlineOnly(false);
|
setOutlineOnly(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -42,13 +42,28 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** render the floor */
|
/** render the floor */
|
||||||
void _render() override {
|
void _render(const RenderParams& params) override {
|
||||||
|
|
||||||
|
// skip me?
|
||||||
|
if (params.clipAboveHeight_m < floor->atHeight) {return;}
|
||||||
|
|
||||||
|
if (transparent) {
|
||||||
|
program.setUniformValue("alpha", 0.5f);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
} else {
|
||||||
|
program.setUniformValue("alpha", 1.0f);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
if (outlineOnly) {
|
if (outlineOnly) {
|
||||||
glLineWidth(1);
|
glLineWidth(1);
|
||||||
outlines.render(&program);
|
outlines.render(&program);
|
||||||
} else {
|
} else {
|
||||||
triangles.render(&program);
|
triangles.render(&program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** render only the outline? */
|
/** render only the outline? */
|
||||||
@@ -64,6 +79,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setTransparent(const bool transparent) override {
|
||||||
|
this->transparent = transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -20,9 +20,13 @@ struct VertColor {
|
|||||||
int getVertOffset() const {return 0;}
|
int getVertOffset() const {return 0;}
|
||||||
int getColorOffset() const {return sizeof(QVector3D);}
|
int getColorOffset() const {return sizeof(QVector3D);}
|
||||||
int getTanOffset() const {throw "error";}
|
int getTanOffset() const {throw "error";}
|
||||||
|
int getNormOffset() const {throw "error";}
|
||||||
|
int getTexOffset() const {throw "error";}
|
||||||
bool operator == (const VertColor& o) const {return (vert == o.vert) && (color == o.color);}
|
bool operator == (const VertColor& o) const {return (vert == o.vert) && (color == o.color);}
|
||||||
static bool hasTangent() {return false;}
|
static bool hasTangent() {return false;}
|
||||||
static bool hasColor() {return true;}
|
static bool hasColor() {return true;}
|
||||||
|
static bool hasNormal() {return false;}
|
||||||
|
static bool hasTexCoord() {return false;}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertNorm {
|
struct VertNorm {
|
||||||
@@ -32,9 +36,12 @@ struct VertNorm {
|
|||||||
int getVertOffset() const {return 0;}
|
int getVertOffset() const {return 0;}
|
||||||
int getNormOffset() const {return sizeof(QVector3D);}
|
int getNormOffset() const {return sizeof(QVector3D);}
|
||||||
int getTanOffset() const {throw "error";}
|
int getTanOffset() const {throw "error";}
|
||||||
|
int getColorOffset() const {throw "error";}
|
||||||
bool operator == (const VertNorm& o) const {return (vert == o.vert) && (norm == o.norm);}
|
bool operator == (const VertNorm& o) const {return (vert == o.vert) && (norm == o.norm);}
|
||||||
static bool hasTangent() {return false;}
|
static bool hasTangent() {return false;}
|
||||||
|
static bool hasNormal() {return true;}
|
||||||
|
static bool hasTexCoord() {return false;}
|
||||||
|
static bool hasColor() {return false;}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertNormTex {
|
struct VertNormTex {
|
||||||
@@ -46,8 +53,12 @@ struct VertNormTex {
|
|||||||
int getNormOffset() const {return sizeof(QVector3D);}
|
int getNormOffset() const {return sizeof(QVector3D);}
|
||||||
int getTexOffset() const {return sizeof(QVector3D)*2;}
|
int getTexOffset() const {return sizeof(QVector3D)*2;}
|
||||||
int getTanOffset() const {throw "error";}
|
int getTanOffset() const {throw "error";}
|
||||||
|
int getColorOffset() const {throw "error";}
|
||||||
bool operator == (const VertNormTex& o) const {return (vert == o.vert) && (norm == o.norm) && (tex == o.tex);}
|
bool operator == (const VertNormTex& o) const {return (vert == o.vert) && (norm == o.norm) && (tex == o.tex);}
|
||||||
static bool hasTangent() {return false;}
|
static bool hasTangent() {return false;}
|
||||||
|
static bool hasNormal() {return true;}
|
||||||
|
static bool hasTexCoord() {return true;}
|
||||||
|
static bool hasColor() {return false;}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertNormTexTan {
|
struct VertNormTexTan {
|
||||||
@@ -60,8 +71,12 @@ struct VertNormTexTan {
|
|||||||
int getNormOffset() const {return sizeof(QVector3D);}
|
int getNormOffset() const {return sizeof(QVector3D);}
|
||||||
int getTexOffset() const {return sizeof(QVector3D)*2;}
|
int getTexOffset() const {return sizeof(QVector3D)*2;}
|
||||||
int getTanOffset() const {return sizeof(QVector3D)*2 + sizeof(QVector2D);}
|
int getTanOffset() const {return sizeof(QVector3D)*2 + sizeof(QVector2D);}
|
||||||
|
int getColorOffset() const {throw "error";}
|
||||||
bool operator == (const VertNormTexTan& o) const {return (vert == o.vert) && (norm == o.norm) && (tex == o.tex) && (tan == o.tan);}
|
bool operator == (const VertNormTexTan& o) const {return (vert == o.vert) && (norm == o.norm) && (tex == o.tex) && (tan == o.tan);}
|
||||||
static bool hasTangent() {return true;}
|
static bool hasTangent() {return true;}
|
||||||
|
static bool hasNormal() {return true;}
|
||||||
|
static bool hasTexCoord() {return true;}
|
||||||
|
static bool hasColor() {return false;}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HELPER_GL_H
|
#endif // HELPER_GL_H
|
||||||
@@ -18,7 +18,8 @@ private:
|
|||||||
std::vector<VertColor> vertices;
|
std::vector<VertColor> vertices;
|
||||||
std::vector<GLuint> indices;
|
std::vector<GLuint> indices;
|
||||||
|
|
||||||
int mode = GL_POINTS;
|
// use rectangles instead of GL_POINTS
|
||||||
|
int mode = GL_TRIANGLES;
|
||||||
bool initOnce = true;
|
bool initOnce = true;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -35,9 +36,31 @@ public:
|
|||||||
|
|
||||||
/** add a new face to this element */
|
/** add a new face to this element */
|
||||||
void addPoint(const QVector3D& pt, const QColor& color) {
|
void addPoint(const QVector3D& pt, const QColor& color) {
|
||||||
indices.push_back(vertices.size());
|
|
||||||
QVector3D c(color.redF(), color.greenF(), color.blueF());
|
const QVector3D c(color.redF(), color.greenF(), color.blueF());
|
||||||
vertices.push_back(VertColor(pt, c));
|
|
||||||
|
float s = 10 / 100.0f;
|
||||||
|
|
||||||
|
const VertColor vc1(pt + QVector3D(-s, 0, -s), c);
|
||||||
|
const VertColor vc2(pt + QVector3D(+s, 0, -s), c);
|
||||||
|
const VertColor vc3(pt + QVector3D(+s, 0, +s), c);
|
||||||
|
const VertColor vc4(pt + QVector3D(-s, 0, +s), c);
|
||||||
|
|
||||||
|
const int start = vertices.size();
|
||||||
|
|
||||||
|
vertices.push_back(vc1);
|
||||||
|
vertices.push_back(vc2);
|
||||||
|
vertices.push_back(vc3);
|
||||||
|
vertices.push_back(vc4);
|
||||||
|
|
||||||
|
indices.push_back(start + 3);
|
||||||
|
indices.push_back(start + 2);
|
||||||
|
indices.push_back(start + 1);
|
||||||
|
|
||||||
|
indices.push_back(start + 3);
|
||||||
|
indices.push_back(start + 1);
|
||||||
|
indices.push_back(start + 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ private:
|
|||||||
QOpenGLTexture* textures[4];
|
QOpenGLTexture* textures[4];
|
||||||
|
|
||||||
std::vector<T> vertices;
|
std::vector<T> vertices;
|
||||||
std::vector<GLushort> indices;
|
std::vector<GLuint> indices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -123,6 +123,9 @@ public:
|
|||||||
/** render the element */
|
/** render the element */
|
||||||
void render(QOpenGLShaderProgram* program) {
|
void render(QOpenGLShaderProgram* program) {
|
||||||
|
|
||||||
|
// nothing to-do?
|
||||||
|
if (indices.empty()) {return;}
|
||||||
|
|
||||||
// Tell OpenGL which VBOs to use
|
// Tell OpenGL which VBOs to use
|
||||||
arrayBuf.bind();
|
arrayBuf.bind();
|
||||||
indexBuf.bind();
|
indexBuf.bind();
|
||||||
@@ -137,13 +140,17 @@ public:
|
|||||||
program->setAttributeBuffer(vertLoc, GL_FLOAT, vertices[0].getVertOffset(), 3, sizeof(vertices[0]));
|
program->setAttributeBuffer(vertLoc, GL_FLOAT, vertices[0].getVertOffset(), 3, sizeof(vertices[0]));
|
||||||
|
|
||||||
// Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
|
// Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
|
||||||
int normLoc = program->attributeLocation("a_normal");
|
if (T::hasNormal()) {
|
||||||
program->enableAttributeArray(normLoc);
|
int normLoc = program->attributeLocation("a_normal");
|
||||||
program->setAttributeBuffer(normLoc, GL_FLOAT, vertices[0].getNormOffset(), 3, sizeof(vertices[0]));
|
program->enableAttributeArray(normLoc);
|
||||||
|
program->setAttributeBuffer(normLoc, GL_FLOAT, vertices[0].getNormOffset(), 3, sizeof(vertices[0]));
|
||||||
|
}
|
||||||
|
|
||||||
int texcoordLocation = program->attributeLocation("a_texcoord");
|
if (T::hasTexCoord()) {
|
||||||
program->enableAttributeArray(texcoordLocation);
|
int texcoordLocation = program->attributeLocation("a_texcoord");
|
||||||
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, vertices[0].getTexOffset(), 2, sizeof(vertices[0]));
|
program->enableAttributeArray(texcoordLocation);
|
||||||
|
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, vertices[0].getTexOffset(), 2, sizeof(vertices[0]));
|
||||||
|
}
|
||||||
|
|
||||||
// bind tangent data?
|
// bind tangent data?
|
||||||
if (T::hasTangent()) {
|
if (T::hasTangent()) {
|
||||||
@@ -152,12 +159,18 @@ public:
|
|||||||
program->setAttributeBuffer(tanLocation, GL_FLOAT, vertices[0].getTanOffset(), 3, sizeof(vertices[0]));
|
program->setAttributeBuffer(tanLocation, GL_FLOAT, vertices[0].getTanOffset(), 3, sizeof(vertices[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bind color data?
|
||||||
|
if (T::hasColor()) {
|
||||||
|
int colorLoc = program->attributeLocation("a_color");
|
||||||
|
program->enableAttributeArray(colorLoc);
|
||||||
|
program->setAttributeBuffer(colorLoc, GL_FLOAT, vertices[0].getColorOffset(), 3, sizeof(vertices[0]));
|
||||||
|
}
|
||||||
|
|
||||||
// texture
|
// texture
|
||||||
program->setUniformValue("texture", 0);
|
program->setUniformValue("texture", 0);
|
||||||
|
|
||||||
// Draw cube geometry using indices from VBO 1
|
// Draw cube geometry using indices from VBO 1
|
||||||
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, 0);
|
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4,12 +4,13 @@
|
|||||||
|
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
#include <Indoor/Assertions.h>
|
#include <Indoor/Assertions.h>
|
||||||
|
#include "../UIHelper.h"
|
||||||
|
|
||||||
MainMenu::MainMenu(QWidget* parent) : QWidget(parent) {
|
MainMenu::MainMenu(QWidget* parent) : QWidget(parent) {
|
||||||
|
|
||||||
setMinimumHeight(64);
|
|
||||||
|
|
||||||
QGridLayout* lay = new QGridLayout(this);
|
QGridLayout* lay = new QGridLayout(this);
|
||||||
int row = 0;
|
int row = 0;
|
||||||
@@ -27,28 +28,50 @@ MainMenu::MainMenu(QWidget* parent) : QWidget(parent) {
|
|||||||
Assert::isTrue(connect(btnCamera, &QPushButton::clicked, this, &MainMenu::onCameraButton), "connect() failed");
|
Assert::isTrue(connect(btnCamera, &QPushButton::clicked, this, &MainMenu::onCameraButton), "connect() failed");
|
||||||
lay->addWidget(btnCamera, row, col, 1,1,Qt::AlignTop); ++col;
|
lay->addWidget(btnCamera, row, col, 1,1,Qt::AlignTop); ++col;
|
||||||
|
|
||||||
btnTransparent = getButton("cube");
|
btnTransparent = getButton("wall");
|
||||||
Assert::isTrue(connect(btnTransparent, &QPushButton::clicked, this, &MainMenu::onTransparentButton), "connect() failed");
|
Assert::isTrue(connect(btnTransparent, &QPushButton::clicked, this, &MainMenu::onTransparentButton), "connect() failed");
|
||||||
lay->addWidget(btnTransparent, row, col, 1,1,Qt::AlignTop); ++col;
|
lay->addWidget(btnTransparent, row, col, 1,1,Qt::AlignTop); ++col;
|
||||||
|
|
||||||
|
btn3D = getButton("cube");
|
||||||
|
Assert::isTrue(connect(btn3D, &QPushButton::clicked, this, &MainMenu::on3DButton), "connect() failed");
|
||||||
|
lay->addWidget(btn3D, row, col, 1,1,Qt::AlignTop); ++col;
|
||||||
|
|
||||||
|
|
||||||
btnStart = getButton("run");
|
btnStart = getButton("run");
|
||||||
Assert::isTrue(connect(btnStart, &QPushButton::clicked, this, &MainMenu::onStartButton), "connect() failed");
|
Assert::isTrue(connect(btnStart, &QPushButton::clicked, this, &MainMenu::onStartButton), "connect() failed");
|
||||||
lay->addWidget(btnStart, row, col, 1,1,Qt::AlignTop); ++col;
|
lay->addWidget(btnStart, row, col, 1,1,Qt::AlignTop); ++col;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void setButtonSize(QPushButton* btn, int size) {
|
||||||
|
const int border = 4;
|
||||||
|
btn->setMinimumHeight(size+border);
|
||||||
|
btn->setMaximumHeight(size+border);
|
||||||
|
btn->setMinimumWidth(size+border);
|
||||||
|
btn->setMaximumWidth(size+border);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainMenu::resizeEvent(QEvent* evt) {
|
||||||
|
|
||||||
|
const int s = UIHelper::getButtonSize(this->parent());
|
||||||
|
setButtonSize(btnLoadMap, s);
|
||||||
|
setButtonSize(btnDebug, s);
|
||||||
|
setButtonSize(btnCamera, s);
|
||||||
|
setButtonSize(btnTransparent, s);
|
||||||
|
setButtonSize(btnStart, s);
|
||||||
|
setButtonSize(btn3D, s);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QPushButton* MainMenu::getButton(const std::string& icon) {
|
QPushButton* MainMenu::getButton(const std::string& icon) {
|
||||||
|
|
||||||
const int size = 48;
|
const int size = UIHelper::getButtonSize(this->parent());
|
||||||
const int border = 4;
|
|
||||||
|
|
||||||
QPushButton* btn = new QPushButton(Icons::getIcon(icon, size), "");
|
QPushButton* btn = new QPushButton(Icons::getIcon(icon, size), "");
|
||||||
btn->setIconSize(QSize(size,size));
|
btn->setIconSize(QSize(size,size));
|
||||||
btn->setMinimumHeight(size+border);
|
setButtonSize(btn, size);
|
||||||
btn->setMaximumHeight(size+border);
|
|
||||||
btn->setMinimumWidth(size+border);
|
|
||||||
btn->setMaximumWidth(size+border);
|
|
||||||
|
|
||||||
return btn;
|
return btn;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
class QLabel;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
|
||||||
class MainMenu : public QWidget {
|
class MainMenu : public QWidget {
|
||||||
@@ -13,6 +14,10 @@ public:
|
|||||||
/** ctor */
|
/** ctor */
|
||||||
explicit MainMenu(QWidget* parent);
|
explicit MainMenu(QWidget* parent);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void resizeEvent(QEvent*);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
void onLoadButton();
|
void onLoadButton();
|
||||||
@@ -20,6 +25,7 @@ signals:
|
|||||||
void onDebugButton();
|
void onDebugButton();
|
||||||
void onCameraButton();
|
void onCameraButton();
|
||||||
void onTransparentButton();
|
void onTransparentButton();
|
||||||
|
void on3DButton();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -30,6 +36,8 @@ private:
|
|||||||
QPushButton* btnDebug;
|
QPushButton* btnDebug;
|
||||||
QPushButton* btnCamera;
|
QPushButton* btnCamera;
|
||||||
QPushButton* btnTransparent;
|
QPushButton* btnTransparent;
|
||||||
|
QPushButton* btn3D;
|
||||||
|
QLabel* lblLog;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
80
yasmin.pro
80
yasmin.pro
@@ -11,12 +11,19 @@ ANDROID {
|
|||||||
QT += sensors
|
QT += sensors
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# openMP
|
||||||
|
QMAKE_CXXFLAGS += -fopenmp
|
||||||
|
LIBS += -fopenmp
|
||||||
|
|
||||||
# debug
|
# debug
|
||||||
DEFINES += WITH_DEBUG_LOG
|
DEFINES += WITH_DEBUG_LOG
|
||||||
DEFINES += WITH_ASSERTIONS
|
DEFINES += WITH_ASSERTIONS
|
||||||
|
|
||||||
|
QMAKE_CXXFLAGS += -Werror=return-type
|
||||||
|
|
||||||
CONFIG += c++11
|
CONFIG += c++11
|
||||||
|
|
||||||
|
|
||||||
# use files in ./_android for the project as well
|
# use files in ./_android for the project as well
|
||||||
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/_android
|
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/_android
|
||||||
|
|
||||||
@@ -38,7 +45,6 @@ SOURCES += \
|
|||||||
main.cpp \
|
main.cpp \
|
||||||
lib/gpc/gpc.cpp \
|
lib/gpc/gpc.cpp \
|
||||||
../Indoor/lib/tinyxml/tinyxml2.cpp \
|
../Indoor/lib/tinyxml/tinyxml2.cpp \
|
||||||
ui/map/MapView.cpp \
|
|
||||||
ui/menu/MainMenu.cpp \
|
ui/menu/MainMenu.cpp \
|
||||||
ui/MainWindow.cpp \
|
ui/MainWindow.cpp \
|
||||||
Controller.cpp \
|
Controller.cpp \
|
||||||
@@ -48,7 +54,11 @@ SOURCES += \
|
|||||||
ui/debug/PlotTurns.cpp \
|
ui/debug/PlotTurns.cpp \
|
||||||
ui/debug/PlotWiFiScan.cpp \
|
ui/debug/PlotWiFiScan.cpp \
|
||||||
sensors/android/WiFiSensorAndroid.cpp \
|
sensors/android/WiFiSensorAndroid.cpp \
|
||||||
sensors/linux/WiFiSensorLinuxC.c
|
sensors/linux/WiFiSensorLinuxC.c \
|
||||||
|
ui/debug/InfoWidget.cpp \
|
||||||
|
ui/map/3D/MapView3D.cpp \
|
||||||
|
ui/map/2D/MapView2D.cpp \
|
||||||
|
tools/calibration/WiFiCalibrationScanDialog.cpp
|
||||||
|
|
||||||
RESOURCES += qml.qrc
|
RESOURCES += qml.qrc
|
||||||
|
|
||||||
@@ -87,24 +97,27 @@ HEADERS += \
|
|||||||
misc/fixc11.h \
|
misc/fixc11.h \
|
||||||
sensors/dummy/WiFiSensorDummy.h \
|
sensors/dummy/WiFiSensorDummy.h \
|
||||||
lib/gpc/Polygon.h \
|
lib/gpc/Polygon.h \
|
||||||
Stairs.h \
|
ui/map/3D/FloorRenderer.h \
|
||||||
ui/map/MapView.h \
|
ui/map/3D/gl/GL.h \
|
||||||
ui/map/FloorRenderer.h \
|
ui/map/3D/gl/GLHelper.h \
|
||||||
ui/map/gl/GL.h \
|
ui/map/3D/gl/GLLines.h \
|
||||||
ui/map/gl/GLHelper.h \
|
ui/map/3D/gl/GLTriangles.h \
|
||||||
ui/map/gl/GLLines.h \
|
ui/map/3D/elements/Doors.h \
|
||||||
ui/map/gl/GLTriangles.h \
|
ui/map/3D/elements/Ground.h \
|
||||||
ui/map/elements/Doors.h \
|
ui/map/3D/elements/Handrails.h \
|
||||||
ui/map/elements/Ground.h \
|
ui/map/3D/elements/Path.h \
|
||||||
ui/map/elements/Handrails.h \
|
ui/map/3D/elements/Stairs.h \
|
||||||
ui/map/elements/Path.h \
|
ui/map/3D/elements/Walls.h \
|
||||||
ui/map/elements/Stairs.h \
|
ui/map/3D/gl/GLPoints.h \
|
||||||
ui/map/elements/Walls.h \
|
ui/map/3D/elements/ColorPoints.h \
|
||||||
|
ui/map/3D/RenderParams.h \
|
||||||
|
ui/map/3D/Renderable.h \
|
||||||
|
ui/map/3D/gl/Shader.h \
|
||||||
|
ui/map/3D/elements/Object.h \
|
||||||
ui/Icons.h \
|
ui/Icons.h \
|
||||||
ui/MainWindow.h \
|
ui/MainWindow.h \
|
||||||
Controller.h \
|
Controller.h \
|
||||||
ui/menu/MainMenu.h \
|
ui/menu/MainMenu.h \
|
||||||
Config.h \
|
|
||||||
ui/dialog/LoadSetupDialog.h \
|
ui/dialog/LoadSetupDialog.h \
|
||||||
ui/debug/plot/Axes.h \
|
ui/debug/plot/Axes.h \
|
||||||
ui/debug/plot/Plot.h \
|
ui/debug/plot/Plot.h \
|
||||||
@@ -120,19 +133,42 @@ HEADERS += \
|
|||||||
nav/Filter.h \
|
nav/Filter.h \
|
||||||
nav/Node.h \
|
nav/Node.h \
|
||||||
sensors/linux/WiFiSensorLinuxC.h \
|
sensors/linux/WiFiSensorLinuxC.h \
|
||||||
ui/map/gl/GLPoints.h \
|
|
||||||
ui/map/elements/ColorPoints.h \
|
|
||||||
sensors/offline/SensorFactoryOffline.h \
|
sensors/offline/SensorFactoryOffline.h \
|
||||||
sensors/dummy/SensorFactoryDummy.h \
|
sensors/dummy/SensorFactoryDummy.h \
|
||||||
sensors/android/SensorFactoryAndroid.h \
|
sensors/android/SensorFactoryAndroid.h \
|
||||||
ui/map/gl/Shader.h \
|
|
||||||
ui/map/elements/Object.h \
|
|
||||||
Settings.h \
|
Settings.h \
|
||||||
nav/RegionalResampling.h \
|
nav/RegionalResampling.h \
|
||||||
sensors/offline/AllInOneSensor.h
|
sensors/offline/AllInOneSensor.h \
|
||||||
|
sensors/ActivitySensor.h \
|
||||||
|
ui/LoggerUI.h \
|
||||||
|
ui/debug/InfoWidget.h \
|
||||||
|
ui/UIHelper.h \
|
||||||
|
nav/NodeResampling.h \
|
||||||
|
ui/map/3D/MapView3D.h \
|
||||||
|
ui/map/2D/MapView2D.h \
|
||||||
|
ui/map/2D/Floor2D.h \
|
||||||
|
ui/map/2D/Scaler2D.h \
|
||||||
|
ui/map/2D/Renderable2D.h \
|
||||||
|
ui/map/2D/RenderParams2D.h \
|
||||||
|
ui/map/2D/ColorPoints2D.h \
|
||||||
|
ui/map/2D/Path2D.h \
|
||||||
|
ui/map/2D/WiFiCalibTool.h \
|
||||||
|
ui/map/2D/HasSelectableNodes.h \
|
||||||
|
tools/calibration/WiFiCalibrationDataModel.h \
|
||||||
|
tools/calibration/WiFiCalibrationScanDialog.h \
|
||||||
|
tests/RuntimeTests.h \
|
||||||
|
ipin/StepLogger.h \
|
||||||
|
ipin/Scaler.h \
|
||||||
|
ipin/Config.h \
|
||||||
|
ipin/IPINHelper.h \
|
||||||
|
nav/NavControllerListener.h \
|
||||||
|
ipin/StepLoggerWrapper.h \
|
||||||
|
ipin/StepLoggerWrapperAndroid.h
|
||||||
|
|
||||||
DISTFILES += \
|
DISTFILES += \
|
||||||
android-sources/src/MyActivity.java \
|
android-sources/src/MyActivity.java \
|
||||||
res/gl/vertex1.glsl \
|
res/gl/vertex1.glsl \
|
||||||
res/gl/fragment1.glsl \
|
res/gl/fragment1.glsl \
|
||||||
res/gl/tex/empty_normals.jpg
|
res/gl/tex/empty_normals.jpg \
|
||||||
|
_android/src/aidl/it/cnr/isti/steplogger/IStepLoggerService.aidl \
|
||||||
|
_android/src/StepLoggerClient.java
|
||||||
|
|||||||
Reference in New Issue
Block a user