From 44f9b6ac8093b67aac73c2f15e1ffa2799f9cce9 Mon Sep 17 00:00:00 2001 From: kazu Date: Sat, 1 Oct 2016 10:21:15 +0200 Subject: [PATCH] performance enhancements memory enhancements prevent starting sensors more than once fix for wifi lag issues map scaling for huge buildings --- Controller.cpp | 6 +- Settings.h | 3 +- _android/src/WiFi.java | 27 ++++++++- ipin/StepLoggerWrapperAndroid.h | 8 +-- nav/NavController.h | 2 +- sensors/android/AccelerometerSensorAndroid.h | 12 +++- sensors/android/BarometerSensorAndroid.h | 7 ++- sensors/android/GyroscopeSensorAndroid.h | 12 +++- sensors/android/WiFiSensorAndroid.h | 20 ++++++- ui/MainWindow.cpp | 10 +++- ui/map/2D/MapView2D.cpp | 62 +++++++++++++++++++- ui/map/2D/MapView2D.h | 5 ++ ui/map/2D/Scaler2D.h | 22 ++++++- ui/map/3D/MapView3D.cpp | 18 +++++- ui/map/3D/MapView3D.h | 2 + ui/map/3D/elements/ColorPoints.h | 7 +++ 16 files changed, 197 insertions(+), 26 deletions(-) diff --git a/Controller.cpp b/Controller.cpp index 22e54ae..d089517 100644 --- a/Controller.cpp +++ b/Controller.cpp @@ -51,9 +51,9 @@ Controller::Controller() : sl(scaler) { //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 SensorFactoryOffline(Settings::Data::getOfflineDir() + "/bergwerk/path4/nexus/vor/1454776525797.csv")); - //SensorFactory::set(new SensorFactoryAndroid()); + SensorFactory::set(new SensorFactoryAndroid()); // SensorFactory::get().getAccelerometer().start(); // SensorFactory::get().getGyroscope().start(); // SensorFactory::get().getBarometer().start(); @@ -218,8 +218,6 @@ void Controller::onLoadButton() { getMapView3D()->showGridImportance(grid); getMapView2D()->showGridImportance(grid); - getMapView3D()->setVisible(false); - // attach ipin step logger nav->addListener(&sl); diff --git a/Settings.h b/Settings.h index 082e351..a5e57ee 100644 --- a/Settings.h +++ b/Settings.h @@ -42,7 +42,8 @@ namespace Settings { - namespace MapView { + namespace MapView3D { + const int maxColorPoints = 10000; constexpr int fps = 15; const Timestamp msPerFrame = Timestamp::fromMS(1000/fps); } diff --git a/_android/src/WiFi.java b/_android/src/WiFi.java index 47b5b37..66c34f2 100644 --- a/_android/src/WiFi.java +++ b/_android/src/WiFi.java @@ -18,7 +18,8 @@ public class WiFi { private static WifiManager manager; private static BroadcastReceiver receiver; - + private static Thread tHeartbeat = null; + private static long lastScanStartTS = 0; /** called when a scan is completed successfully */ public static native void onScanComplete(final byte[] result); @@ -48,7 +49,28 @@ public class WiFi { act.registerReceiver(WiFi.receiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); // start the first scan - triggerOneScan(); + triggerOneScan(); + + + + // if the scan result takes longer than X milliseconds, + // trigger another-scan to ensure nothing is stuck + final Runnable r = new Runnable() { + public void run() { + while(true) { + final long ts = System.currentTimeMillis(); + final long diff = ts - lastScanStartTS; + if (diff > 1000) { triggerOneScan(); } + try {Thread.sleep(200);} catch (final Exception e) {;} + } + } + }; + + // start the heartbeat once + if (tHeartbeat == null) { + tHeartbeat = new Thread(r); + tHeartbeat.start(); + } return 1337; @@ -91,6 +113,7 @@ public class WiFi { try { if(!manager.startScan()) {throw new RuntimeException("Cant start WiFi!");} + lastScanStartTS = System.currentTimeMillis(); }catch (final Exception e) { throw new RuntimeException(e); } diff --git a/ipin/StepLoggerWrapperAndroid.h b/ipin/StepLoggerWrapperAndroid.h index 114e08a..9ae48ab 100644 --- a/ipin/StepLoggerWrapperAndroid.h +++ b/ipin/StepLoggerWrapperAndroid.h @@ -5,7 +5,7 @@ #include "../nav/NavControllerListener.h" #include -#ifdef Android +#ifdef ANDROID #include #endif @@ -48,10 +48,10 @@ 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"); +#ifdef ANDROID + //Log::add("SLWA", "calling android with lon/lat/floor"); int res = QAndroidJniObject::callStaticMethod("indoor/java/StepLoggerClient", "log", "(DDD)I", x, y, z); - if (res != 1337) {throw Exception("error while logging");} + //if (res != 1337) {throw Exception("invalid return code while sending the current position to StepLogger.\nService Down?");} #endif } diff --git a/nav/NavController.h b/nav/NavController.h index faafebf..477d9bf 100644 --- a/nav/NavController.h +++ b/nav/NavController.h @@ -336,7 +336,7 @@ private: } - const int display_ms = Settings::MapView::msPerFrame.ms(); + const int display_ms = Settings::MapView3D::msPerFrame.ms(); /** UI update loop */ void updateMapViewLoop() { diff --git a/sensors/android/AccelerometerSensorAndroid.h b/sensors/android/AccelerometerSensorAndroid.h index ed6bb7a..210b647 100644 --- a/sensors/android/AccelerometerSensorAndroid.h +++ b/sensors/android/AccelerometerSensorAndroid.h @@ -23,6 +23,8 @@ private: ; } + bool started = false; + public: /** singleton access */ @@ -33,26 +35,30 @@ public: void start() override { + if (started) {return;} + started = true; + auto onSensorData = [&] () { AccelerometerData data(acc.reading()->x(), acc.reading()->y(), acc.reading()->z()); informListeners(data); }; + // accelerometer is usually verry fast -> limit the maximum data-rate to 200 Hz (5ms) + acc.setDataRate(200); + acc.connect(&acc, &QAccelerometer::readingChanged, onSensorData); acc.start(); } bool isRunning() const override { - return acc.isActive(); + return started; } void stop() override { throw "TODO"; } - - }; #endif // ANDROID diff --git a/sensors/android/BarometerSensorAndroid.h b/sensors/android/BarometerSensorAndroid.h index 2fcb5c1..6760f10 100644 --- a/sensors/android/BarometerSensorAndroid.h +++ b/sensors/android/BarometerSensorAndroid.h @@ -22,6 +22,8 @@ private: ; } + bool started = false; + public: /** singleton access */ @@ -32,6 +34,9 @@ public: void start() override { + if (started) {return;} + started = true; + auto onSensorData = [&] () { BarometerData data(baro.reading()->pressure() / 100.0f); // convert Pa to hPa informListeners(data); @@ -43,7 +48,7 @@ public: } bool isRunning() const override { - return baro.isActive(); + return started; } void stop() override { diff --git a/sensors/android/GyroscopeSensorAndroid.h b/sensors/android/GyroscopeSensorAndroid.h index 4f33e86..05377c3 100644 --- a/sensors/android/GyroscopeSensorAndroid.h +++ b/sensors/android/GyroscopeSensorAndroid.h @@ -22,6 +22,8 @@ private: ; } + bool started = false; + public: /** singleton access */ @@ -36,18 +38,26 @@ public: void start() override { + if (started) {return;} + started = true; + auto onSensorData = [&] () { GyroscopeData data(degToRad(gyro.reading()->x()), degToRad(gyro.reading()->y()), degToRad(gyro.reading()->z())); informListeners(data); +// const Timestamp now = Timestamp::fromRunningTime(); +// Log::add("123", "ts:" + std::to_string(now.ms())); }; + // gyroscope is usually not as fast as the acceleromter -> limiting not needed + //gyro.setDataRate(200); + gyro.connect(&gyro, &QGyroscope::readingChanged, onSensorData); gyro.start(); } bool isRunning() const override { - return gyro.isActive(); + return started; } void stop() override { diff --git a/sensors/android/WiFiSensorAndroid.h b/sensors/android/WiFiSensorAndroid.h index 40c37b8..8840da3 100644 --- a/sensors/android/WiFiSensorAndroid.h +++ b/sensors/android/WiFiSensorAndroid.h @@ -9,6 +9,8 @@ #include "../../misc/Debug.h" #include "../WiFiSensor.h" +#include + class WiFiSensorAndroid : public WiFiSensor { private: @@ -30,11 +32,11 @@ public: // do NOT start twice! if (started) {return;} + started = true; // start scanning int res = QAndroidJniObject::callStaticMethod("indoor/java/WiFi", "start", "()I"); if (res != 1337) {throw Exception("error while starting WiFi");} - started = true; } @@ -46,7 +48,11 @@ public: return started; } - /** called from java. handle the given incoming scan result */ + /** + * called from WiFi.java + * handle the given incoming scan result + * just a bit curious, thus std::string instead of std::string& + */ void handle(const std::string data) { // to-be-constructed sensor data @@ -68,6 +74,16 @@ public: // call listeners informListeners(sensorData); + // interval debug +// static Timestamp lastTS; +// const Timestamp diff = curTS - lastTS; +// Log::add("wifi", std::to_string(diff.ms())); +// if (diff.ms() > 650) { +// Log::add("wifi", "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); +// } +// lastTS = curTS; + + } }; diff --git a/ui/MainWindow.cpp b/ui/MainWindow.cpp index c1fa7ca..7bcb1f4 100644 --- a/ui/MainWindow.cpp +++ b/ui/MainWindow.cpp @@ -22,14 +22,20 @@ MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { mainMenu = new MainMenu(this); infoWidget = new InfoWidget(this); - sensorWidget = new SensorDataWidget(this); sensorWidget->setVisible(false); + sensorWidget = new SensorDataWidget(this); - //sensorWidget->setVisible(false); + // ensure we are fullscreen showMaximized(); sleep(1); emit resizeEvent(nullptr); + // important! must be called AFTER window is visible + // otherwise MapView3D's openGL context is uninitialized. + sensorWidget->setVisible(false); + mapView2D->setVisible(true); + mapView3D->setVisible(false); + } void MainWindow::resizeEvent(QResizeEvent* event) { diff --git a/ui/map/2D/MapView2D.cpp b/ui/map/2D/MapView2D.cpp index 76ae493..3fa85e7 100644 --- a/ui/map/2D/MapView2D.cpp +++ b/ui/map/2D/MapView2D.cpp @@ -4,8 +4,10 @@ #include #include #include +#include #include +#include #include "Floor2D.h" #include "ColorPoints2D.h" @@ -67,7 +69,12 @@ MapView2D::MapView2D(QWidget *parent) : QWidget(parent) { lay->addWidget(btnLayerPlus, row, 2, 1, 1); + // start with invisible particles. speeds things up a bit + colorPoints->setVisible(false); + // we want to receive pinch gestures + //setAttribute(Qt::WA_AcceptTouchEvents, true); + grabGesture(Qt::PinchGesture); } @@ -96,7 +103,11 @@ void MapView2D::setMap(WiFiCalibrationDataModel* mdl, Floorplan::IndoorMap* map) wifiCalib = new WiFiCalibTool(mdl, map); elementsB.push_back(wifiCalib); - scaler.setCenterM(Point2(70, 35)); + const BBox3 bbox3 = FloorplanHelper::getBBox(map); + const BBox2 bbox2 = BBox2(bbox3.getMin().xy(), bbox3.getMax().xy()); + + scaler.setMapBBox(bbox2); + scaler.setCenterM(Point2(bbox2.getCenter().x, bbox2.getCenter().y)); } @@ -169,6 +180,16 @@ void MapView2D::mouseReleaseEvent(QMouseEvent* evt) { } +void MapView2D::wheelEvent(QWheelEvent* event) { + if (event->delta() < 0) { + scaler.mulScale(0.5); + emit update(); + } else { + scaler.mulScale(2.0); + emit update(); + } +} + void MapView2D::paintEvent(QPaintEvent*) { QPainter qp(this); @@ -183,3 +204,42 @@ void MapView2D::paintEvent(QPaintEvent*) { qp.end(); } + +bool MapView2D::event(QEvent *event) { + + switch (event->type()) { + case QEvent::Gesture: + return gestureEvent(static_cast(event)); + + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + + // prevent [additional] mouse events for undetected gestures [more than 1 finger] + // TODO: not yet stable... improvements? + if (static_cast(event)->touchPoints().count() == 2) {return true;} + break; + + default: + break; + } + + // event not consumed. bubble it to following stages. + // this will e.g. generate mouseMoveEvent etc. + return QWidget::event(event); + +} + +bool MapView2D::gestureEvent(QGestureEvent *event) { + + if (QGesture* pinch = event->gesture(Qt::PinchGesture)) { + const QPinchGesture* pg = static_cast(pinch); + scaler.mulScale(pg->scaleFactor()); + emit update(); + return true; // event consumed + } + + // event not consumed + return false; + +} diff --git a/ui/map/2D/MapView2D.h b/ui/map/2D/MapView2D.h index db10bb2..f85b12d 100644 --- a/ui/map/2D/MapView2D.h +++ b/ui/map/2D/MapView2D.h @@ -21,6 +21,7 @@ class MyGridNode; class Renderable2D; class QSlider; class QPushButton; +class QGestureEvent; class ColorPoints2D; class Path2D; @@ -127,6 +128,10 @@ public slots: void mousePressEvent(QMouseEvent*); void mouseMoveEvent(QMouseEvent*); void mouseReleaseEvent(QMouseEvent*); + void wheelEvent(QWheelEvent*); + + bool event(QEvent*); + bool gestureEvent(QGestureEvent *event); }; diff --git a/ui/map/2D/Scaler2D.h b/ui/map/2D/Scaler2D.h index e66063e..d7c7e20 100644 --- a/ui/map/2D/Scaler2D.h +++ b/ui/map/2D/Scaler2D.h @@ -3,6 +3,7 @@ #include #include +#include class Scaler2D { @@ -13,6 +14,8 @@ private: float rotation_rad = 0.0f; float scaleFactor = 1; + BBox2 mapBBox_m; + public: Scaler2D() { @@ -32,11 +35,17 @@ public: /** change the point displayed within the center of the screen */ void setCenterM(const Point2 center_m) { this->center_m = center_m; + if (!mapBBox_m.isInvalid()) { + if (this->center_m.x < mapBBox_m.getMin().x) {this->center_m.x = mapBBox_m.getMin().x;} + if (this->center_m.y < mapBBox_m.getMin().y) {this->center_m.y = mapBBox_m.getMin().y;} + if (this->center_m.x > mapBBox_m.getMax().x) {this->center_m.x = mapBBox_m.getMax().x;} + if (this->center_m.y > mapBBox_m.getMax().y) {this->center_m.y = mapBBox_m.getMax().y;} + } } /** change the point displayed within the center of the screen */ void setCenterPX(const Point2 center_px) { - this->center_m = pxToM(center_px); + setCenterM(pxToM(center_px)); } Point2 getCenterPX() const { @@ -48,10 +57,21 @@ public: this->rotation_rad = rad; } + /** set the map's scaling */ void setScale(const float scale) { this->scaleFactor = scale; + if (this->scaleFactor < 0.1) {this->scaleFactor = 0.1;} + if (this->scaleFactor > 4.0) {this->scaleFactor = 4.0;} } + void mulScale(const float mod) { + setScale(this->scaleFactor * mod); + } + + /** set the map's bbox. used to prevent from scrolling outside of the map */ + void setMapBBox(const BBox2 bbox_m) { + this->mapBBox_m = bbox_m; + } public: diff --git a/ui/map/3D/MapView3D.cpp b/ui/map/3D/MapView3D.cpp index 21a4f6e..b455061 100644 --- a/ui/map/3D/MapView3D.cpp +++ b/ui/map/3D/MapView3D.cpp @@ -108,14 +108,26 @@ void MapView3D::initializeGL() { glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); - // start background update timer - timer.start(Settings::MapView::msPerFrame.ms(), this); - // OpenGL is now initialized isGLInitialized = true; } +void MapView3D::setVisible(bool visible) { + + // inform parent + QOpenGLWidget::setVisible(visible); + + if (!visible) { + // stop background update timer + timer.stop(); + } else { + // start background update timer + timer.start(Settings::MapView3D::msPerFrame.ms(), this); + } + +} + void MapView3D::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw(); diff --git a/ui/map/3D/MapView3D.h b/ui/map/3D/MapView3D.h index d61f2a8..d56372b 100644 --- a/ui/map/3D/MapView3D.h +++ b/ui/map/3D/MapView3D.h @@ -140,6 +140,8 @@ public: void toggleRenderMode(); + void setVisible(bool visible) override; + public slots: void mousePressEvent(QMouseEvent*); diff --git a/ui/map/3D/elements/ColorPoints.h b/ui/map/3D/elements/ColorPoints.h index dcad3a9..7d2c2a0 100644 --- a/ui/map/3D/elements/ColorPoints.h +++ b/ui/map/3D/elements/ColorPoints.h @@ -10,6 +10,7 @@ //#include "../gl/GLTriangles.h" #include "../Renderable.h" +#include "../../../../Settings.h" #include "../../../../nav/Node.h" class ColorPoints : public Renderable { @@ -31,6 +32,9 @@ public: points.clear(); + // do not display? + if (grid->getNumNodes() > Settings::MapView3D::maxColorPoints) {return;} + float min = +INFINITY; float max = -INFINITY; @@ -62,6 +66,9 @@ public: points.clear(); + // do not display? + if (particles.size() > Settings::MapView3D::maxColorPoints) {return;} + // group particles by grid-point std::unordered_map weights; for (const K::Particle& p : particles) {