This repository has been archived on 2020-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
Files
YASMIN/Controller.cpp
mail@toni-fetzer.de ef6066ae14 we are now able to record bluetooth fingerprints
for this, we use the same ui interface and fingerprint positions as wifi. if wifi has done 30 scans, also the ble
scans will be stopped. this is just a quick and dirte solution, as changing the gui completely for this two options
was to time consuming
2019-06-06 17:42:11 +02:00

398 lines
14 KiB
C++

#include "Controller.h"
#include "ui/map/3D/MapView3D.h"
#include "ui/map/2D/MapView2D.h"
#include "ui/menu/MainMenu.h"
#include "ui/MainWindow.h"
#include "ui/dialog/LoadSetupDialog.h"
#include "ui/debug/SensorDataWidget.h"
#include <Indoor/grid/factory/v2/GridFactory.h>
#include <Indoor/grid/factory/v2/Importance.h>
#include <Indoor/navMesh/NavMesh.h>
#include <Indoor/navMesh/NavMeshFactory.h>
#include <Indoor/floorplan/v2/Floorplan.h>
#include <Indoor/floorplan/v2/FloorplanReader.h>
#include <Indoor/floorplan/v2/FloorplanHelper.h>
#include <Indoor/sensors/radio/WiFiGridEstimator.h>
#include <Indoor/sensors/radio/setup/WiFiOptimizerLogDistCeiling.h>
#include <Indoor/sensors/radio/model/WiFiModel.h>
#include <Indoor/sensors/beacon/model/BeaconModel.h>
#include <Indoor/sensors/beacon/model/BeaconModelLogDistCeiling.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/android/SensorFactoryAndroid.h"
#include "sensors/offline/SensorFactoryOffline.h"
#include "sensors/SensorWriter.h"
#include "tools/calibration/WiFiCalibrationDataModel.h"
#include "nav/NavController.h"
#include "nav/grid/NavControllerGrid.h"
#include "nav/mesh/NavControllerMesh.h"
Controller::Controller() {
// OpenGL setup
// MUST happen before anything gets visible (= gets initialized)
QSurfaceFormat format;
format.setDepthBufferSize(16);
QSurfaceFormat::setDefaultFormat(format);
// configure the to-be-used sensor factory
//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/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(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"));
// live data on the smartphone
if (1 == 1) {
// use android's sensors
SensorFactory::set(new SensorFactoryAndroid());
// write them to file??
//const std::string file = Settings::Data::getRecordsDir() + "/" + std::to_string(Timestamp::fromUnixTime().ms()) + ".csv";
//SensorWriter* writer = new SensorWriter();
//writer->start(file);
// start the sensors
SensorFactory::get().getAccelerometer().start();
SensorFactory::get().getGyroscope().start();
SensorFactory::get().getBarometer().start();
SensorFactory::get().getWiFi().start();
SensorFactory::get().getGPS().start();
SensorFactory::get().getCompass().start();
SensorFactory::get().getBLE().start();
}
// create the main window
mainWindow = new MainWindow();
//sl = new StepLoggerWrapperAndroid(scaler);
//sl = new StepLoggerWrapper(scaler, 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::onDebugButton, this, &Controller::onDebugButton), "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::onCameraButton, this, &Controller::onCameraButton), "connect() failed");
Assert::isTrue(connect(mainWindow->getMainMenu(), &MainMenu::on3DButton, this, &Controller::on3DButton), "connect() failed");
// order is important! otherwise OpenGL fails!
mainWindow->show();
// // start all sensors
// SensorFactory::get().getAccelerometer().start();
// SensorFactory::get().getGyroscope().start();
// SensorFactory::get().getBarometer().start();
// SensorFactory::get().getWiFi().start();
}
MapView3D* Controller::getMapView3D() const {
return mainWindow->getMapView3D();
}
MapView2D* Controller::getMapView2D() const {
return mainWindow->getMapView2D();
}
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) {
WiFiCalibrationDataModel mdl(fpFile);
Assert::isFalse(mdl.getFingerprints().empty(), "no fingerprints available!");
WiFiOptimizer::LogDistCeiling opt(map, Settings::WiFiModel::vg_calib);
for (const WiFiFingerprint& fp : mdl.getFingerprints()) {
opt.addFingerprint(fp);
}
const WiFiOptimizer::LogDistCeiling::APParamsList res = opt.optimizeAll(opt.NONE);
WiFiGridEstimator::estimate(*grid, wifiModel, Settings::smartphoneAboveGround);
for (const WiFiOptimizer::LogDistCeiling::APParamsMAC& ap : res.get()) {
const WiFiModelLogDistCeiling::APEntry entry(ap.params.getPos(), ap.params.txp, ap.params.exp, ap.params.waf);
wifiModel.addAP(ap.mac, entry);
}
} else {
// NOTE IPIN UAH map does not make sense.. APs look like VAPs but are not
// -> disable VAP-grouping in Settings.h [this is for eval and here]
// load all APs from the floorplan and use same TXP/EXP/WAF for all of them
//wifiModel.loadAPs(map, Settings::WiFiModel::vg_calib, Settings::WiFiModel::TXP, Settings::WiFiModel::EXP, Settings::WiFiModel::WAF);
wifiModel.loadAPs(map, Settings::WiFiModel::TXP, Settings::WiFiModel::EXP, Settings::WiFiModel::WAF);
Assert::isFalse(wifiModel.getAllAPs().empty(), "no AccessPoints stored within the map.xml");
}
// build the grid
GridFactory<MyGridNode> gf(*grid);
gf.build(map);
// add node-importance
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);
grid->write(out);
out.close();
}
WiFiModel* buildWiFiModelOnce(Floorplan::IndoorMap* map, const std::string& fpFile, const std::string& wifiModelFile){
// 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);
WiFiModel* wifiModel = new WiFiModelLogDistCeiling(map);
// WiFi setup
if (replyWiFiFP == QMessageBox::Yes) {
std::ifstream inp(wifiModelFile, std::ifstream::binary);
if (!inp.good() || (inp.peek()&&0) || inp.eof()) {
Log::add("Controller", "Create new WiFiModel");
WiFiCalibrationDataModel mdl(fpFile);
Assert::isFalse(mdl.getFingerprints().empty(), "no fingerprints available!");
WiFiOptimizer::LogDistCeiling opt(map, Settings::WiFiModel::vg_calib);
for (const WiFiFingerprint& fp : mdl.getFingerprints()) {
opt.addFingerprint(fp);
}
const WiFiOptimizer::LogDistCeiling::APParamsList res = opt.optimizeAll(opt.NONE);
for (const WiFiOptimizer::LogDistCeiling::APParamsMAC& ap : res.get()) {
const WiFiModelLogDistCeiling::APEntry entry(ap.params.getPos(), ap.params.txp, ap.params.exp, ap.params.waf);
((WiFiModelLogDistCeiling*) wifiModel)->addAP(ap.mac, entry);
}
((WiFiModelLogDistCeiling*) wifiModel)->saveXML(wifiModelFile);
} else {
Log::add("Controller", "Use existing WifiModel");
// load WiFiModel from file. The factory will create the correct instance
//WiFiModel->loadXML(setup.wifiModel);
WiFiModelFactory fac(map);
if(wifiModel){delete wifiModel;}
wifiModel = fac.loadXML(wifiModelFile);
}
} else {
Log::add("Controller", "Read AP from File");
// load all APs from the floorplan and use same TXP/EXP/WAF for all of them
((WiFiModelLogDistCeiling*)wifiModel)->loadAPs(map, Settings::WiFiModel::TXP, Settings::WiFiModel::EXP, Settings::WiFiModel::WAF);
Assert::isFalse(wifiModel->getAllAPs().empty(), "no AccessPoints stored within the map.xml");
}
return wifiModel;
}
BeaconModel* buildBLEModelOnce(Floorplan::IndoorMap* map, const std::string& fpFile, const std::string& bleModelFile){
// ask questions
const QMessageBox::StandardButton replyWiFiFP = QMessageBox::question(nullptr, "BLE", "Use Fingerprints for Bluetooth Calibration?\n\nYes: Use fingerprints and num-optimize AP-Params\nNo: Use Beacons from the map.xml (pos+params)", QMessageBox::Yes|QMessageBox::No);
BeaconModel* bleModel = new BeaconModelLogDistCeiling(map);
return bleModel;
}
void Controller::on3DButton() {
static bool use3D = false;
use3D = !use3D;
getMapView2D()->setVisible(!use3D);
getMapView3D()->setVisible( use3D);
}
void Controller::onLoadButton() {
// pick a map to load
QDir dir = LoadSetupDialog::pickSetupFolder();
// cancelled?
if (dir.path() == ".") { return; }
loadNavMesh(dir);
}
void Controller::loadGrid(QDir dir) {
QFile fMap(dir.path() + "/map.xml");
QFile fGrid(dir.path() + "/grid.dat");
QFile fWiFiFP(dir.path() + "/wifi_fp.dat");
QFile fBLEFP(dir.path() + "/ble_fp.dat");
Assert::isTrue(fMap.exists(), "map.xml missing");
//Assert::isTrue(fGrid.exists(), "grid.dat missing");
fMap.open(QIODevice::ReadOnly);
QString str = QString(fMap.readAll());
im = Floorplan::Reader::readFromString(str.toStdString());
const std::string sGrid = fGrid.fileName().toStdString();
std::ifstream inp(sGrid, std::ifstream::binary);
//Assert::isTrue(inp.good(), "failed to open grid.dat");
const std::string sWiFiFP = fWiFiFP.fileName().toStdString();
const std::string sBLEFP = fBLEFP.fileName().toStdString();
// create a new, empty grid
if (grid) {delete grid; grid = nullptr;}
grid = new Grid<MyGridNode>(Settings::Grid::gridSize_cm);
// grid.dat empty? -> build one and save it
if (!inp.good() || (inp.peek()&&0) || inp.eof()) {
buildGridOnce(grid, im, sWiFiFP, sGrid);
} else {
grid->read(inp);
}
// create a new navigator
if (nav) {delete nav; nav = nullptr;}
nav = new GridBased::NavControllerGrid(this, im, grid);
WiFiCalibrationDataModel* wifiCalib = new WiFiCalibrationDataModel(sWiFiFP);
BLECalibrationDataModel* bleCalib = new BLECalibrationDataModel(sBLEFP);
getMapView3D()->setMap(im);
getMapView2D()->setMap(wifiCalib, bleCalib, im);
getMapView3D()->showGridImportance(grid);
getMapView2D()->showGridImportance(grid);
getMapView3D()->setVisible(false);
// attach ipin step logger
//nav->addListener(sl);
}
void Controller::loadNavMesh(QDir dir) {
QFile fMap(dir.path() + "/map.xml");
QFile fGrid(dir.path() + "/grid.dat");
QFile fWiFiFP(dir.path() + "/wifi_fp.dat");
QFile fWiFiModel(dir.path() + "/wifimodel.dat");
QFile fBLEFP(dir.path() + "/ble_fp.dat");
Assert::isTrue(fMap.exists(), "map.xml missing");
fMap.open(QIODevice::ReadOnly);
QString str = QString(fMap.readAll());
im = Floorplan::Reader::readFromString(str.toStdString());
const std::string sWiFiFP = fWiFiFP.fileName().toStdString();
const std::string sWiFiModel = fWiFiModel.fileName().toStdString();
const std::string sBLEFP = fBLEFP.fileName().toStdString();
wifiModel = buildWiFiModelOnce(im, sWiFiFP, sWiFiModel);
// create navmesh
if (navMesh) {delete navMesh; navMesh = nullptr;}
NM::NavMeshSettings settings;
navMesh = new NM::NavMesh<NM::NavMeshTriangle>();
NM::NavMeshFactory<NM::NavMeshTriangle> fac(navMesh, settings);
fac.build(im);
// create a new navigator
if (nav) {delete nav; nav = nullptr;}
nav = new MeshBased::NavControllerMesh(this, im, navMesh, wifiModel);
WiFiCalibrationDataModel* wifiCalib = new WiFiCalibrationDataModel(sWiFiFP);
BLECalibrationDataModel* bleCalib = new BLECalibrationDataModel(sBLEFP);
getMapView3D()->setMap(im);
getMapView2D()->setMap(wifiCalib, bleCalib, im);
//getMapView3D()->showGridImportance(grid);
//getMapView2D()->showGridImportance(grid);
getMapView3D()->setVisible(false);
// attach ipin step logger
//nav->addListener(sl);
}
void Controller::onDebugButton() {
mainWindow->getSensorDataWidget()->setVisible( !mainWindow->getSensorDataWidget()->isVisible() );
}
void Controller::onStartButton() {
nav->start();
}
void Controller::onTransparentButton() {
mainWindow->getMapView3D()->toggleRenderMode();
}
void Controller::onCameraButton() {
nav->toggleCamera();
}