diff --git a/.gitignore b/.gitignore index 085545b..6ee5457 100644 --- a/.gitignore +++ b/.gitignore @@ -37,4 +37,4 @@ Makefile* # QtCtreator CMake CMakeLists.txt.user* - +PaxHeader/ diff --git a/Manager.cpp b/Manager.cpp new file mode 100644 index 0000000..1883c11 --- /dev/null +++ b/Manager.cpp @@ -0,0 +1,105 @@ +#include "Manager.h" + +#ifdef ANDROID + #include +#endif + +#include +#include +#include + +const std::string NUC1 = "38:de:ad:6d:77:25"; +const std::string NUC2 = "38:de:ad:6d:60:ff"; +const std::string NUC3 = "1c:1b:b5:ef:a2:9a"; +const std::string NUC4 = "1c:1b:b5:ec:d1:82"; + +Manager::Manager() { + + +} + +void Manager::trigger() { + +#ifdef ANDROID + + QAndroidJniObject::callStaticMethod("android/net/wifi/RTT", "start", "()I"); + +#else + + //onData("38:de:ad:6d:77:25;FAILED"); + onData(NUC1+";6230;1231"); + onData(NUC2+";3430;3423"); + onData(NUC3+";5630;2341"); + onData(NUC4+";8830;2241"); + +#endif + + + + +} + +void Manager::onData(std::string str) { + + qDebug() << QString(str.c_str()); + + std::stringstream lineStream(str); + std::string cell; + + std::string mac; + + int distIndex = 0; + int i = 0; + const float alpha = 0.7f; + + while (std::getline(lineStream, cell, ';')) { + + switch(i) { + + case 0: { + if(NUC1 == cell) {distIndex = 0;} + if(NUC2 == cell) {distIndex = 1;} + if(NUC3 == cell) {distIndex = 2;} + if(NUC4 == cell) {distIndex = 3;} + break; + } + + case 1: { + if ("FAILED" == cell) { + _dist[distIndex] = 0; + } else { + //_dist[distIndex] = std::stoi(cell); + _dist[distIndex] = _dist[distIndex] * alpha + atoi(cell.c_str()) * (1-alpha); + } + break; + } + + case 2: { + _stdDev[distIndex] = atoi(cell.c_str()); + break; + } + + } + ++i; + } + + emit distChanged(); + +} + +Manager mgmt; + +#ifdef ANDROID +extern "C" { + + JNIEXPORT void JNICALL Java_android_net_wifi_RTT_onRTTComplete(JNIEnv* env, jobject jobj, jbyteArray arrayID) { + (void) env; (void) jobj; + jsize length = env->GetArrayLength(arrayID); + jbyte* data = env->GetByteArrayElements(arrayID, 0); + std::string str((char*)data, length); + env->ReleaseByteArrayElements(arrayID, data, JNI_ABORT); + mgmt.onData(str); + } + +} +#endif diff --git a/Manager.h b/Manager.h new file mode 100644 index 0000000..a84958d --- /dev/null +++ b/Manager.h @@ -0,0 +1,54 @@ +#ifndef MANAGER_H +#define MANAGER_H + +#include + +class Manager : public QObject { + + Q_OBJECT + +private: + + float _dist[4]; + float _stdDev[4]; + +public: + + Q_PROPERTY(float dist1 READ getDist1() NOTIFY distChanged) + Q_PROPERTY(float dist2 READ getDist2() NOTIFY distChanged) + Q_PROPERTY(float dist3 READ getDist3() NOTIFY distChanged) + Q_PROPERTY(float dist4 READ getDist4() NOTIFY distChanged) + + Q_PROPERTY(float stdDev1 READ getStdDev1() NOTIFY distChanged) + Q_PROPERTY(float stdDev2 READ getStdDev2() NOTIFY distChanged) + Q_PROPERTY(float stdDev3 READ getStdDev3() NOTIFY distChanged) + Q_PROPERTY(float stdDev4 READ getStdDev4() NOTIFY distChanged) + + + Q_INVOKABLE void trigger(); + + void onData(std::string str); + +public: + + float getDist1() {return _dist[0];} + float getDist2() {return _dist[1];} + float getDist3() {return _dist[2];} + float getDist4() {return _dist[3];} + + float getStdDev1() {return _stdDev[0];} + float getStdDev2() {return _stdDev[1];} + float getStdDev3() {return _stdDev[2];} + float getStdDev4() {return _stdDev[3];} + +signals: + + void distChanged(); + +public: + + Manager(); + +}; + +#endif // MANAGER_H diff --git a/RTT.pro b/RTT.pro new file mode 100644 index 0000000..2203fb9 --- /dev/null +++ b/RTT.pro @@ -0,0 +1,45 @@ +QT += quick +QT += androidextras +CONFIG += c++11 + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += \ + main.cpp \ + Manager.cpp + +RESOURCES += qml.qrc + +OTHER_FILES += \ + _android/src/MyActivity.java\ + _android/src/WiFi.java\ + _android/src/RTT.java\ + _android/src/LocationPermissionController.java\ + _android/AndroidManifest.xml + +# use files in ./_android for the project as well +ANDROID_PACKAGE_SOURCE_DIR = $$PWD/_android + + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +HEADERS += \ + Manager.h diff --git a/_android/AndroidManifest.xml b/_android/AndroidManifest.xml new file mode 100644 index 0000000..37b01e0 --- /dev/null +++ b/_android/AndroidManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/_android/build.gradle.2 b/_android/build.gradle.2 new file mode 100644 index 0000000..c044907 --- /dev/null +++ b/_android/build.gradle.2 @@ -0,0 +1,8 @@ +buildscript { + + dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile "com.android.support:support-v4:23.0.+" + } + +} diff --git a/_android/src/LocationPermissionController.java b/_android/src/LocationPermissionController.java new file mode 100644 index 0000000..ae59b39 --- /dev/null +++ b/_android/src/LocationPermissionController.java @@ -0,0 +1,70 @@ +package de.plinzen.android.rttmanager.permission; + +import android.Manifest; +import android.app.Activity; +import android.content.Context; +import android.content.pm.PackageManager; +import android.support.annotation.NonNull; +//import android.support.design.widget.Snackbar; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; +import android.view.View; + +//import de.plinzen.android.rttmanager.R; + +/* +public class LocationPermissionController { + + private static final int REQUEST_LOCATION_PERMISSION = 8545; + + public boolean checkLocationPermissions(final Context context) { + return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == + PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(context, Manifest.permission + .ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; + } + + public boolean onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, + @NonNull final int[] grantResults) { + if (requestCode == REQUEST_LOCATION_PERMISSION) { + return verifyPermissions(grantResults); + } + return false; + } + + public void requestLocationPermission(final Activity activity, final View snackbarContainer) { + if (ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission.ACCESS_COARSE_LOCATION) || + ActivityCompat.shouldShowRequestPermissionRationale(activity, Manifest.permission + .ACCESS_FINE_LOCATION)) { + // Snackbar.make(snackbarContainer, R.string.permission_location_description, Snackbar.LENGTH_INDEFINITE) + // .setAction(android.R.string.ok, view -> requestPermissions(activity)).show(); + Snackbar.make(snackbarContainer, R.string.permission_location_description, Snackbar.LENGTH_INDEFINITE) + .setAction(android.R.string.ok, new View.OnClickListener() { + public void onClick(View v) { + requestPermissions(activity); + } + }).show(); + } else { + requestPermissions(activity); + } + } + + private void requestPermissions(final Activity activity) { +// ActivityCompat.requestPermissions(activity, +// new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, +// REQUEST_LOCATION_PERMISSION); + } + + private boolean verifyPermissions(int[] grantResults) { + if (grantResults.length < 1) { + return false; + } + + for (int result : grantResults) { + if (result != PackageManager.PERMISSION_GRANTED) { + return false; + } + } + return true; + } +} +*/ diff --git a/_android/src/MyActivity.java b/_android/src/MyActivity.java new file mode 100644 index 0000000..320a50d --- /dev/null +++ b/_android/src/MyActivity.java @@ -0,0 +1,37 @@ +package indoor.java; + +import android.os.Bundle; +import android.view.WindowManager; +import org.qtproject.qt5.android.bindings.QtActivity; +import android.widget.Toast; + +public class MyActivity extends QtActivity { + + public static MyActivity act; + + // IPIN2016 + //private StepLoggerClient stepLogger; + + + @Override + public void onCreate(Bundle savedState) { + + MyActivity.act = this; + super.onCreate(savedState); + + // prevent power-safe? + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + // IPIN2016 + //stepLogger = new StepLoggerClient(this); + + } + + @Override + public void onDestroy() { + super.onDestroy(); + MyActivity.act = null; + } + + +} diff --git a/_android/src/RTT.java b/_android/src/RTT.java new file mode 100644 index 0000000..d3ab95f --- /dev/null +++ b/_android/src/RTT.java @@ -0,0 +1,195 @@ +//package indoor.java; +package android.net.wifi; + +import android.app.Activity; +import android.util.Log; +import android.content.Context; + +import java.util.List; +import java.util.ArrayList; + +import android.net.wifi.ScanResult; +import android.net.wifi.rtt.RangingRequest; +import android.net.wifi.rtt.RangingResult; +import android.net.wifi.rtt.RangingResultCallback; +import android.net.wifi.rtt.WifiRttManager; + +import java.util.concurrent.Executor; +import android.net.MacAddress; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Array; + +import indoor.java.MyActivity; +import java.io.ByteArrayOutputStream; + + +public class RTT { + + private static Activity act; + private static WifiRttManager rttManager; + private static Executor mainExecutor; + + // called when a RTT is completed successfully + public static native void onRTTComplete(final byte[] result); + + // result callback + private static final RangingResultCallback callback = new RangingResultCallback() { + @Override + public void onRangingFailure(final int i) { + //emitter.onError(new RuntimeException("The WiFi-Ranging failed with error code: " + i)); + Log.d("RTT", "onRangingFailure: " + i); + } + + @Override + public void onRangingResults(final List list) { + //emitter.onSuccess(list); + Log.d("RTT", "onRangingResults: " + list.size()); + + for (final RangingResult res : list) { + + final MacAddress mac = res.getMacAddress(); + if (res.getStatus() == RangingResult.STATUS_SUCCESS) { + final int dist = res.getDistanceMm(); + final int stdDevDist = res.getDistanceStdDevMm(); + Log.d("RTT", mac.toString() + " " + dist + " " + stdDevDist); + } else { + Log.d("RTT", mac.toString() + " FAILED"); + } + + RTT.onRTTComplete(serialize(res)); + + } + + } + }; + + private static byte[] serialize(final RangingResult res) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + + char delim = ';'; + + baos.write(res.getMacAddress().toString().getBytes()); + baos.write(delim); + + if (res.getStatus() == RangingResult.STATUS_SUCCESS) { + baos.write( ("" + res.getDistanceMm()).getBytes() ); + baos.write(delim); + baos.write( ("" + res.getDistanceStdDevMm()).getBytes() ); + } else { + baos.write( "FAILED".getBytes() ); + } + + } catch (final Exception e) {;} + return baos.toByteArray(); + } + + + public static int start() { + + Log.d("RTT", "start()"); + + MyActivity act = MyActivity.act; + rttManager = (WifiRttManager) act.getSystemService(Context.WIFI_RTT_RANGING_SERVICE); + + mainExecutor = act.getMainExecutor(); + + final ArrayList macs = new ArrayList<>(); + macs.add(MacAddress.fromString("38:de:ad:6d:77:25")); // NUC 1 + macs.add(MacAddress.fromString("38:de:ad:6d:60:ff")); // NUC 2 + macs.add(MacAddress.fromString("1c:1b:b5:ef:a2:9a")); // NUC 3 + macs.add(MacAddress.fromString("1c:1b:b5:ec:d1:82")); // NUC 4 + + new Thread() { + public void run() { + while(true) { + try { + Thread.sleep(200); + } catch (Exception e) {;} + startRangingOnMacs(macs); + } + } + }.start(); + + + return 1337; + + } + + public static void startRangingOnMacs(final ArrayList macs) { + + Log.d("RTT", "startRangingOnMac()"); + + RangingRequest.Builder builder = new RangingRequest.Builder(); + + for (final MacAddress mac : macs) { + + ScanResult sr = new ScanResult(); + sr.BSSID = mac.toString(); + sr.SSID = "tof_test"; + sr.frequency = 2447; + sr.capabilities = "[ESS]"; + + try { + + Class clazz = Class.forName("android.net.wifi.ScanResult$InformationElement"); + Object[] ies = (Object[]) Array.newInstance(clazz, 1); + + Object ie = clazz.getDeclaredConstructor().newInstance(); + ies[0] = ie; + + Field f1 = sr.getClass().getDeclaredField("flags"); + f1.setAccessible(true); + f1.set(sr, 2); + + Field f2 = sr.getClass().getDeclaredField("informationElements"); + f2.setAccessible(true); + f2.set(sr, ies); + + builder.addAccessPoint(sr); + + } catch (final Exception e) { + e.printStackTrace(); + } + + } + + Log.d("RTT", "startRanging() on " + macs.size()); + if (macs.size() == 0) {return;} + + // fire# + final RangingRequest request = builder.build(); + rttManager.startRanging(request, mainExecutor, callback); + + } + + + public static void startRangingOnScanResult(final List scanResults) { + + Log.d("RTT", "startRangingOnScanResult()"); + + // build the request + int cnt = 0; + RangingRequest.Builder builder = new RangingRequest.Builder(); + for (final ScanResult r : scanResults) { + if (r.is80211mcResponder()) { + Log.d("RTT", "- " + r.BSSID + " [supported]"); + builder.addAccessPoint(r); + ++cnt; + } else { + Log.d("RTT", "- " + r.BSSID + " [NO!]"); + } + } + + Log.d("RTT", "startRanging on " + cnt + " devices"); + if (cnt == 0) {return;} + + // fire + final RangingRequest request = builder.build(); + rttManager.startRanging(request, mainExecutor, callback); + + } + +} diff --git a/_android/src/WiFi.java b/_android/src/WiFi.java new file mode 100644 index 0000000..50ccf3f --- /dev/null +++ b/_android/src/WiFi.java @@ -0,0 +1,181 @@ +package indoor.java; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.os.Debug; +import android.util.Log; +import java.util.List; +import java.io.ByteArrayOutputStream; +import java.lang.reflect.Method; + +import android.os.*; +import java.io.*; +import java.util.Arrays; +import java.lang.StringBuffer; + +public class WiFi { + + private static Activity act; + 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); + + private static String makeString(final byte[] arr) { + StringBuffer output=new StringBuffer(); + for (byte a : arr) { + int val1 = a & 0xff; + output.append(Integer.toHexString(val1)); + output.append(" "); + } + return output.toString(); + } + + public static int start() { + + Log.d("wifi", "start()"); + + MyActivity act = MyActivity.act; + manager = (WifiManager) act.getSystemService(Context.WIFI_SERVICE); + + // reset(); + + WiFi.receiver = new BroadcastReceiver() { + public final void onReceive(final Context context, final Intent intent) { + + Log.d("wifi", "onReceive()"); + + // trigger RTT scan + //RTT.startRangingOnScanResult(manager.getScanResults()); + + // serialze + final byte[] result = serialize(manager.getScanResults()); + + for (final ScanResult sr : manager.getScanResults()) { + + Log.d("wifi", sr.BSSID + " - " + sr.SSID + " " + sr.capabilities + " " + sr.centerFreq0 + " " + sr.centerFreq1 + " " + sr.channelWidth + " " + sr.frequency + " " + sr.level); + +// final ByteArrayOutputStream baos = new ByteArrayOutputStream(); +// final ObjectOutputStream oos = new ObjectOutputStream(baos); +// oos.write(p1); + +// Parcel p = Parcel.obtain(); +// p.writeValue(sr); +// p.setDataPosition(0); +// byte [] b = p.marshall(); +// Log.d("wifi", "" + makeString(b)); + + + + } + + // trigger next scan + //triggerOneScan(); + + // send serialized data to Qt + WiFi.onScanComplete(result); + + } + }; + + // register scan callback + act.registerReceiver(WiFi.receiver, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); + + // start the first scan + triggerOneScan(); + +// //this is a very nice hack. do not try this at home. +// Method m = null; +// try { +// m = manager.getClass().getDeclaredMethod("setFrequencyBand", int.class, boolean.class); +// m.setAccessible(true); +// m.invoke(manager, 2, true); +// m.invoke(manager, 2, true); +// m.invoke(manager, 2, true); +// Log.d("wifi", "HACK IS RUNNING, BIAAAATCH"); +// } catch (Exception e) { +// Log.d("wifi", "HACK HAS FAILED >.<"); +// e.printStackTrace(); +// } + +// // 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; + + } + + private static byte[] serialize(final List lst) { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try { + for (final ScanResult res : lst) { + baos.write(res.BSSID.getBytes()); + baos.write((byte)res.level); + baos.write((byte)0); + baos.write((byte)0); + } + } catch (final Exception e) {;} + return baos.toByteArray(); + } + + + + private static void reset() { + WiFi.manager.disconnect(); + WiFi.manager.createWifiLock(manager.WIFI_MODE_SCAN_ONLY, "Indoor"); + //WiFi.manager.setWifiEnabled(false); + //WiFi.manager.setWifiEnabled(true); + WiFi.manager.disconnect(); + WiFi.manager.disconnect(); + WiFi.manager.disconnect(); + WiFi.manager.disconnect(); + WiFi.manager.disconnect(); + WiFi.manager.disconnect(); + } + + // try to trigger one scan process + private static void triggerOneScan() { + + Log.d("wifi", "triggerOneScan()"); + + try { + if(!manager.startScan()) {throw new RuntimeException("WiFi: can not startScan()");} + lastScanStartTS = System.currentTimeMillis(); + }catch (final Exception e) { + try { + Thread.sleep(1000); + } catch (Exception ex) {;} + Log.e("wifi", "triggerOneScan() failed!!!!!"); + //throw new RuntimeException(e); + } + + } + + +} + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..dcebc85 --- /dev/null +++ b/main.cpp @@ -0,0 +1,32 @@ +#include +#include + +#include + +#include "Manager.h" +extern Manager mgmt; + +int main(int argc, char *argv[]) { + + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + + engine.rootContext()->setContextProperty("mgmt", &mgmt); + + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + + if (engine.rootObjects().isEmpty()) + return -1; + + + + //QAndroidJniObject::callStaticMethod("android/net/wifi/RTT", "start", "()I"); + //QAndroidJniObject::callStaticMethod("indoor/java/WiFi", "start", "()I"); + + return app.exec(); + + +} diff --git a/main.qml b/main.qml new file mode 100644 index 0000000..dbcca1e --- /dev/null +++ b/main.qml @@ -0,0 +1,157 @@ +import QtQuick 2.9 +import QtQuick.Window 2.2 +import QtQuick.Controls 2.4 + +Window { + id: window + + visible: true + width: 640 + height: 680 + title: qsTr("Hello World") + + Column { + id: column + + Label { + text: "dist1: " + ((mgmt.dist1 ? mgmt.dist1+sld1.value : 0)/1000).toFixed(2); + } + + Label { + text: "dist2: " + ((mgmt.dist2 ? mgmt.dist2+sld1.value : 0)/1000).toFixed(2); + } + + Label { + text: "dist3: " + ((mgmt.dist3 ? mgmt.dist3+sld1.value : 0)/1000).toFixed(2); + } + + Label { + text: "dist4: " + ((mgmt.dist4 ? mgmt.dist4+sld1.value : 0)/1000).toFixed(2); + } + + Slider { + width: 400; + id: sld1; + from: -3000; + to: 5000; + onValueChanged: leCanvas.requestPaint(); + } + + Label { + text: "offset: " + sld1.value; + } + + Connections { + target: mgmt + onDistChanged: leCanvas.requestPaint(); + } + + + Button { + text: "party hard"; + onClicked: mgmt.trigger(); + } + + } + + Canvas { + + id: leCanvas; + anchors.right: parent.right + anchors.rightMargin: 0 + anchors.left: parent.left + anchors.leftMargin: 0 + anchors.bottom: parent.bottom + anchors.bottomMargin: 0 + anchors.top: column.bottom + anchors.topMargin: 20 + + readonly property double s: 0.02; + + + function leArc(ctx, cx, cy, dist, stdDev) { + + // center circle + ctx.fillStyle = "#000000"; + ctx.beginPath(); + ctx.arc(cx*s, cy*s, 2, 0, 360); + ctx.fill(); + + // error circle +// ctx.beginPath(); +// ctx.arc(cx*s, cy*s, (dist+sld1.value)*s, 0, 360); +// ctx.closePath(); +// ctx.lineWidth = stdDev*s*0.5; +// ctx.strokeStyle = "#66000000"; +// ctx.stroke(); + + // circle + ctx.lineWidth = 1; + ctx.strokeStyle = "#aa000000"; + ctx.beginPath(); + ctx.arc(cx*s, cy*s, (dist+sld1.value)*s, 0, 360); + ctx.stroke(); + + } + + onPaint: { + var ctx = getContext("2d") + + ctx.reset(); + + ctx.fillStyle = "#dddddd"; + ctx.clearRect(0, 0, leCanvas.width, leCanvas.height); + + //ctx.strokeStyle = Qt.rgba(0, 0, 0, 1) + //ctx.lineWidth = 1 + + var ox = 4000; + var oy = 4000; + + var cx1 = ox+0; + var cy1 = oy+0; + + var cx2 = ox+0; + var cy2 = oy+7250; + + var cx3 = ox+9000; + var cy3 = oy+7250; + + var cx4 = ox+9000; + var cy4 = oy+0; + + leArc(ctx, cx1, cy1, mgmt.dist1, mgmt.stdDev1); + leArc(ctx, cx2, cy2, mgmt.dist2, mgmt.stdDev2); + leArc(ctx, cx3, cy3, mgmt.dist3, mgmt.stdDev3); + leArc(ctx, cx4, cy4, mgmt.dist4, mgmt.stdDev4); + + var sigma = 2000; + var stepSize = 333; + + var maxP = Math.pow( 1.0 / Math.sqrt(2*Math.PI*sigma), 4.1); + + for (var y = 0; y < leCanvas.height/s; y += stepSize) { + for (var x = 0; x < leCanvas.width/s; x += stepSize) { + + var d1 = Math.sqrt( Math.pow(x-cx1, 2) + Math.pow(y-cy1, 2) ) - (mgmt.dist1-sld1.value); + var d2 = Math.sqrt( Math.pow(x-cx2, 2) + Math.pow(y-cy2, 2) ) - (mgmt.dist2-sld1.value); + var d3 = Math.sqrt( Math.pow(x-cx3, 2) + Math.pow(y-cy3, 2) ) - (mgmt.dist3-sld1.value); + var d4 = Math.sqrt( Math.pow(x-cx4, 2) + Math.pow(y-cy4, 2) ) - (mgmt.dist4-sld1.value); + + var p = 1; + p *= 1.0 / Math.sqrt(2*Math.PI*sigma) * Math.exp( - d1*d1/(2*sigma*sigma) ); + p *= 1.0 / Math.sqrt(2*Math.PI*sigma) * Math.exp( - d2*d2/(2*sigma*sigma) ); + p *= 1.0 / Math.sqrt(2*Math.PI*sigma) * Math.exp( - d3*d3/(2*sigma*sigma) ); + p *= 1.0 / Math.sqrt(2*Math.PI*sigma) * Math.exp( - d4*d4/(2*sigma*sigma) ); + + //p = Math.pow(p, 1); + + if (p > maxP / 50) { + ctx.fillStyle = Qt.rgba(1,0,0, p/maxP); + ctx.fillRect(x*s, y*s, stepSize*s, stepSize*s); + } + } + } + } + } +} diff --git a/qml.qrc b/qml.qrc new file mode 100644 index 0000000..5f6483a --- /dev/null +++ b/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + +