aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitreview5
-rw-r--r--LICENSE54
-rw-r--r--README.md43
-rw-r--r--app/app.pri18
-rw-r--r--app/app.pro36
-rw-r--r--app/app.qrc8
-rw-r--r--app/config.tests/libhomescreen/.qmake.stash24
-rw-r--r--app/config.tests/libhomescreen/libhomescreen.cpp8
-rw-r--r--app/config.tests/libhomescreen/libhomescreen.pro5
-rw-r--r--app/config.tests/qlibwindowmanager/.qmake.stash24
-rw-r--r--app/config.tests/qlibwindowmanager/qlibwindowmanager.cpp8
-rw-r--r--app/config.tests/qlibwindowmanager/qlibwindowmanager.pro5
-rw-r--r--app/dbus_client.cpp116
-rw-r--r--app/dbus_client.h46
-rw-r--r--app/file_operation.cpp92
-rw-r--r--app/file_operation.h40
-rw-r--r--app/images/Thumbs.dbbin0 -> 3584 bytes
-rw-r--r--app/images/arrow-0-large.pngbin0 -> 3587 bytes
-rw-r--r--app/images/arrow-l-180-full.pngbin0 -> 21134 bytes
-rw-r--r--app/images/arrow-l-180-large.pngbin0 -> 3982 bytes
-rw-r--r--app/images/arrow-l-30-full.pngbin0 -> 17061 bytes
-rw-r--r--app/images/arrow-l-30-large.pngbin0 -> 3817 bytes
-rw-r--r--app/images/arrow-l-45-full.pngbin0 -> 17970 bytes
-rw-r--r--app/images/arrow-l-45-large.pngbin0 -> 3749 bytes
-rw-r--r--app/images/arrow-l-75-full.pngbin0 -> 22426 bytes
-rw-r--r--app/images/arrow-l-75-large.pngbin0 -> 3970 bytes
-rw-r--r--app/images/arrow-r-180-full.pngbin0 -> 21211 bytes
-rw-r--r--app/images/arrow-r-180-large.pngbin0 -> 3966 bytes
-rw-r--r--app/images/arrow-r-30-full.pngbin0 -> 16478 bytes
-rw-r--r--app/images/arrow-r-30-large.pngbin0 -> 3808 bytes
-rw-r--r--app/images/arrow-r-45-full.pngbin0 -> 17690 bytes
-rw-r--r--app/images/arrow-r-45-large.pngbin0 -> 3763 bytes
-rw-r--r--app/images/arrow-r-75-full.pngbin0 -> 23047 bytes
-rw-r--r--app/images/arrow-r-75-large.pngbin0 -> 4036 bytes
-rw-r--r--app/images/car-marker.pngbin0 -> 6248 bytes
-rw-r--r--app/images/destination.pngbin0 -> 5375 bytes
-rw-r--r--app/images/destination_full.pngbin0 -> 16658 bytes
-rw-r--r--app/images/images.qrc28
-rw-r--r--app/images/marker-end.pngbin0 -> 6199 bytes
-rw-r--r--app/images/marker-green.pngbin0 -> 958 bytes
-rw-r--r--app/images/simple-background-white.pngbin0 -> 4548 bytes
-rw-r--r--app/images/simple-bottom-background-black.pngbin0 -> 4561 bytes
-rw-r--r--app/main.cpp126
-rw-r--r--app/org.agl.naviapi.xml28
-rw-r--r--app/qcheapruler.cpp117
-rw-r--r--app/qcheapruler.hpp57
-rw-r--r--app/qml/Main.qml25
-rw-r--r--app/qml/MapWindow.qml283
-rw-r--r--app/qml/TbtBoard.qml187
-rw-r--r--app/qml/qmldir2
-rw-r--r--include/mapbox/cheap_ruler.hpp358
-rw-r--r--include/mapbox/geometry.hpp13
-rw-r--r--include/mapbox/geometry/box.hpp34
-rw-r--r--include/mapbox/geometry/envelope.hpp33
-rw-r--r--include/mapbox/geometry/feature.hpp81
-rw-r--r--include/mapbox/geometry/for_each_point.hpp45
-rw-r--r--include/mapbox/geometry/geometry.hpp53
-rw-r--r--include/mapbox/geometry/line_string.hpp21
-rw-r--r--include/mapbox/geometry/multi_line_string.hpp21
-rw-r--r--include/mapbox/geometry/multi_point.hpp21
-rw-r--r--include/mapbox/geometry/multi_polygon.hpp21
-rw-r--r--include/mapbox/geometry/point.hpp35
-rw-r--r--include/mapbox/geometry/point_arithmetic.hpp119
-rw-r--r--include/mapbox/geometry/polygon.hpp31
-rw-r--r--include/mapbox/optional.hpp74
-rw-r--r--include/mapbox/recursive_wrapper.hpp122
-rw-r--r--include/mapbox/variant.hpp1013
-rw-r--r--include/mapbox/variant_io.hpp45
-rw-r--r--include/mapbox/variant_visitor.hpp38
-rw-r--r--package/config.xml18
-rw-r--r--package/icon.svg283
-rw-r--r--package/package.pro19
-rw-r--r--tbtnavi.pro3
73 files changed, 3886 insertions, 0 deletions
diff --git a/.gitreview b/.gitreview
new file mode 100644
index 0000000..64f8bad
--- /dev/null
+++ b/.gitreview
@@ -0,0 +1,5 @@
+[gerrit]
+host=gerrit.automotivelinux.org
+port=29418
+project=apps/tbtnavi
+defaultbranch=master
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..31c692a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,54 @@
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+ You must give any other recipients of the Work or Derivative Works a copy of this License; and
+ You must cause any modified files to carry prominent notices stating that You changed the files; and
+ You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+ If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3365abb
--- /dev/null
+++ b/README.md
@@ -0,0 +1,43 @@
+# tbtnavi
+
+#reference
+
+https://doc-snapshots.qt.io/qt5-5.9/qtlocation-mapviewer-example.html
+
+#build step
+
+source /SDK_PATH/environment-setup-aarch64-agl-linux
+
+mkdir build
+
+cd build
+
+qmake ../
+
+make
+
+#configuration
+
+This is the same file for navigation.
+If you have done it during install the navigation,please jump it.
+
+Please set mapAccessToken, mapStyleUrl, speed,
+interval, latitude and longitude in JSON format
+in /etc/naviconfig.ini
+
+mapAccessToken sets Access token provided by Mapbox.
+speed sets vehicle speed in km / h.
+interval sets the screen update interval in milliseconds.
+latitude, longitute sets the current position at application start.
+mapStyleUrls sets Mapbox style URLs.
+
+example
+{
+ "mapAccessToken":"pk.***********",
+ "speed":60,
+ "interval":100,
+ "latitude":36.1363,
+ "longitute":-115.151,
+ "mapStyleUrls":"mapbox://styles/mapbox/dark-v9"
+}
+
diff --git a/app/app.pri b/app/app.pri
new file mode 100644
index 0000000..a1f6562
--- /dev/null
+++ b/app/app.pri
@@ -0,0 +1,18 @@
+load(configure)
+
+qtCompileTest(libhomescreen)
+qtCompileTest(qlibwindowmanager)
+
+config_libhomescreen {
+ CONFIG += link_pkgconfig
+ PKGCONFIG += libhomescreen
+ DEFINES += HAVE_LIBHOMESCREEN
+}
+
+config_qlibwindowmanager {
+ CONFIG += link_pkgconfig
+ PKGCONFIG += qlibwindowmanager
+ DEFINES += HAVE_QLIBWINDOWMANAGER
+}
+
+DESTDIR = $${OUT_PWD}/../package/root/bin
diff --git a/app/app.pro b/app/app.pro
new file mode 100644
index 0000000..594eca3
--- /dev/null
+++ b/app/app.pro
@@ -0,0 +1,36 @@
+TARGET = tbtnavi
+TEMPLATE = app
+
+QT += qml network quick positioning location sql widgets dbus
+
+CONFIG += c++14
+
+include(app.pri)
+
+ios|android {
+ QT -= widgets
+}
+
+SOURCES += \
+ main.cpp \
+ qcheapruler.cpp \
+ dbus_client.cpp \
+ file_operation.cpp
+
+HEADERS += \
+ qcheapruler.hpp \
+ dbus_client.h \
+ file_operation.h
+
+INCLUDEPATH += \
+ ../include
+
+OTHER_FILES += \
+ qmapboxlgapp.qml
+
+RESOURCES += \
+ images/images.qrc \
+ app.qrc
+
+DBUS_ADAPTORS += org.agl.naviapi.xml
+DBUS_INTERFACES += org.agl.naviapi.xml
diff --git a/app/app.qrc b/app/app.qrc
new file mode 100644
index 0000000..7ffb6e2
--- /dev/null
+++ b/app/app.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/qmldir</file>
+ <file>qml/Main.qml</file>
+ <file>qml/MapWindow.qml</file>
+ <file>qml/TbtBoard.qml</file>
+ </qresource>
+</RCC>
diff --git a/app/config.tests/libhomescreen/.qmake.stash b/app/config.tests/libhomescreen/.qmake.stash
new file mode 100644
index 0000000..d0807e7
--- /dev/null
+++ b/app/config.tests/libhomescreen/.qmake.stash
@@ -0,0 +1,24 @@
+QMAKE_CXX.INCDIRS = \
+ /usr/include/c++/5 \
+ /usr/include/x86_64-linux-gnu/c++/5 \
+ /usr/include/c++/5/backward \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include \
+ /usr/local/include \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed \
+ /usr/include/x86_64-linux-gnu \
+ /usr/include
+QMAKE_CXX.LIBDIRS = \
+ /usr/lib/gcc/x86_64-linux-gnu/5 \
+ /usr/lib/x86_64-linux-gnu \
+ /usr/lib \
+ /lib/x86_64-linux-gnu \
+ /lib
+QMAKE_CXX.QT_COMPILER_STDCXX = 199711L
+QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 5
+QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 4
+QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0
+QMAKE_CXX.COMPILER_MACROS = \
+ QT_COMPILER_STDCXX \
+ QMAKE_GCC_MAJOR_VERSION \
+ QMAKE_GCC_MINOR_VERSION \
+ QMAKE_GCC_PATCH_VERSION
diff --git a/app/config.tests/libhomescreen/libhomescreen.cpp b/app/config.tests/libhomescreen/libhomescreen.cpp
new file mode 100644
index 0000000..d698b05
--- /dev/null
+++ b/app/config.tests/libhomescreen/libhomescreen.cpp
@@ -0,0 +1,8 @@
+#include <libhomescreen.hpp>
+
+int main(int argc,char **argv)
+{
+ LibHomeScreen libHomeScreen;
+ return 0;
+}
+
diff --git a/app/config.tests/libhomescreen/libhomescreen.pro b/app/config.tests/libhomescreen/libhomescreen.pro
new file mode 100644
index 0000000..7d43112
--- /dev/null
+++ b/app/config.tests/libhomescreen/libhomescreen.pro
@@ -0,0 +1,5 @@
+SOURCES = libhomescreen.cpp
+
+CONFIG -= qt
+CONFIG += link_pkgconfig
+PKGCONFIG += libhomescreen
diff --git a/app/config.tests/qlibwindowmanager/.qmake.stash b/app/config.tests/qlibwindowmanager/.qmake.stash
new file mode 100644
index 0000000..d0807e7
--- /dev/null
+++ b/app/config.tests/qlibwindowmanager/.qmake.stash
@@ -0,0 +1,24 @@
+QMAKE_CXX.INCDIRS = \
+ /usr/include/c++/5 \
+ /usr/include/x86_64-linux-gnu/c++/5 \
+ /usr/include/c++/5/backward \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include \
+ /usr/local/include \
+ /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed \
+ /usr/include/x86_64-linux-gnu \
+ /usr/include
+QMAKE_CXX.LIBDIRS = \
+ /usr/lib/gcc/x86_64-linux-gnu/5 \
+ /usr/lib/x86_64-linux-gnu \
+ /usr/lib \
+ /lib/x86_64-linux-gnu \
+ /lib
+QMAKE_CXX.QT_COMPILER_STDCXX = 199711L
+QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 5
+QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 4
+QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0
+QMAKE_CXX.COMPILER_MACROS = \
+ QT_COMPILER_STDCXX \
+ QMAKE_GCC_MAJOR_VERSION \
+ QMAKE_GCC_MINOR_VERSION \
+ QMAKE_GCC_PATCH_VERSION
diff --git a/app/config.tests/qlibwindowmanager/qlibwindowmanager.cpp b/app/config.tests/qlibwindowmanager/qlibwindowmanager.cpp
new file mode 100644
index 0000000..bb95c93
--- /dev/null
+++ b/app/config.tests/qlibwindowmanager/qlibwindowmanager.cpp
@@ -0,0 +1,8 @@
+#include <qlibwindowmanager.h>
+
+int main(int argc,char **argv)
+{
+ QLibWindowmanager qwm;
+ return 0;
+}
+
diff --git a/app/config.tests/qlibwindowmanager/qlibwindowmanager.pro b/app/config.tests/qlibwindowmanager/qlibwindowmanager.pro
new file mode 100644
index 0000000..cb51d98
--- /dev/null
+++ b/app/config.tests/qlibwindowmanager/qlibwindowmanager.pro
@@ -0,0 +1,5 @@
+SOURCES = qlibwindowmanager.cpp
+
+CONFIG += qt
+CONFIG += link_pkgconfig
+PKGCONFIG += qlibwindowmanager
diff --git a/app/dbus_client.cpp b/app/dbus_client.cpp
new file mode 100644
index 0000000..6b5b5fb
--- /dev/null
+++ b/app/dbus_client.cpp
@@ -0,0 +1,116 @@
+#include "dbus_client.h"
+
+dbus_client::dbus_client(const QString &pathName,
+ const QString &objName,
+ const QString &serverName,
+ QObject *parent) :
+ m_serverName(serverName),
+ m_pathName(pathName + serverName),
+ m_objName(objName + serverName)
+{
+ //DBus & api ini
+ initDBus();
+ initAPIs(parent);
+}
+
+dbus_client::~dbus_client(){}
+
+void dbus_client::initDBus(){
+
+ new NaviapiAdaptor(this);
+
+ //make a connect session to navigation service(add route info)
+ if (!QDBusConnection::sessionBus().connect(
+ QString(),
+ QString(),
+ m_pathName,
+ "signalRouteInfo",
+ this,
+ SLOT(addRoutePointsSlot(double, double, double, double)))) { //slot
+ qDebug() << m_serverName << "sessionBus.connect(): signalRouteInfo failed";
+ }
+
+ //make a connect session to navigation service(current postion info)
+ if (!QDBusConnection::sessionBus().connect(
+ QString(),
+ QString(),
+ m_pathName,
+ "signalPosInfo",
+ this,
+ SLOT(positionSlot(double, double, double, double)))) { //slot
+ qDebug() << m_serverName << "sessionBus.connect(): signalPosInfo failed";
+ }
+
+ //make a connect session to navigation service(when demo stopped)
+ if (!QDBusConnection::sessionBus().connect(
+ QString(),
+ QString(),
+ m_pathName,
+ "signalStopDemo",
+ this,
+ SLOT(stopdemoSlot()))) { //slot
+ qDebug() << m_serverName << "sessionBus.connect(): signalStopDemo failed";
+ }
+
+ //make a connect session to navigation service(when arrived destination)
+ if (!QDBusConnection::sessionBus().connect(
+ QString(),
+ QString(),
+ m_pathName,
+ "signalArrvied",
+ this,
+ SLOT(arrivedestSlot()))) { //slot
+ qDebug() << m_serverName << "sessionBus.connect(): signalArrvied failed";
+ }
+}
+
+void dbus_client::initAPIs(QObject *parent){
+ //connect the signal to qml inside function(addRoutePointsQml -> do_addRoutePoint)
+ if(!QObject::connect(this, SIGNAL(addRoutePointsQml(QVariant, QVariant, QVariant, QVariant)),
+ parent, SLOT(do_addRoutePoint(QVariant, QVariant, QVariant, QVariant)))) {
+ qDebug() << m_serverName << "SIGNAL:addRoutePointsQml to qmlSLOT:do_addRoutePoint connect is failed";
+ }
+
+ //connect the signal to qml inside function(positionQml -> do_setCoordinate)
+ if(!QObject::connect(this, SIGNAL(positionQml(QVariant, QVariant,QVariant, QVariant)),
+ parent, SLOT(do_setCoordinate(QVariant, QVariant,QVariant, QVariant)))) {
+ qDebug() << m_serverName << "SIGNAL:positionQml to qmlSLOT:do_setCoordinate connect is failed";
+ }
+
+ //connect the signal to qml inside function(stopdemoQml -> do_stopnavidemo)
+ if(!QObject::connect(this, SIGNAL(stopdemoQml()),
+ parent, SLOT(do_stopnavidemo()))) {
+ qDebug() << m_serverName << "SIGNAL:stopdemoQml to qmlSLOT:do_stopnavidemo connect is failed";
+ }
+
+ //connect the signal to qml inside function(arrivedestQml -> do_arrivedest)
+ if(!QObject::connect(this, SIGNAL(arrivedestQml()),
+ parent, SLOT(do_arrivedest()))) {
+ qDebug() << m_serverName << "SIGNAL:arrivedestQml to qmlSLOT:do_arrivedest connect is failed";
+ }
+}
+
+//Signal&&Method
+//addRoutePointsSlot -> addRoutePointsQml(use for qml)
+void dbus_client::addRoutePointsSlot(double route_Lat_s, double route_Lon_s, double route_Lat_e, double route_Lon_e)
+{
+ emit addRoutePointsQml(route_Lat_s, route_Lon_s, route_Lat_e, route_Lon_e);
+}
+
+//positionSlot -> positionQml(use for qml)
+void dbus_client::positionSlot(double cur_Lat_p, double cur_Lon_p,double cur_direction, double cur_distance)
+{
+ emit positionQml(cur_Lat_p, cur_Lon_p,cur_direction,cur_distance);
+}
+
+//stopdemoSlot -> stopdemoQml(use for qml)
+void dbus_client::stopdemoSlot()
+{
+ emit stopdemoQml();
+}
+
+//arrivedestSlot -> arrivedestQml(use for qml)
+void dbus_client::arrivedestSlot()
+{
+ emit arrivedestQml();
+}
diff --git a/app/dbus_client.h b/app/dbus_client.h
new file mode 100644
index 0000000..0abae31
--- /dev/null
+++ b/app/dbus_client.h
@@ -0,0 +1,46 @@
+#ifndef DBUS_CLIENT_H
+#define DBUS_CLIENT_H
+
+#include "naviapi_interface.h"
+#include "naviapi_adaptor.h"
+#include <QtQml/QQmlApplicationEngine>
+
+class dbus_client : public QObject{
+ Q_OBJECT
+ QString m_serverName;
+ QString m_pathName;
+ QString m_objName;
+
+public:
+ dbus_client(const QString &pathName,
+ const QString &objName,
+ const QString &serverName,
+ QObject *parent = nullptr);
+ ~dbus_client();
+
+private:
+ //DBus & API init
+ void initDBus();
+ void initAPIs(QObject*);
+
+signals:
+ //notify add routepoints signal to qml
+ void addRoutePointsQml(QVariant, QVariant, QVariant, QVariant);
+ //notify current position signal to qml
+ void positionQml(QVariant, QVariant,QVariant, QVariant);
+ //notify stop demo signal to qml
+ void stopdemoQml();
+ //notify arrive destination signal to qml
+ void arrivedestQml();
+
+private slots:
+ //receive add routepoints notify from navigation service
+ void addRoutePointsSlot(double route_Lat_s, double route_Lon_s, double route_Lat_e, double route_Lon_e);
+ //receive current position notify from navigation service
+ void positionSlot(double cur_Lat_p, double cur_Lon_p,double cur_direction, double cur_distance);
+ //receive stop demo notify from navigation service
+ void stopdemoSlot();
+ //receive arrive destination notify from navigation service
+ void arrivedestSlot();
+};
+#endif // DBUS_CLIENT_H
diff --git a/app/file_operation.cpp b/app/file_operation.cpp
new file mode 100644
index 0000000..a191c76
--- /dev/null
+++ b/app/file_operation.cpp
@@ -0,0 +1,92 @@
+#include "file_operation.h"
+
+File_Operation::File_Operation(){
+ initFileOperation();
+}
+
+File_Operation::~File_Operation(){
+
+}
+
+void File_Operation::initFileOperation(){
+
+ m_mapAccessToken = "";
+ m_car_speed = 60; // set default Km/h
+ m_update_interval = 100; // set default millisecond
+ m_start_latitude = 35.692396; // set default coordinate Tokyo Hilton
+ m_start_longitute = 139.691102;
+
+ QFile file(NAVI_CONFIG_FILEPATH);
+ if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
+ fprintf(stderr,"Failed to open mapAccessToken file \"%s\": %m", qPrintable(NAVI_CONFIG_FILEPATH));
+ return;
+ }
+
+ QByteArray data = file.readAll();
+ QJsonDocument jsonDoc(QJsonDocument::fromJson(data));
+ QJsonObject jsonObj(jsonDoc.object());
+
+ if(jsonObj.contains("mapAccessToken")){
+ m_mapAccessToken = jsonObj["mapAccessToken"].toString();
+ }else{
+ fprintf(stderr,"Failed to find mapAccessToken data \"%s\": %m", qPrintable(NAVI_CONFIG_FILEPATH));
+ return;
+ }
+ if(jsonObj.contains("mapStyle")){
+ m_mapStyle = jsonObj["mapStyle"].toString();
+ }else{
+ fprintf(stderr,"Failed to find mapStyle data \"%s\": %m", qPrintable(NAVI_CONFIG_FILEPATH));
+ return;
+ }
+
+ if(jsonObj.contains("speed")){
+ m_car_speed = jsonObj["speed"].toDouble();
+ }else{
+ fprintf(stderr,"Failed to find speed data \"%s\": %m", qPrintable(NAVI_CONFIG_FILEPATH));
+ return;
+ }
+
+ if(jsonObj.contains("interval")){
+ m_update_interval = jsonObj["interval"].toInt();
+ }else{
+ fprintf(stderr,"Failed to find interval data \"%s\": %m", qPrintable(NAVI_CONFIG_FILEPATH));
+ return;
+ }
+
+ if(jsonObj.contains("latitude")){
+ m_start_latitude = jsonObj["latitude"].toDouble();
+ }else{
+ fprintf(stderr,"Failed to find latitude data \"%s\": %m", qPrintable(NAVI_CONFIG_FILEPATH));
+ return;
+ }
+
+ if(jsonObj.contains("longitute")){
+ m_start_longitute = jsonObj["longitute"].toDouble();
+ }else{
+ fprintf(stderr,"Failed to find longitute data \"%s\": %m", qPrintable(NAVI_CONFIG_FILEPATH));
+ return;
+ }
+
+ file.close();
+
+ return;
+}
+
+QString File_Operation::getMapAccessToken() {
+ return m_mapAccessToken;
+}
+QString File_Operation::getMapStyle() {
+ return m_mapStyle;
+}
+double File_Operation::getCarSpeed(){
+ return m_car_speed;
+}
+int File_Operation::getUpdateInterval(){
+ return m_update_interval;
+}
+double File_Operation::getStartLatitude(){
+ return m_start_latitude;
+}
+double File_Operation::getStartLongitute(){
+ return m_start_longitute;
+}
diff --git a/app/file_operation.h b/app/file_operation.h
new file mode 100644
index 0000000..65df54a
--- /dev/null
+++ b/app/file_operation.h
@@ -0,0 +1,40 @@
+#ifndef FILE_OPERATION_H
+#define FILE_OPERATION_H
+#include <QObject>
+#include <QString>
+#include <QFile>
+#include <QJsonObject>
+#include <QJsonDocument>
+
+/******************************************************
+ * Write navigation config in /etc/naviconfig.ini
+ ******************************************************/
+#define NAVI_CONFIG_FILEPATH "/etc/naviconfig.ini"
+
+class File_Operation: public QObject{
+
+ Q_OBJECT
+
+ QString m_mapAccessToken;
+ QString m_mapStyle;
+ double m_car_speed; // set Km/h
+ int m_update_interval; // set millisecond
+ double m_start_latitude;
+ double m_start_longitute;
+
+public:
+ File_Operation();
+ ~File_Operation();
+
+ Q_INVOKABLE QString getMapAccessToken();
+ Q_INVOKABLE QString getMapStyle();
+ Q_INVOKABLE double getCarSpeed();
+ Q_INVOKABLE int getUpdateInterval();
+ Q_INVOKABLE double getStartLatitude();
+ Q_INVOKABLE double getStartLongitute();
+
+private:
+ void initFileOperation();
+};
+
+#endif // FILE_OPERATION_H
diff --git a/app/images/Thumbs.db b/app/images/Thumbs.db
new file mode 100644
index 0000000..3ac30c1
--- /dev/null
+++ b/app/images/Thumbs.db
Binary files differ
diff --git a/app/images/arrow-0-large.png b/app/images/arrow-0-large.png
new file mode 100644
index 0000000..124b896
--- /dev/null
+++ b/app/images/arrow-0-large.png
Binary files differ
diff --git a/app/images/arrow-l-180-full.png b/app/images/arrow-l-180-full.png
new file mode 100644
index 0000000..0c71027
--- /dev/null
+++ b/app/images/arrow-l-180-full.png
Binary files differ
diff --git a/app/images/arrow-l-180-large.png b/app/images/arrow-l-180-large.png
new file mode 100644
index 0000000..cb4ff22
--- /dev/null
+++ b/app/images/arrow-l-180-large.png
Binary files differ
diff --git a/app/images/arrow-l-30-full.png b/app/images/arrow-l-30-full.png
new file mode 100644
index 0000000..de799ac
--- /dev/null
+++ b/app/images/arrow-l-30-full.png
Binary files differ
diff --git a/app/images/arrow-l-30-large.png b/app/images/arrow-l-30-large.png
new file mode 100644
index 0000000..b660a71
--- /dev/null
+++ b/app/images/arrow-l-30-large.png
Binary files differ
diff --git a/app/images/arrow-l-45-full.png b/app/images/arrow-l-45-full.png
new file mode 100644
index 0000000..a3d8354
--- /dev/null
+++ b/app/images/arrow-l-45-full.png
Binary files differ
diff --git a/app/images/arrow-l-45-large.png b/app/images/arrow-l-45-large.png
new file mode 100644
index 0000000..6050cf7
--- /dev/null
+++ b/app/images/arrow-l-45-large.png
Binary files differ
diff --git a/app/images/arrow-l-75-full.png b/app/images/arrow-l-75-full.png
new file mode 100644
index 0000000..cd92e2d
--- /dev/null
+++ b/app/images/arrow-l-75-full.png
Binary files differ
diff --git a/app/images/arrow-l-75-large.png b/app/images/arrow-l-75-large.png
new file mode 100644
index 0000000..5edd0b4
--- /dev/null
+++ b/app/images/arrow-l-75-large.png
Binary files differ
diff --git a/app/images/arrow-r-180-full.png b/app/images/arrow-r-180-full.png
new file mode 100644
index 0000000..d761b48
--- /dev/null
+++ b/app/images/arrow-r-180-full.png
Binary files differ
diff --git a/app/images/arrow-r-180-large.png b/app/images/arrow-r-180-large.png
new file mode 100644
index 0000000..22e8c9f
--- /dev/null
+++ b/app/images/arrow-r-180-large.png
Binary files differ
diff --git a/app/images/arrow-r-30-full.png b/app/images/arrow-r-30-full.png
new file mode 100644
index 0000000..0bebfb9
--- /dev/null
+++ b/app/images/arrow-r-30-full.png
Binary files differ
diff --git a/app/images/arrow-r-30-large.png b/app/images/arrow-r-30-large.png
new file mode 100644
index 0000000..47bd445
--- /dev/null
+++ b/app/images/arrow-r-30-large.png
Binary files differ
diff --git a/app/images/arrow-r-45-full.png b/app/images/arrow-r-45-full.png
new file mode 100644
index 0000000..fa170f0
--- /dev/null
+++ b/app/images/arrow-r-45-full.png
Binary files differ
diff --git a/app/images/arrow-r-45-large.png b/app/images/arrow-r-45-large.png
new file mode 100644
index 0000000..b69a9e8
--- /dev/null
+++ b/app/images/arrow-r-45-large.png
Binary files differ
diff --git a/app/images/arrow-r-75-full.png b/app/images/arrow-r-75-full.png
new file mode 100644
index 0000000..08dc143
--- /dev/null
+++ b/app/images/arrow-r-75-full.png
Binary files differ
diff --git a/app/images/arrow-r-75-large.png b/app/images/arrow-r-75-large.png
new file mode 100644
index 0000000..537fd0b
--- /dev/null
+++ b/app/images/arrow-r-75-large.png
Binary files differ
diff --git a/app/images/car-marker.png b/app/images/car-marker.png
new file mode 100644
index 0000000..34bab94
--- /dev/null
+++ b/app/images/car-marker.png
Binary files differ
diff --git a/app/images/destination.png b/app/images/destination.png
new file mode 100644
index 0000000..2d92322
--- /dev/null
+++ b/app/images/destination.png
Binary files differ
diff --git a/app/images/destination_full.png b/app/images/destination_full.png
new file mode 100644
index 0000000..e5c79d9
--- /dev/null
+++ b/app/images/destination_full.png
Binary files differ
diff --git a/app/images/images.qrc b/app/images/images.qrc
new file mode 100644
index 0000000..fc51ad3
--- /dev/null
+++ b/app/images/images.qrc
@@ -0,0 +1,28 @@
+<RCC>
+ <qresource prefix="/">
+ <file>car-marker.png</file>
+ <file>marker-green.png</file>
+ <file>marker-end.png</file>
+ <file>simple-bottom-background-black.png</file>
+ <file>arrow-l-30-full.png</file>
+ <file>arrow-l-45-full.png</file>
+ <file>arrow-l-75-full.png</file>
+ <file>arrow-l-180-full.png</file>
+ <file>arrow-r-30-full.png</file>
+ <file>arrow-r-45-full.png</file>
+ <file>arrow-r-75-full.png</file>
+ <file>arrow-r-180-full.png</file>
+ <file>arrow-0-large.png</file>
+ <file>arrow-l-30-large.png</file>
+ <file>arrow-l-45-large.png</file>
+ <file>arrow-l-75-large.png</file>
+ <file>arrow-l-180-large.png</file>
+ <file>arrow-r-30-large.png</file>
+ <file>arrow-r-45-large.png</file>
+ <file>arrow-r-75-large.png</file>
+ <file>arrow-r-180-large.png</file>
+ <file>simple-background-white.png</file>
+ <file>destination.png</file>
+ <file>destination_full.png</file>
+ </qresource>
+</RCC>
diff --git a/app/images/marker-end.png b/app/images/marker-end.png
new file mode 100644
index 0000000..2763c39
--- /dev/null
+++ b/app/images/marker-end.png
Binary files differ
diff --git a/app/images/marker-green.png b/app/images/marker-green.png
new file mode 100644
index 0000000..e2f2078
--- /dev/null
+++ b/app/images/marker-green.png
Binary files differ
diff --git a/app/images/simple-background-white.png b/app/images/simple-background-white.png
new file mode 100644
index 0000000..df9c2a0
--- /dev/null
+++ b/app/images/simple-background-white.png
Binary files differ
diff --git a/app/images/simple-bottom-background-black.png b/app/images/simple-bottom-background-black.png
new file mode 100644
index 0000000..5c70f5f
--- /dev/null
+++ b/app/images/simple-bottom-background-black.png
Binary files differ
diff --git a/app/main.cpp b/app/main.cpp
new file mode 100644
index 0000000..6194c25
--- /dev/null
+++ b/app/main.cpp
@@ -0,0 +1,126 @@
+#include <QQmlApplicationEngine>
+
+#include <QtCore/QDebug>
+#include <QtCore/QCommandLineParser>
+#include <QtCore/QUrlQuery>
+#include <QtGui/QGuiApplication>
+#include <QtQml/QQmlContext>
+#include <QtQuick/QQuickWindow>
+#include <QtDBus/QDBusConnection>
+
+#include "qcheapruler.hpp"
+#include "dbus_client.h"
+#include "file_operation.h"
+
+#ifdef HAVE_LIBHOMESCREEN
+#include <libhomescreen.hpp>
+#endif
+#ifdef HAVE_QLIBWINDOWMANAGER
+#include <qlibwindowmanager.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+ if (!QDBusConnection::sessionBus().isConnected()) {
+ qWarning("Cannot connect to the D-Bus session bus.\n"
+ "Please check your system settings and try again.\n");
+ return 1;
+ }
+
+ QString myname = QString("tbtnavi");
+
+ QGuiApplication app(argc, argv);
+ app.setApplicationName(myname);
+ app.setApplicationVersion(QStringLiteral("0.1.0"));
+ app.setOrganizationDomain(QStringLiteral("automotivelinux.org"));
+ app.setOrganizationName(QStringLiteral("AutomotiveGradeLinux"));
+
+ QCommandLineParser parser;
+ parser.addPositionalArgument("port", app.translate("main", "port for binding"));
+ parser.addPositionalArgument("secret", app.translate("main", "secret for binding"));
+ parser.addHelpOption();
+ parser.addVersionOption();
+ parser.process(app);
+ QStringList positionalArguments = parser.positionalArguments();
+
+ QQmlApplicationEngine engine;
+ int port = 0;
+ QString secret;
+ if (positionalArguments.length() == 2) {
+ port = positionalArguments.takeFirst().toInt();
+ secret = positionalArguments.takeFirst();
+ }
+
+#ifdef HAVE_QLIBWINDOWMANAGER
+ // WindowManager
+ QLibWindowmanager* qwm = new QLibWindowmanager();
+ if(qwm->init(port,secret) != 0){
+ exit(EXIT_FAILURE);
+ }
+ // Request a surface as described in layers.json windowmanager’s file
+ if(qwm->requestSurface(myname) != 0){
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+#ifdef HAVE_LIBHOMESCREEN
+ // HomeScreen
+ LibHomeScreen* hs = new LibHomeScreen();
+ std::string token = secret.toStdString();
+ hs->init(port, token.c_str());
+ // Set the event handler for Event_TapShortcut which will activate the surface for windowmanager
+ hs->set_event_handler(LibHomeScreen::Event_TapShortcut, [qwm, myname](json_object *object){
+
+ json_object *appnameJ = nullptr;
+ if(json_object_object_get_ex(object, "application_name", &appnameJ))
+ {
+ const char *appname = json_object_get_string(appnameJ);
+ if(QString::compare(myname, appname, Qt::CaseInsensitive) == 0)
+ {
+ qDebug("Surface %s got tapShortcut\n", appname);
+ json_object *para, *area;
+ json_object_object_get_ex(object, "parameter", &para);
+ json_object_object_get_ex(para, "area", &area);
+ const char *displayArea = json_object_get_string(area);
+ qDebug("Surface %s got tapShortcut area\n", displayArea);
+// qwm->activateWindow(myname, QString(QLatin1String(displayArea)));
+ qwm->activateWindow(myname, "master.split.sub");
+ }
+ }
+ });
+#endif
+ qmlRegisterType<QCheapRuler>("com.mapbox.cheap_ruler", 1, 0, "CheapRuler");
+
+ File_Operation file;
+ engine.rootContext()->setContextProperty("fileOperation", &file);
+
+ engine.load(QUrl(QStringLiteral("qrc:qml/Main.qml")));
+
+ QObject *root = engine.rootObjects().first();
+ QQuickWindow *window = qobject_cast<QQuickWindow *>(root);
+
+ //make the DBus connection info
+ QString pathBase = "org.agl.";
+ QString objBase = "/org/agl/";
+ QString serverName = "naviapi";
+ QObject *mapWindow = root->findChild<QObject*>("mapwindow");
+ dbus_client dbus(pathBase, objBase, serverName, mapWindow);
+
+#ifdef HAVE_QLIBWINDOWMANAGER
+// QObject::connect(window, SIGNAL(frameSwapped()), qwm, SLOT(slotActivateSurface()));
+ // Create an event callback against an event type. Here a lambda is called when SyncDraw event occurs
+ qwm->set_event_handler(QLibWindowmanager::Event_SyncDraw, [root, qwm, myname](json_object *object) {
+ fprintf(stderr, "Surface got syncDraw!\n");
+ qwm->endDraw(myname);
+ });
+ // Create an event callback against an event type. Here a lambda is called when SyncDraw event occurs
+ qwm->set_event_handler(QLibWindowmanager::Event_Active, [root](json_object *object) {
+ fprintf(stderr, "Surface got Event_Active!\n");
+ });
+#else
+ window->resize(1024, 768);
+ window->setVisible(true);
+#endif
+
+ return app.exec();
+}
diff --git a/app/org.agl.naviapi.xml b/app/org.agl.naviapi.xml
new file mode 100644
index 0000000..d1538e7
--- /dev/null
+++ b/app/org.agl.naviapi.xml
@@ -0,0 +1,28 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.agl.naviapi">
+ <!-- void signalRouteInfo() -->
+ <signal name="signalRouteInfo">
+ <arg name="start_latitude" type="d" direction="out"/>
+ <arg name="start_longitude" type="d" direction="out"/>
+ <arg name="end_latitude" type="d" direction="out"/>
+ <arg name="end_longitude" type="d" direction="out"/>
+ </signal>
+ <!-- void signalPosInfo() -->
+ <signal name="signalPosInfo">
+ <arg name="latitude" type="d" direction="out"/>
+ <arg name="longitude" type="d" direction="out"/>
+ <arg name="direction" type="d" direction="out"/>
+ <arg name="distance" type="d" direction="out"/>
+ </signal>
+ <!-- void signalStopDemo() -->
+ <signal name="signalStopDemo">
+ </signal>
+ <!-- void signalArrvied() -->
+ <signal name="signalArrvied">
+ </signal>
+ <!-- void getRouteInfo() -->
+ <signal name="getRouteInfo">
+ </signal>
+ </interface>
+</node>
diff --git a/app/qcheapruler.cpp b/app/qcheapruler.cpp
new file mode 100644
index 0000000..890fd63
--- /dev/null
+++ b/app/qcheapruler.cpp
@@ -0,0 +1,117 @@
+#include "qcheapruler.hpp"
+#include "naviapi_adaptor.h"
+
+#include <QString>
+
+QCheapRuler::QCheapRuler()
+{
+ //set the default current position
+ // m_currentPosition = QGeoCoordinate(36.136261, -115.151254);
+ m_currentPosition = QGeoCoordinate(35.692396, 139.691102);
+}
+
+QCheapRuler::~QCheapRuler()
+{
+}
+
+//get route distance
+double QCheapRuler::distance() const
+{
+ return m_distance;
+}
+
+//get current distance along the route
+double QCheapRuler::currentDistance() const
+{
+ return m_currentDistance;
+}
+
+//set current position below the coordinate info from navigation service
+void QCheapRuler::setCurrentPosition(double latitude, double longitude)
+{
+ //set coordinate info and notify the changes when latitude or longitude info has changed
+ if((m_currentPosition.latitude() != latitude)
+ ||(m_currentPosition.longitude() != longitude))
+ {
+ m_currentPosition.setLatitude(latitude);
+ m_currentPosition.setLongitude(longitude);
+ emit currentPositionChanged();
+ }
+}
+
+void QCheapRuler::setCurrentDistance(double distance)
+{
+ //set current distance info and notify the changes when the info has changed
+ //but it will not send notify when it start or stop demo
+ if((m_currentDistance != distance)
+ &&(distance != 0.0))
+ {
+ m_currentDistance = distance;
+ emit currentDistanceChanged();
+ }
+}
+
+//get current position(coordinate)
+QGeoCoordinate QCheapRuler::currentPosition() const
+{
+ return m_currentPosition;
+}
+
+QJSValue QCheapRuler::path() const
+{
+ // Should neveer be called.
+ return QJSValue();
+}
+
+//set route path and get the total distance
+void QCheapRuler::setPath(const QJSValue &value)
+{
+ if (!value.isArray())
+ return;
+
+ m_path.clear();
+ quint32 length = value.property(QStringLiteral("length")).toUInt();
+
+ //push back the coordinate info along the route
+ for (unsigned i = 0; i < length; ++i) {
+ auto property = value.property(i);
+ cr::point coordinate = { 0., 0. };
+
+ if (property.hasProperty(QStringLiteral("latitude")))
+ coordinate.y = property.property(QStringLiteral("latitude")).toNumber();
+
+ if (property.hasProperty(QStringLiteral("longitude")))
+ coordinate.x = property.property(QStringLiteral("longitude")).toNumber();
+
+ m_path.push_back(coordinate);
+ }
+
+ //count the total distance along the route
+ double distance = ruler().lineDistance(m_path);
+ if (m_distance != distance) {
+ m_distance = distance;
+ }
+
+ emit pathChanged();
+}
+
+//init the route and postion info when start in the first time.(can be called by qml)
+void QCheapRuler::initRouteInfo()
+{
+ //send "getRouteInfo" message to the navigation service
+ QDBusMessage message = QDBusMessage::createSignal("/", "org.agl.naviapi", "getRouteInfo");
+ if(!QDBusConnection::sessionBus().send(message))
+ {
+ qDebug() << "initRouteInfo" << "sessionBus.send(): getRouteInfo failed";
+ }
+}
+
+//init the CheapRuler class
+cr::CheapRuler QCheapRuler::ruler() const
+{
+ if (m_path.empty()) {
+ return cr::CheapRuler(0., cr::CheapRuler::Kilometers);
+ } else {
+ return cr::CheapRuler(m_currentPosition.latitude(), cr::CheapRuler::Kilometers);
+ }
+}
diff --git a/app/qcheapruler.hpp b/app/qcheapruler.hpp
new file mode 100644
index 0000000..9e9c664
--- /dev/null
+++ b/app/qcheapruler.hpp
@@ -0,0 +1,57 @@
+#pragma once
+
+#include <QGeoCoordinate>
+#include <QJSValue>
+#include <QObject>
+#include <QtCore>
+
+#include <mapbox/cheap_ruler.hpp> /* BSD3 LICENSE */
+
+namespace cr = mapbox::cheap_ruler;
+
+class QCheapRuler : public QObject{
+ Q_OBJECT
+ //registy the read write&notify function for qml
+ //the distance from start point to end point(read only)
+ Q_PROPERTY(double distance READ distance)
+ //the distance from start point to current postion along the route(read notify)
+ Q_PROPERTY(double currentDistance READ currentDistance NOTIFY currentDistanceChanged)
+ //the coordinate info of current postion(read)
+ Q_PROPERTY(QGeoCoordinate currentPosition READ currentPosition NOTIFY currentPositionChanged)
+ //the route path info postion(read write&notify)
+ Q_PROPERTY(QJSValue path READ path WRITE setPath NOTIFY pathChanged)
+
+public:
+ QCheapRuler();
+ ~QCheapRuler();
+
+ //read write&notify function for qml
+ double distance() const;
+ double currentDistance() const;
+ QGeoCoordinate currentPosition() const;
+ QJSValue path() const;
+ void setPath(const QJSValue &value);
+
+ //functions that can called by qml(Q_INVOKABLE)
+ Q_INVOKABLE void initRouteInfo();
+ Q_INVOKABLE void setCurrentPosition(double, double);
+ Q_INVOKABLE void setCurrentDistance(double);
+
+signals:
+ //notify signals to qml
+ //notify signal when the distance from start point to current postion changed
+ void currentDistanceChanged();
+ //notify signal when currentPosition changed
+ void currentPositionChanged();
+ //notify signal when the distance from start point to current postion changed
+ void pathChanged();
+
+private:
+ cr::CheapRuler ruler() const;
+
+ double m_distance = 0.;
+ double m_currentDistance = 0.;
+ QGeoCoordinate m_currentPosition;
+
+ cr::line_string m_path;
+};
diff --git a/app/qml/Main.qml b/app/qml/Main.qml
new file mode 100644
index 0000000..4139cb9
--- /dev/null
+++ b/app/qml/Main.qml
@@ -0,0 +1,25 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.2
+
+import "qrc:/qml"
+
+ApplicationWindow {
+ id: window
+
+ title: "Turn By Turn Navigation Demo"
+ height: 720
+ width: 640
+ visible: true
+
+ Item {
+ anchors.centerIn: parent
+ width: parent.width
+ height: parent.height
+
+ MapWindow {
+ id:mapwindow
+ anchors.fill: parent
+ objectName: "mapwindow"
+ }
+ }
+}
diff --git a/app/qml/MapWindow.qml b/app/qml/MapWindow.qml
new file mode 100644
index 0000000..8a41390
--- /dev/null
+++ b/app/qml/MapWindow.qml
@@ -0,0 +1,283 @@
+import QtLocation 5.9
+import QtPositioning 5.0
+import QtQuick 2.0
+
+import com.mapbox.cheap_ruler 1.0
+
+Item {
+ id: mapWindow
+
+ property int disOffset: 70
+ property real rotateAngle: 0
+ property var startPoint
+ property var endPoint
+
+ //turn by turn board view
+ TbtBoard {
+ id: tbt_board
+ z: 1
+ visible: false
+ anchors.fill: parent
+ }
+
+ //mapview and route views
+ Map {
+ id: map
+ anchors.fill: parent
+
+ plugin: Plugin {
+ name: "mapboxgl"
+
+ PluginParameter {
+ name: "mapboxgl.mapping.items.insert_before"
+ value: "road-label-small"
+ }
+
+ PluginParameter {
+ name: "mapboxgl.mapping.additional_style_urls"
+ value: "mapbox://styles/mapbox/streets-v9"
+ }
+
+ PluginParameter {
+ name: "mapboxgl.access_token"
+ value: fileOperation.getMapAccessToken()
+ }
+
+ PluginParameter {
+ name: "mapboxgl.mapping.cache.directory"
+ value: "/home/0/app-data/navigation/"
+ }
+ }
+
+ center: ruler.currentPosition
+ zoomLevel: 20
+ tilt: 60
+ gesture.acceptedGestures:MapGestureArea.NoGesture
+ copyrightsVisible: false
+
+ RotationAnimation on bearing {
+ id: bearingAnimation
+
+ duration: 250
+ alwaysRunToEnd: false
+ direction: RotationAnimation.Shortest
+ running: true
+ }
+
+ Location {
+ id: previousLocation
+ coordinate: QtPositioning.coordinate(0, 0);
+ }
+
+ onCenterChanged: {
+ if (previousLocation.coordinate === center)
+ return;
+
+ bearingAnimation.to = previousLocation.coordinate.azimuthTo(center);
+ bearingAnimation.start();
+
+ previousLocation.coordinate = center;
+ }
+
+ MapQuickItem {
+ id: startMarker
+
+ sourceItem: Image {
+ id: greenMarker
+ source: "qrc:///marker-green.png"
+ }
+ anchorPoint.x: greenMarker.width / 2
+ anchorPoint.y: greenMarker.height / 2
+ }
+
+ MapQuickItem {
+ id: endMarker
+
+ sourceItem: Image {
+ id: redMarker
+ source: "qrc:///marker-end.png"
+ }
+ anchorPoint.x: redMarker.width / 2
+ anchorPoint.y: redMarker.height / 2
+ }
+
+ MapItemView {
+ model: routeModel
+
+ delegate: MapRoute {
+ route: routeData
+ line.color: "#6b43a1"
+ line.width: map.zoomLevel - 5
+ opacity: (index == 0) ? 1.0 : 0.3
+
+ onRouteChanged: {
+ ruler.path = routeData.path;
+ }
+ }
+ }
+
+ MapQuickItem {
+ zoomLevel: map.zoomLevel
+
+ sourceItem: Image {
+ id: carMarker
+ source: "qrc:///car-marker.png"
+ transform: Rotation {
+ origin.x: carMarker.width / 2;
+ origin.y: carMarker.height / 2;
+ angle: rotateAngle
+ }
+ }
+
+ coordinate: ruler.currentPosition
+ anchorPoint.x: carMarker.width / 2
+ anchorPoint.y: carMarker.height / 2
+
+ Location {
+ id: previousCarLocation
+ coordinate: QtPositioning.coordinate(0, 0);
+ }
+
+ onCoordinateChanged: {
+ if(coordinate === mapWindow.startPoint)
+ return;
+ rotateAngle = previousCarLocation.coordinate.azimuthTo(coordinate);
+ previousCarLocation.coordinate = coordinate;
+ }
+ }
+
+ //add route view in the map
+ function updateRoute() {
+ routeQuery.clearWaypoints();
+ routeQuery.addWaypoint(startMarker.coordinate);
+ routeQuery.addWaypoint(endMarker.coordinate);
+ map.addMapItem(startMarker)
+ map.addMapItem(endMarker)
+ }
+
+ //clear route view in the map
+ function clearRoute() {
+ routeQuery.clearWaypoints();
+ routeModel.reset();
+ map.removeMapItem(startMarker)
+ map.removeMapItem(endMarker)
+ }
+
+ CheapRuler {
+ id: ruler
+
+ onCurrentDistanceChanged: {
+ var total = 0;
+ var i = 0;
+ var alldistance = ruler.distance * 1000;
+
+ if((routeModel.status === RouteModel.Ready)
+ && (routeModel.count === 1))
+ {
+ // XXX: Use car speed in meters to pre-warn the turn instruction
+ while (total < ruler.currentDistance && i < routeModel.get(0).segments.length)
+ {
+ total += routeModel.get(0).segments[i++].maneuver.distanceToNextInstruction;
+ }
+
+ //show the tbt board(it will be always show when demo start)
+ tbt_board.visible = true
+
+ // Set turn instruction
+ tbt_board.do_setTurnInstructions(routeModel.get(0).segments[i].maneuver.instructionText)
+ tbt_board.state = routeModel.get(0).segments[i].maneuver.direction
+
+ //when goto the last instruction,set the states to "arriveDest"
+ if(i >= (routeModel.get(0).segments.length-1))
+ {
+ total = alldistance;
+ tbt_board.state = "arriveDest";
+ }
+
+ var dis = (total - ruler.currentDistance).toFixed(1);
+
+ // Set distance
+ tbt_board.do_setDistance(dis)
+
+ // Set board status
+ if(dis < mapWindow.disOffset && i < routeModel.get(0).segments.length)
+ {
+ //show the tbt board(the big one)
+ tbt_board.do_showTbtboard(true)
+ }
+ else
+ {
+ //disvisible the tbt board(the big one)
+ tbt_board.do_showTbtboard(false)
+ }
+ }
+ }
+ }
+ }
+
+ //the route view display by RouteModel
+ RouteModel {
+ id: routeModel
+
+ autoUpdate: true
+ query: routeQuery
+
+ plugin: Plugin {
+ name: "mapbox"
+
+ // Development access token, do not use in production.
+ PluginParameter {
+ name: "mapbox.access_token"
+ value: fileOperation.getMapAccessToken()
+ }
+ }
+ }
+
+ RouteQuery {
+ id: routeQuery
+ }
+
+ Component.onCompleted: {
+ //request the route info when map load finish
+ if (ruler) {
+ ruler.initRouteInfo();
+ ruler.setCurrentPosition(fileOperation.getStartLatitude(), fileOperation.getStartLongitute());
+ }
+ }
+
+ //the functions can be called by outside
+ //add route signal function
+ function do_addRoutePoint(poi_Lat_s, poi_Lon_s, poi_Lat_e, poi_Lon_e) {
+ //set the startPoint and endPoint
+ startPoint= QtPositioning.coordinate(poi_Lat_s,poi_Lon_s);
+ endPoint = QtPositioning.coordinate(poi_Lat_e,poi_Lon_e);
+ startMarker.coordinate = startPoint;
+ endMarker.coordinate = endPoint;
+ //update the route view
+ if (map) {
+ map.updateRoute();
+ }
+ }
+
+ //set the current position
+ function do_setCoordinate(latitude,longitude,direction,distance) {
+ ruler.setCurrentPosition(latitude, longitude);
+ ruler.setCurrentDistance(distance);
+ }
+
+ //stop navidemo signal
+ function do_stopnavidemo() {
+ //disvisible the tbt board
+ tbt_board.visible = false
+ //clear the routeview
+ if (map) {
+ map.clearRoute();
+ }
+ }
+
+ //arrvice the destination signal
+ function do_arrivedest(){
+ //disvisible the tbt board
+ tbt_board.visible = false
+ }
+}
diff --git a/app/qml/TbtBoard.qml b/app/qml/TbtBoard.qml
new file mode 100644
index 0000000..cf6f537
--- /dev/null
+++ b/app/qml/TbtBoard.qml
@@ -0,0 +1,187 @@
+import QtQuick 2.0
+
+//turn by turn board view
+Item {
+ id: tbt_board
+
+ property bool showboard: false
+
+ // the backgroud image(the small one)
+ Image {
+ id: whitebackgroud
+ visible: !showboard
+ anchors.top: parent.top
+ width:turnDirection.width
+ height:turnDirection.height + distance.height
+ source: "qrc:simple-background-white.png"
+ z: 1
+ }
+
+ // turn direction arrow board image(the small one)
+ Image {
+ id: turnDirection
+ visible: !showboard
+ anchors.top: parent.top
+ z: 3
+ }
+
+ // the distance to the next crossing road(textview)(the small one)
+ Text {
+ id: distance
+ visible: !showboard
+ anchors.top: turnDirection.bottom
+ z: 3
+ font.pixelSize: 23
+ width:turnDirection.width
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.family: "Lato"
+ font.weight: Font.Light
+ color: "#000000"
+ }
+
+ // the backgroud image
+ Image {
+ id: backgroudBoard
+ visible: showboard
+ anchors.fill: parent
+ source: "qrc:simple-bottom-background-black.png"
+ z: 1
+ }
+
+ // turn direction arrow board image
+ Image {
+ id: turnDirectionBoard
+ visible: showboard
+ width : parent.height - turnInstructionsBoard.height - distanceBoard.height
+ height: parent.height - turnInstructionsBoard.height - distanceBoard.height
+ anchors.centerIn: parent
+ z: 3
+ }
+
+ // the distance to the next crossing road(textview)
+ Text {
+ id: distanceBoard
+ visible: showboard
+ anchors.bottom: turnInstructionsBoard.top
+ z: 3
+ font.pixelSize: 45
+ width:tbt_board.width
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.family: "Lato"
+ font.weight: Font.Light
+ color: "#FFFFFF"
+ }
+
+ // the description of the next crossing road(textview)
+ Text {
+ id: turnInstructionsBoard
+ visible: showboard
+ anchors.bottom: parent.bottom
+ z: 3
+ font.pixelSize: 30
+ width:tbt_board.width
+ wrapMode: Text.Wrap
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.family: "Lato"
+ font.weight: Font.Light
+ color: "#FFFFFF"
+ }
+
+ // the cases of direction arrow board
+ states: [
+ State {
+ name: "arriveDest" //arrive the destination
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:destination_full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:destination.png" }
+ },
+ State {
+ name: "0" // NoDirection
+ PropertyChanges { target: turnDirectionBoard; source: "" }
+ PropertyChanges { target: turnDirection; source: "" }
+ },
+ State {
+ name: "1" // DirectionForward
+ PropertyChanges { target: turnDirectionBoard; source: "" }
+ PropertyChanges { target: turnDirection; source: "" }
+ },
+ State {
+ name: "2" // DirectionBearRight
+ PropertyChanges { target: turnDirectionBoard; source: "" }
+ PropertyChanges { target: turnDirection; source: "" }
+ },
+ State {
+ name: "3" // DirectionLightRight
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:arrow-r-30-full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:arrow-r-30-large.png" }
+ },
+ State {
+ name: "4" // DirectionRight
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:arrow-r-45-full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:arrow-r-45-large.png" }
+ },
+ State {
+ name: "5" // DirectionHardRight
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:arrow-r-75-full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:arrow-r-75-large.png" }
+ },
+ State {
+ name: "6" // DirectionUTurnRight
+ //TODO modify qtlocation U-Turn best.For test, change app source.
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:arrow-l-180-full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:arrow-l-180-large.png" }
+ },
+ State {
+ name: "7" // DirectionUTurnLeft
+ //TODO modify qtlocation U-Turn best.For test, change app source.
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:arrow-r-180-full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:arrow-r-180-large.png" }
+ },
+ State {
+ name: "8" // DirectionHardLeft
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:arrow-l-75-full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:arrow-l-75-large.png" }
+ },
+ State {
+ name: "9" // DirectionLeft
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:arrow-l-45-full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:arrow-l-45-large.png" }
+ },
+ State {
+ name: "10" // DirectionLightLeft
+ PropertyChanges { target: turnDirectionBoard; source: "qrc:arrow-l-30-full.png" }
+ PropertyChanges { target: turnDirection; source: "qrc:arrow-l-30-large.png" }
+ },
+ State {
+ name: "11" // DirectionBearLeft
+ PropertyChanges { target: turnDirectionBoard; source: "" }
+ PropertyChanges { target: turnDirection; source: "" }
+ }
+ ]
+
+ // Set distance
+ function do_setDistance(dis) {
+ if(dis > 1000)
+ {
+ distanceBoard.text = (dis / 1000).toFixed(1) + " km"
+ }
+ else
+ {
+ distanceBoard.text = dis + " m"
+ }
+
+ distance.text = (((dis/100).toFixed(0))*100) +"m"
+ }
+
+ //set turnInstructions
+ function do_setTurnInstructions(turnInstructions) {
+ turnInstructionsBoard.text = turnInstructions
+ }
+
+ //show the tbt board(the big one)
+ function do_showTbtboard(mvisible) {
+ showboard = mvisible
+ }
+}
diff --git a/app/qml/qmldir b/app/qml/qmldir
new file mode 100644
index 0000000..7bbd751
--- /dev/null
+++ b/app/qml/qmldir
@@ -0,0 +1,2 @@
+MapWindow 1.0 MapWindow.qml
+TbtBoard 1.0 TbtBoard.qml
diff --git a/include/mapbox/cheap_ruler.hpp b/include/mapbox/cheap_ruler.hpp
new file mode 100644
index 0000000..ae82706
--- /dev/null
+++ b/include/mapbox/cheap_ruler.hpp
@@ -0,0 +1,358 @@
+#pragma once
+
+#include <mapbox/geometry.hpp>
+
+#include <cmath>
+#include <cstdint>
+#include <limits>
+#include <tuple>
+#include <utility>
+
+namespace mapbox {
+namespace cheap_ruler {
+
+using box = geometry::box<double>;
+using line_string = geometry::line_string<double>;
+using linear_ring = geometry::linear_ring<double>;
+using multi_line_string = geometry::multi_line_string<double>;
+using point = geometry::point<double>;
+using polygon = geometry::polygon<double>;
+
+class CheapRuler {
+public:
+ enum Unit {
+ Kilometers,
+ Miles,
+ NauticalMiles,
+ Meters,
+ Metres = Meters,
+ Yards,
+ Feet,
+ Inches
+ };
+
+ //
+ // A collection of very fast approximations to common geodesic measurements. Useful
+ // for performance-sensitive code that measures things on a city scale. Point coordinates
+ // are in the [x = longitude, y = latitude] form.
+ //
+ explicit CheapRuler(double latitude, Unit unit = Kilometers) {
+ double m = 0.;
+
+ switch (unit) {
+ case Kilometers:
+ m = 1.;
+ break;
+ case Miles:
+ m = 1000. / 1609.344;
+ break;
+ case NauticalMiles:
+ m = 1000. / 1852.;
+ break;
+ case Meters:
+ m = 1000.;
+ break;
+ case Yards:
+ m = 1000. / 0.9144;
+ break;
+ case Feet:
+ m = 1000. / 0.3048;
+ break;
+ case Inches:
+ m = 1000. / 0.0254;
+ break;
+ }
+
+ auto cos = std::cos(latitude * M_PI / 180.);
+ auto cos2 = 2. * cos * cos - 1.;
+ auto cos3 = 2. * cos * cos2 - cos;
+ auto cos4 = 2. * cos * cos3 - cos2;
+ auto cos5 = 2. * cos * cos4 - cos3;
+
+ // multipliers for converting longitude and latitude
+ // degrees into distance (http://1.usa.gov/1Wb1bv7)
+ kx = m * (111.41513 * cos - 0.09455 * cos3 + 0.00012 * cos5);
+ ky = m * (111.13209 - 0.56605 * cos2 + 0.0012 * cos4);
+ }
+
+ static CheapRuler fromTile(uint32_t y, uint32_t z) {
+ double n = M_PI * (1. - 2. * (y + 0.5) / std::pow(2., z));
+ double latitude = std::atan(0.5 * (std::exp(n) - std::exp(-n))) * 180. / M_PI;
+
+ return CheapRuler(latitude);
+ }
+
+ //
+ // Given two points of the form [x = longitude, y = latitude], returns the distance.
+ //
+ double distance(point a, point b) {
+ auto dx = (a.x - b.x) * kx;
+ auto dy = (a.y - b.y) * ky;
+
+ return std::sqrt(dx * dx + dy * dy);
+ }
+
+ //
+ // Returns the bearing between two points in angles.
+ //
+ double bearing(point a, point b) {
+ auto dx = (b.x - a.x) * kx;
+ auto dy = (b.y - a.y) * ky;
+
+ if (!dx && !dy) {
+ return 0.;
+ }
+
+ auto bearing = std::atan2(-dy, dx) * 180. / M_PI + 90.;
+
+ if (bearing > 180.) {
+ bearing -= 360.;
+ }
+
+ return bearing;
+ }
+
+ //
+ // Returns a new point given distance and bearing from the starting point.
+ //
+ point destination(point origin, double dist, double bearing) {
+ auto a = (90. - bearing) * M_PI / 180.;
+
+ return offset(origin, std::cos(a) * dist, std::sin(a) * dist);
+ }
+
+ //
+ // Returns a new point given easting and northing offsets from the starting point.
+ //
+ point offset(point origin, double dx, double dy) {
+ return point(origin.x + dx / kx, origin.y + dy / ky);
+ }
+
+ //
+ // Given a line (an array of points), returns the total line distance.
+ //
+ double lineDistance(const line_string& points) {
+ double total = 0.;
+
+ for (unsigned i = 0; i < points.size() - 1; ++i) {
+ total += distance(points[i], points[i + 1]);
+ }
+
+ return total;
+ }
+
+ //
+ // Given a polygon (an array of rings, where each ring is an array of points),
+ // returns the area.
+ //
+ double area(polygon poly) {
+ double sum = 0.;
+
+ for (unsigned i = 0; i < poly.size(); ++i) {
+ auto& ring = poly[i];
+
+ for (unsigned j = 0, len = ring.size(), k = len - 1; j < len; k = j++) {
+ sum += (ring[j].x - ring[k].x) * (ring[j].y + ring[k].y) * (i ? -1. : 1.);
+ }
+ }
+
+ return (std::abs(sum) / 2.) * kx * ky;
+ }
+
+ //
+ // Returns the point at a specified distance along the line.
+ //
+ point along(const line_string& line, double dist) {
+ double sum = 0.;
+
+ if (dist <= 0.) {
+ return line[0];
+ }
+
+ for (unsigned i = 0; i < line.size() - 1; ++i) {
+ auto p0 = line[i];
+ auto p1 = line[i + 1];
+ auto d = distance(p0, p1);
+
+ sum += d;
+
+ if (sum > dist) {
+ return interpolate(p0, p1, (dist - (sum - d)) / d);
+ }
+ }
+
+ return line[line.size() - 1];
+ }
+
+ //
+ // Returns a pair of the form <point, index> where point is closest point on the line from
+ // the given point and index is the start index of the segment with the closest point.
+ //
+ std::pair<point, unsigned> pointOnLine(const line_string& line, point p) {
+ auto result = _pointOnLine(line, p);
+
+ return std::make_pair(std::get<0>(result), std::get<1>(result));
+ }
+
+ //
+ // Returns a part of the given line between the start and the stop points (or their closest
+ // points on the line).
+ //
+ line_string lineSlice(point start, point stop, const line_string& line) {
+ constexpr auto getPoint = [](auto tuple) { return std::get<0>(tuple); };
+ constexpr auto getIndex = [](auto tuple) { return std::get<1>(tuple); };
+ constexpr auto getT = [](auto tuple) { return std::get<2>(tuple); };
+
+ auto p1 = _pointOnLine(line, start);
+ auto p2 = _pointOnLine(line, stop);
+
+ if (getIndex(p1) > getIndex(p2) || (getIndex(p1) == getIndex(p2) && getT(p1) > getT(p2))) {
+ auto tmp = p1;
+ p1 = p2;
+ p2 = tmp;
+ }
+
+ line_string slice = { getPoint(p1) };
+
+ auto l = getIndex(p1) + 1;
+ auto r = getIndex(p2);
+
+ if (line[l] != slice[0] && l <= r) {
+ slice.push_back(line[l]);
+ }
+
+ for (unsigned i = l + 1; i <= r; ++i) {
+ slice.push_back(line[i]);
+ }
+
+ if (line[r] != getPoint(p2)) {
+ slice.push_back(getPoint(p2));
+ }
+
+ return slice;
+ };
+
+ //
+ // Returns a part of the given line between the start and the stop points
+ // indicated by distance along the line.
+ //
+ line_string lineSliceAlong(double start, double stop, const line_string& line) {
+ double sum = 0.;
+ line_string slice;
+
+ for (unsigned i = 0; i < line.size() - 1; ++i) {
+ auto p0 = line[i];
+ auto p1 = line[i + 1];
+ auto d = distance(p0, p1);
+
+ sum += d;
+
+ if (sum > start && slice.size() == 0) {
+ slice.push_back(interpolate(p0, p1, (start - (sum - d)) / d));
+ }
+
+ if (sum >= stop) {
+ slice.push_back(interpolate(p0, p1, (stop - (sum - d)) / d));
+ return slice;
+ }
+
+ if (sum > start) {
+ slice.push_back(p1);
+ }
+ }
+
+ return slice;
+ };
+
+ //
+ // Given a point, returns a bounding box object ([w, s, e, n])
+ // created from the given point buffered by a given distance.
+ //
+ box bufferPoint(point p, double buffer) {
+ auto v = buffer / ky;
+ auto h = buffer / kx;
+
+ return box(
+ point(p.x - h, p.y - v),
+ point(p.x + h, p.y + v)
+ );
+ }
+
+ //
+ // Given a bounding box, returns the box buffered by a given distance.
+ //
+ box bufferBBox(box bbox, double buffer) {
+ auto v = buffer / ky;
+ auto h = buffer / kx;
+
+ return box(
+ point(bbox.min.x - h, bbox.min.y - v),
+ point(bbox.max.x + h, bbox.max.y + v)
+ );
+ }
+
+ //
+ // Returns true if the given point is inside in the given bounding box, otherwise false.
+ //
+ bool insideBBox(point p, box bbox) {
+ return p.x >= bbox.min.x &&
+ p.x <= bbox.max.x &&
+ p.y >= bbox.min.y &&
+ p.y <= bbox.max.y;
+ }
+
+ static point interpolate(point a, point b, double t) {
+ double dx = b.x - a.x;
+ double dy = b.y - a.y;
+
+ return point(a.x + dx * t, a.y + dy * t);
+ }
+
+private:
+ std::tuple<point, unsigned, double> _pointOnLine(const line_string& line, point p) {
+ double minDist = std::numeric_limits<double>::infinity();
+ double minX = 0., minY = 0., minI = 0., minT = 0.;
+
+ for (unsigned i = 0; i < line.size() - 1; ++i) {
+ auto t = 0.;
+ auto x = line[i].x;
+ auto y = line[i].y;
+ auto dx = (line[i + 1].x - x) * kx;
+ auto dy = (line[i + 1].y - y) * ky;
+
+ if (dx != 0. || dy != 0.) {
+ t = ((p.x - x) * kx * dx + (p.y - y) * ky * dy) / (dx * dx + dy * dy);
+
+ if (t > 1) {
+ x = line[i + 1].x;
+ y = line[i + 1].y;
+
+ } else if (t > 0) {
+ x += (dx / kx) * t;
+ y += (dy / ky) * t;
+ }
+ }
+
+ dx = (p.x - x) * kx;
+ dy = (p.y - y) * ky;
+
+ auto sqDist = dx * dx + dy * dy;
+
+ if (sqDist < minDist) {
+ minDist = sqDist;
+ minX = x;
+ minY = y;
+ minI = i;
+ minT = t;
+ }
+ }
+
+ return std::make_tuple(point(minX, minY), minI, minT);
+ }
+
+ double ky;
+ double kx;
+};
+
+} // namespace cheap_ruler
+} // namespace mapbox
diff --git a/include/mapbox/geometry.hpp b/include/mapbox/geometry.hpp
new file mode 100644
index 0000000..e232453
--- /dev/null
+++ b/include/mapbox/geometry.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <mapbox/geometry/point.hpp>
+#include <mapbox/geometry/line_string.hpp>
+#include <mapbox/geometry/polygon.hpp>
+#include <mapbox/geometry/multi_point.hpp>
+#include <mapbox/geometry/multi_line_string.hpp>
+#include <mapbox/geometry/multi_polygon.hpp>
+#include <mapbox/geometry/geometry.hpp>
+#include <mapbox/geometry/feature.hpp>
+#include <mapbox/geometry/point_arithmetic.hpp>
+#include <mapbox/geometry/for_each_point.hpp>
+#include <mapbox/geometry/envelope.hpp>
diff --git a/include/mapbox/geometry/box.hpp b/include/mapbox/geometry/box.hpp
new file mode 100644
index 0000000..bf81b70
--- /dev/null
+++ b/include/mapbox/geometry/box.hpp
@@ -0,0 +1,34 @@
+#pragma once
+
+#include <mapbox/geometry/point.hpp>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T>
+struct box
+{
+ using point_type = point<T>;
+
+ constexpr box(point_type const& min_, point_type const& max_)
+ : min(min_), max(max_)
+ {}
+
+ point_type min;
+ point_type max;
+};
+
+template <typename T>
+constexpr bool operator==(box<T> const& lhs, box<T> const& rhs)
+{
+ return lhs.min == rhs.min && lhs.max == rhs.max;
+}
+
+template <typename T>
+constexpr bool operator!=(box<T> const& lhs, box<T> const& rhs)
+{
+ return lhs.min != rhs.min || lhs.max != rhs.max;
+}
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/envelope.hpp b/include/mapbox/geometry/envelope.hpp
new file mode 100644
index 0000000..8603583
--- /dev/null
+++ b/include/mapbox/geometry/envelope.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <mapbox/geometry/box.hpp>
+#include <mapbox/geometry/for_each_point.hpp>
+
+#include <limits>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename G, typename T = typename G::coordinate_type>
+box<T> envelope(G const& geometry)
+{
+ using limits = std::numeric_limits<T>;
+
+ T min_t = limits::has_infinity ? -limits::infinity() : limits::min();
+ T max_t = limits::has_infinity ? limits::infinity() : limits::max();
+
+ point<T> min(max_t, max_t);
+ point<T> max(min_t, min_t);
+
+ for_each_point(geometry, [&] (point<T> const& point) {
+ if (min.x > point.x) min.x = point.x;
+ if (min.y > point.y) min.y = point.y;
+ if (max.x < point.x) max.x = point.x;
+ if (max.y < point.y) max.y = point.y;
+ });
+
+ return box<T>(min, max);
+}
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/feature.hpp b/include/mapbox/geometry/feature.hpp
new file mode 100644
index 0000000..3bdd484
--- /dev/null
+++ b/include/mapbox/geometry/feature.hpp
@@ -0,0 +1,81 @@
+#pragma once
+
+#include <mapbox/geometry/geometry.hpp>
+
+#include <mapbox/variant.hpp>
+
+#include <cstdint>
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <experimental/optional>
+
+namespace mapbox {
+namespace geometry {
+
+struct value;
+
+struct null_value_t
+{
+ constexpr null_value_t() {}
+ constexpr null_value_t(std::nullptr_t) {}
+};
+
+constexpr bool operator==(const null_value_t&, const null_value_t&) { return true; }
+constexpr bool operator!=(const null_value_t&, const null_value_t&) { return false; }
+
+constexpr null_value_t null_value = null_value_t();
+
+// Multiple numeric types (uint64_t, int64_t, double) are present in order to support
+// the widest possible range of JSON numbers, which do not have a maximum range.
+// Implementations that produce `value`s should use that order for type preference,
+// using uint64_t for positive integers, int64_t for negative integers, and double
+// for non-integers and integers outside the range of 64 bits.
+using value_base = mapbox::util::variant<null_value_t, bool, uint64_t, int64_t, double, std::string,
+ mapbox::util::recursive_wrapper<std::vector<value>>,
+ mapbox::util::recursive_wrapper<std::unordered_map<std::string, value>>>;
+
+struct value : value_base
+{
+ using value_base::value_base;
+};
+
+using property_map = std::unordered_map<std::string, value>;
+
+// The same considerations and requirement for numeric types apply as for `value_base`.
+using identifier = mapbox::util::variant<uint64_t, int64_t, double, std::string>;
+
+template <class T>
+struct feature
+{
+ using coordinate_type = T;
+ using geometry_type = mapbox::geometry::geometry<T>; // Fully qualified to avoid GCC -fpermissive error.
+
+ geometry_type geometry;
+ property_map properties {};
+ std::experimental::optional<identifier> id {};
+};
+
+template <class T>
+constexpr bool operator==(feature<T> const& lhs, feature<T> const& rhs)
+{
+ return lhs.id == rhs.id && lhs.geometry == rhs.geometry && lhs.properties == rhs.properties;
+}
+
+template <class T>
+constexpr bool operator!=(feature<T> const& lhs, feature<T> const& rhs)
+{
+ return !(lhs == rhs);
+}
+
+template <class T, template <typename...> class Cont = std::vector>
+struct feature_collection : Cont<feature<T>>
+{
+ using coordinate_type = T;
+ using feature_type = feature<T>;
+ using container_type = Cont<feature_type>;
+ using container_type::container_type;
+};
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/for_each_point.hpp b/include/mapbox/geometry/for_each_point.hpp
new file mode 100644
index 0000000..44d6e77
--- /dev/null
+++ b/include/mapbox/geometry/for_each_point.hpp
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <mapbox/geometry/geometry.hpp>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename Point, typename F>
+auto for_each_point(Point&& point, F&& f)
+ -> decltype(point.x, point.y, void())
+{
+ f(std::forward<Point>(point));
+}
+
+template <typename Container, typename F>
+auto for_each_point(Container&& container, F&& f)
+ -> decltype(container.begin(), container.end(), void());
+
+template <typename...Types, typename F>
+void for_each_point(mapbox::util::variant<Types...> const& geom, F&& f)
+{
+ mapbox::util::variant<Types...>::visit(geom, [&] (auto const& g) {
+ for_each_point(g, f);
+ });
+}
+
+template <typename...Types, typename F>
+void for_each_point(mapbox::util::variant<Types...> & geom, F&& f)
+{
+ mapbox::util::variant<Types...>::visit(geom, [&] (auto & g) {
+ for_each_point(g, f);
+ });
+}
+
+template <typename Container, typename F>
+auto for_each_point(Container&& container, F&& f)
+ -> decltype(container.begin(), container.end(), void())
+{
+ for (auto& e: container) {
+ for_each_point(e, f);
+ }
+}
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/geometry.hpp b/include/mapbox/geometry/geometry.hpp
new file mode 100644
index 0000000..a3970bf
--- /dev/null
+++ b/include/mapbox/geometry/geometry.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <mapbox/geometry/point.hpp>
+#include <mapbox/geometry/line_string.hpp>
+#include <mapbox/geometry/polygon.hpp>
+#include <mapbox/geometry/multi_point.hpp>
+#include <mapbox/geometry/multi_line_string.hpp>
+#include <mapbox/geometry/multi_polygon.hpp>
+
+#include <mapbox/variant.hpp>
+
+// stl
+#include <vector>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T, template <typename...> class Cont = std::vector>
+struct geometry_collection;
+
+template <typename T>
+using geometry_base = mapbox::util::variant<point<T>,
+ line_string<T>,
+ polygon<T>,
+ multi_point<T>,
+ multi_line_string<T>,
+ multi_polygon<T>,
+ geometry_collection<T>>;
+
+template <typename T>
+struct geometry : geometry_base<T>
+{
+ using coordinate_type = T;
+ using geometry_base<T>::geometry_base;
+
+ /*
+ * The default constructor would create a point geometry with default-constructed coordinates;
+ * i.e. (0, 0). Since this is not particularly useful, and could hide bugs, it is disabled.
+ */
+ geometry() = delete;
+};
+
+template <typename T, template <typename...> class Cont>
+struct geometry_collection : Cont<geometry<T>>
+{
+ using coordinate_type = T;
+ using geometry_type = geometry<T>;
+ using container_type = Cont<geometry_type>;
+ using container_type::container_type;
+};
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/line_string.hpp b/include/mapbox/geometry/line_string.hpp
new file mode 100644
index 0000000..6d811ce
--- /dev/null
+++ b/include/mapbox/geometry/line_string.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+// mapbox
+#include <mapbox/geometry/point.hpp>
+// stl
+#include <vector>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T, template <typename...> class Cont = std::vector>
+struct line_string : Cont<point<T> >
+{
+ using coordinate_type = T;
+ using point_type = point<T>;
+ using container_type = Cont<point_type>;
+ using container_type::container_type;
+};
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/multi_line_string.hpp b/include/mapbox/geometry/multi_line_string.hpp
new file mode 100644
index 0000000..07a7a1d
--- /dev/null
+++ b/include/mapbox/geometry/multi_line_string.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+// mapbox
+#include <mapbox/geometry/line_string.hpp>
+// stl
+#include <vector>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T, template <typename...> class Cont = std::vector>
+struct multi_line_string : Cont<line_string<T>>
+{
+ using coordinate_type = T;
+ using line_string_type = line_string<T>;
+ using container_type = Cont<line_string_type>;
+ using container_type::container_type;
+};
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/multi_point.hpp b/include/mapbox/geometry/multi_point.hpp
new file mode 100644
index 0000000..a3c73cf
--- /dev/null
+++ b/include/mapbox/geometry/multi_point.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+// mapbox
+#include <mapbox/geometry/point.hpp>
+// stl
+#include <vector>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T, template <typename...> class Cont = std::vector>
+struct multi_point : Cont<point<T>>
+{
+ using coordinate_type = T;
+ using point_type = point<T>;
+ using container_type = Cont<point_type>;
+ using container_type::container_type;
+};
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/multi_polygon.hpp b/include/mapbox/geometry/multi_polygon.hpp
new file mode 100644
index 0000000..ad230a0
--- /dev/null
+++ b/include/mapbox/geometry/multi_polygon.hpp
@@ -0,0 +1,21 @@
+#pragma once
+
+// mapbox
+#include <mapbox/geometry/polygon.hpp>
+// stl
+#include <vector>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T, template <typename...> class Cont = std::vector>
+struct multi_polygon : Cont<polygon<T>>
+{
+ using coordinate_type = T;
+ using polygon_type = polygon<T>;
+ using container_type = Cont<polygon_type>;
+ using container_type::container_type;
+};
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/point.hpp b/include/mapbox/geometry/point.hpp
new file mode 100644
index 0000000..0cba499
--- /dev/null
+++ b/include/mapbox/geometry/point.hpp
@@ -0,0 +1,35 @@
+#pragma once
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T>
+struct point
+{
+ using coordinate_type = T;
+
+ constexpr point()
+ : x(), y()
+ {}
+ constexpr point(T x_, T y_)
+ : x(x_), y(y_)
+ {}
+
+ T x;
+ T y;
+};
+
+template <typename T>
+constexpr bool operator==(point<T> const& lhs, point<T> const& rhs)
+{
+ return lhs.x == rhs.x && lhs.y == rhs.y;
+}
+
+template <typename T>
+constexpr bool operator!=(point<T> const& lhs, point<T> const& rhs)
+{
+ return !(lhs == rhs);
+}
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/point_arithmetic.hpp b/include/mapbox/geometry/point_arithmetic.hpp
new file mode 100644
index 0000000..3940e5b
--- /dev/null
+++ b/include/mapbox/geometry/point_arithmetic.hpp
@@ -0,0 +1,119 @@
+#pragma once
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T>
+constexpr point<T> operator+(point<T> const& lhs, point<T> const& rhs)
+{
+ return point<T>(lhs.x + rhs.x, lhs.y + rhs.y);
+}
+
+template <typename T>
+constexpr point<T> operator+(point<T> const& lhs, T const& rhs)
+{
+ return point<T>(lhs.x + rhs, lhs.y + rhs);
+}
+
+template <typename T>
+constexpr point<T> operator-(point<T> const& lhs, point<T> const& rhs)
+{
+ return point<T>(lhs.x - rhs.x, lhs.y - rhs.y);
+}
+
+template <typename T>
+constexpr point<T> operator-(point<T> const& lhs, T const& rhs)
+{
+ return point<T>(lhs.x - rhs, lhs.y - rhs);
+}
+
+template <typename T>
+constexpr point<T> operator*(point<T> const& lhs, point<T> const& rhs)
+{
+ return point<T>(lhs.x * rhs.x, lhs.y * rhs.y);
+}
+
+template <typename T>
+constexpr point<T> operator*(point<T> const& lhs, T const& rhs)
+{
+ return point<T>(lhs.x * rhs, lhs.y * rhs);
+}
+
+template <typename T>
+constexpr point<T> operator/(point<T> const& lhs, point<T> const& rhs)
+{
+ return point<T>(lhs.x / rhs.x, lhs.y / rhs.y);
+}
+
+template <typename T>
+constexpr point<T> operator/(point<T> const& lhs, T const& rhs)
+{
+ return point<T>(lhs.x / rhs, lhs.y / rhs);
+}
+
+template <typename T>
+constexpr point<T>& operator+=(point<T>& lhs, point<T> const& rhs)
+{
+ lhs.x += rhs.x;
+ lhs.y += rhs.y;
+ return lhs;
+}
+
+template <typename T>
+constexpr point<T>& operator+=(point<T>& lhs, T const& rhs)
+{
+ lhs.x += rhs;
+ lhs.y += rhs;
+ return lhs;
+}
+
+template <typename T>
+constexpr point<T>& operator-=(point<T>& lhs, point<T> const& rhs)
+{
+ lhs.x -= rhs.x;
+ lhs.y -= rhs.y;
+ return lhs;
+}
+
+template <typename T>
+constexpr point<T>& operator-=(point<T>& lhs, T const& rhs)
+{
+ lhs.x -= rhs;
+ lhs.y -= rhs;
+ return lhs;
+}
+
+template <typename T>
+constexpr point<T>& operator*=(point<T>& lhs, point<T> const& rhs)
+{
+ lhs.x *= rhs.x;
+ lhs.y *= rhs.y;
+ return lhs;
+}
+
+template <typename T>
+constexpr point<T>& operator*=(point<T>& lhs, T const& rhs)
+{
+ lhs.x *= rhs;
+ lhs.y *= rhs;
+ return lhs;
+}
+
+template <typename T>
+constexpr point<T>& operator/=(point<T>& lhs, point<T> const& rhs)
+{
+ lhs.x /= rhs.x;
+ lhs.y /= rhs.y;
+ return lhs;
+}
+
+template <typename T>
+constexpr point<T>& operator/=(point<T>& lhs, T const& rhs)
+{
+ lhs.x /= rhs;
+ lhs.y /= rhs;
+ return lhs;
+}
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/geometry/polygon.hpp b/include/mapbox/geometry/polygon.hpp
new file mode 100644
index 0000000..99a66aa
--- /dev/null
+++ b/include/mapbox/geometry/polygon.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+// mapbox
+#include <mapbox/geometry/point.hpp>
+
+// stl
+#include <vector>
+
+namespace mapbox {
+namespace geometry {
+
+template <typename T, template <typename...> class Cont = std::vector>
+struct linear_ring : Cont<point<T>>
+{
+ using coordinate_type = T;
+ using point_type = point<T>;
+ using container_type = Cont<point_type>;
+ using container_type::container_type;
+};
+
+template <typename T, template <typename...> class Cont = std::vector>
+struct polygon : Cont<linear_ring<T>>
+{
+ using coordinate_type = T;
+ using linear_ring_type = linear_ring<T>;
+ using container_type = Cont<linear_ring_type>;
+ using container_type::container_type;
+};
+
+} // namespace geometry
+} // namespace mapbox
diff --git a/include/mapbox/optional.hpp b/include/mapbox/optional.hpp
new file mode 100644
index 0000000..d84705c
--- /dev/null
+++ b/include/mapbox/optional.hpp
@@ -0,0 +1,74 @@
+#ifndef MAPBOX_UTIL_OPTIONAL_HPP
+#define MAPBOX_UTIL_OPTIONAL_HPP
+
+#pragma message("This implementation of optional is deprecated. See https://github.com/mapbox/variant/issues/64.")
+
+#include <type_traits>
+#include <utility>
+
+#include <mapbox/variant.hpp>
+
+namespace mapbox {
+namespace util {
+
+template <typename T>
+class optional
+{
+ static_assert(!std::is_reference<T>::value, "optional doesn't support references");
+
+ struct none_type
+ {
+ };
+
+ variant<none_type, T> variant_;
+
+public:
+ optional() = default;
+
+ optional(optional const& rhs)
+ {
+ if (this != &rhs)
+ { // protect against invalid self-assignment
+ variant_ = rhs.variant_;
+ }
+ }
+
+ optional(T const& v) { variant_ = v; }
+
+ explicit operator bool() const noexcept { return variant_.template is<T>(); }
+
+ T const& get() const { return variant_.template get<T>(); }
+ T& get() { return variant_.template get<T>(); }
+
+ T const& operator*() const { return this->get(); }
+ T operator*() { return this->get(); }
+
+ optional& operator=(T const& v)
+ {
+ variant_ = v;
+ return *this;
+ }
+
+ optional& operator=(optional const& rhs)
+ {
+ if (this != &rhs)
+ {
+ variant_ = rhs.variant_;
+ }
+ return *this;
+ }
+
+ template <typename... Args>
+ void emplace(Args&&... args)
+ {
+ variant_ = T{std::forward<Args>(args)...};
+ }
+
+ void reset() { variant_ = none_type{}; }
+
+}; // class optional
+
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_OPTIONAL_HPP
diff --git a/include/mapbox/recursive_wrapper.hpp b/include/mapbox/recursive_wrapper.hpp
new file mode 100644
index 0000000..4ffcbd7
--- /dev/null
+++ b/include/mapbox/recursive_wrapper.hpp
@@ -0,0 +1,122 @@
+#ifndef MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
+#define MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
+
+// Based on variant/recursive_wrapper.hpp from boost.
+//
+// Original license:
+//
+// Copyright (c) 2002-2003
+// Eric Friedman, Itay Maman
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <cassert>
+#include <utility>
+
+namespace mapbox {
+namespace util {
+
+template <typename T>
+class recursive_wrapper
+{
+
+ T* p_;
+
+ void assign(T const& rhs)
+ {
+ this->get() = rhs;
+ }
+
+public:
+ using type = T;
+
+ /**
+ * Default constructor default initializes the internally stored value.
+ * For POD types this means nothing is done and the storage is
+ * uninitialized.
+ *
+ * @throws std::bad_alloc if there is insufficient memory for an object
+ * of type T.
+ * @throws any exception thrown by the default constructur of T.
+ */
+ recursive_wrapper()
+ : p_(new T){}
+
+ ~recursive_wrapper() noexcept { delete p_; }
+
+ recursive_wrapper(recursive_wrapper const& operand)
+ : p_(new T(operand.get())) {}
+
+ recursive_wrapper(T const& operand)
+ : p_(new T(operand)) {}
+
+ recursive_wrapper(recursive_wrapper&& operand)
+ : p_(new T(std::move(operand.get()))) {}
+
+ recursive_wrapper(T&& operand)
+ : p_(new T(std::move(operand))) {}
+
+ inline recursive_wrapper& operator=(recursive_wrapper const& rhs)
+ {
+ assign(rhs.get());
+ return *this;
+ }
+
+ inline recursive_wrapper& operator=(T const& rhs)
+ {
+ assign(rhs);
+ return *this;
+ }
+
+ inline void swap(recursive_wrapper& operand) noexcept
+ {
+ T* temp = operand.p_;
+ operand.p_ = p_;
+ p_ = temp;
+ }
+
+ recursive_wrapper& operator=(recursive_wrapper&& rhs) noexcept
+ {
+ swap(rhs);
+ return *this;
+ }
+
+ recursive_wrapper& operator=(T&& rhs)
+ {
+ get() = std::move(rhs);
+ return *this;
+ }
+
+ T& get()
+ {
+ assert(p_);
+ return *get_pointer();
+ }
+
+ T const& get() const
+ {
+ assert(p_);
+ return *get_pointer();
+ }
+
+ T* get_pointer() { return p_; }
+
+ const T* get_pointer() const { return p_; }
+
+ operator T const&() const { return this->get(); }
+
+ operator T&() { return this->get(); }
+
+}; // class recursive_wrapper
+
+template <typename T>
+inline void swap(recursive_wrapper<T>& lhs, recursive_wrapper<T>& rhs) noexcept
+{
+ lhs.swap(rhs);
+}
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_RECURSIVE_WRAPPER_HPP
diff --git a/include/mapbox/variant.hpp b/include/mapbox/variant.hpp
new file mode 100644
index 0000000..fb0f77e
--- /dev/null
+++ b/include/mapbox/variant.hpp
@@ -0,0 +1,1013 @@
+#ifndef MAPBOX_UTIL_VARIANT_HPP
+#define MAPBOX_UTIL_VARIANT_HPP
+
+#include <cassert>
+#include <cstddef> // size_t
+#include <new> // operator new
+#include <stdexcept> // runtime_error
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+#include <functional>
+
+#include <mapbox/recursive_wrapper.hpp>
+#include <mapbox/variant_visitor.hpp>
+
+// clang-format off
+// [[deprecated]] is only available in C++14, use this for the time being
+#if __cplusplus <= 201103L
+# ifdef __GNUC__
+# define MAPBOX_VARIANT_DEPRECATED __attribute__((deprecated))
+# elif defined(_MSC_VER)
+# define MAPBOX_VARIANT_DEPRECATED __declspec(deprecated)
+# else
+# define MAPBOX_VARIANT_DEPRECATED
+# endif
+#else
+# define MAPBOX_VARIANT_DEPRECATED [[deprecated]]
+#endif
+
+
+#ifdef _MSC_VER
+// https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx
+# ifdef NDEBUG
+# define VARIANT_INLINE __forceinline
+# else
+# define VARIANT_INLINE //__declspec(noinline)
+# endif
+#else
+# ifdef NDEBUG
+# define VARIANT_INLINE //inline __attribute__((always_inline))
+# else
+# define VARIANT_INLINE __attribute__((noinline))
+# endif
+#endif
+// clang-format on
+
+// Exceptions
+#if defined( __EXCEPTIONS) || defined( _MSC_VER)
+#define HAS_EXCEPTIONS
+#endif
+
+#define VARIANT_MAJOR_VERSION 1
+#define VARIANT_MINOR_VERSION 1
+#define VARIANT_PATCH_VERSION 0
+
+#define VARIANT_VERSION (VARIANT_MAJOR_VERSION * 100000) + (VARIANT_MINOR_VERSION * 100) + (VARIANT_PATCH_VERSION)
+
+namespace mapbox {
+namespace util {
+
+// XXX This should derive from std::logic_error instead of std::runtime_error.
+// See https://github.com/mapbox/variant/issues/48 for details.
+class bad_variant_access : public std::runtime_error
+{
+
+public:
+ explicit bad_variant_access(const std::string& what_arg)
+ : runtime_error(what_arg) {}
+
+ explicit bad_variant_access(const char* what_arg)
+ : runtime_error(what_arg) {}
+
+}; // class bad_variant_access
+
+template <typename R = void>
+struct MAPBOX_VARIANT_DEPRECATED static_visitor
+{
+ using result_type = R;
+
+protected:
+ static_visitor() {}
+ ~static_visitor() {}
+};
+
+namespace detail {
+
+static constexpr std::size_t invalid_value = std::size_t(-1);
+
+template <typename T, typename... Types>
+struct direct_type;
+
+template <typename T, typename First, typename... Types>
+struct direct_type<T, First, Types...>
+{
+ static constexpr std::size_t index = std::is_same<T, First>::value
+ ? sizeof...(Types)
+ : direct_type<T, Types...>::index;
+};
+
+template <typename T>
+struct direct_type<T>
+{
+ static constexpr std::size_t index = invalid_value;
+};
+
+#if __cpp_lib_logical_traits >= 201510L
+
+using std::disjunction;
+
+#else
+
+template <typename...>
+struct disjunction : std::false_type {};
+
+template <typename B1>
+struct disjunction<B1> : B1 {};
+
+template <typename B1, typename B2>
+struct disjunction<B1, B2> : std::conditional<B1::value, B1, B2>::type {};
+
+template <typename B1, typename... Bs>
+struct disjunction<B1, Bs...> : std::conditional<B1::value, B1, disjunction<Bs...>>::type {};
+
+#endif
+
+template <typename T, typename... Types>
+struct convertible_type;
+
+template <typename T, typename First, typename... Types>
+struct convertible_type<T, First, Types...>
+{
+ static constexpr std::size_t index = std::is_convertible<T, First>::value
+ ? disjunction<std::is_convertible<T, Types>...>::value ? invalid_value : sizeof...(Types)
+ : convertible_type<T, Types...>::index;
+};
+
+template <typename T>
+struct convertible_type<T>
+{
+ static constexpr std::size_t index = invalid_value;
+};
+
+template <typename T, typename... Types>
+struct value_traits
+{
+ using value_type = typename std::remove_const<typename std::remove_reference<T>::type>::type;
+ static constexpr std::size_t direct_index = direct_type<value_type, Types...>::index;
+ static constexpr bool is_direct = direct_index != invalid_value;
+ static constexpr std::size_t index = is_direct ? direct_index : convertible_type<value_type, Types...>::index;
+ static constexpr bool is_valid = index != invalid_value;
+ static constexpr std::size_t tindex = is_valid ? sizeof...(Types)-index : 0;
+ using target_type = typename std::tuple_element<tindex, std::tuple<void, Types...>>::type;
+};
+
+template <typename T, typename R = void>
+struct enable_if_type
+{
+ using type = R;
+};
+
+template <typename F, typename V, typename Enable = void>
+struct result_of_unary_visit
+{
+ using type = typename std::result_of<F(V&)>::type;
+};
+
+template <typename F, typename V>
+struct result_of_unary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
+{
+ using type = typename F::result_type;
+};
+
+template <typename F, typename V, typename Enable = void>
+struct result_of_binary_visit
+{
+ using type = typename std::result_of<F(V&, V&)>::type;
+};
+
+template <typename F, typename V>
+struct result_of_binary_visit<F, V, typename enable_if_type<typename F::result_type>::type>
+{
+ using type = typename F::result_type;
+};
+
+template <std::size_t arg1, std::size_t... others>
+struct static_max;
+
+template <std::size_t arg>
+struct static_max<arg>
+{
+ static const std::size_t value = arg;
+};
+
+template <std::size_t arg1, std::size_t arg2, std::size_t... others>
+struct static_max<arg1, arg2, others...>
+{
+ static const std::size_t value = arg1 >= arg2 ? static_max<arg1, others...>::value : static_max<arg2, others...>::value;
+};
+
+template <typename... Types>
+struct variant_helper;
+
+template <typename T, typename... Types>
+struct variant_helper<T, Types...>
+{
+ VARIANT_INLINE static void destroy(const std::size_t type_index, void* data)
+ {
+ if (type_index == sizeof...(Types))
+ {
+ reinterpret_cast<T*>(data)->~T();
+ }
+ else
+ {
+ variant_helper<Types...>::destroy(type_index, data);
+ }
+ }
+
+ VARIANT_INLINE static void move(const std::size_t old_type_index, void* old_value, void* new_value)
+ {
+ if (old_type_index == sizeof...(Types))
+ {
+ new (new_value) T(std::move(*reinterpret_cast<T*>(old_value)));
+ }
+ else
+ {
+ variant_helper<Types...>::move(old_type_index, old_value, new_value);
+ }
+ }
+
+ VARIANT_INLINE static void copy(const std::size_t old_type_index, const void* old_value, void* new_value)
+ {
+ if (old_type_index == sizeof...(Types))
+ {
+ new (new_value) T(*reinterpret_cast<const T*>(old_value));
+ }
+ else
+ {
+ variant_helper<Types...>::copy(old_type_index, old_value, new_value);
+ }
+ }
+};
+
+template <>
+struct variant_helper<>
+{
+ VARIANT_INLINE static void destroy(const std::size_t, void*) {}
+ VARIANT_INLINE static void move(const std::size_t, void*, void*) {}
+ VARIANT_INLINE static void copy(const std::size_t, const void*, void*) {}
+};
+
+template <typename T>
+struct unwrapper
+{
+ static T const& apply_const(T const& obj) { return obj; }
+ static T& apply(T& obj) { return obj; }
+};
+
+template <typename T>
+struct unwrapper<recursive_wrapper<T>>
+{
+ static auto apply_const(recursive_wrapper<T> const& obj)
+ -> typename recursive_wrapper<T>::type const&
+ {
+ return obj.get();
+ }
+ static auto apply(recursive_wrapper<T>& obj)
+ -> typename recursive_wrapper<T>::type&
+ {
+ return obj.get();
+ }
+};
+
+template <typename T>
+struct unwrapper<std::reference_wrapper<T>>
+{
+ static auto apply_const(std::reference_wrapper<T> const& obj)
+ -> typename std::reference_wrapper<T>::type const&
+ {
+ return obj.get();
+ }
+ static auto apply(std::reference_wrapper<T>& obj)
+ -> typename std::reference_wrapper<T>::type&
+ {
+ return obj.get();
+ }
+};
+
+template <typename F, typename V, typename R, typename... Types>
+struct dispatcher;
+
+template <typename F, typename V, typename R, typename T, typename... Types>
+struct dispatcher<F, V, R, T, Types...>
+{
+ VARIANT_INLINE static R apply_const(V const& v, F&& f)
+ {
+ if (v.template is<T>())
+ {
+ return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
+ }
+ else
+ {
+ return dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
+ }
+ }
+
+ VARIANT_INLINE static R apply(V& v, F&& f)
+ {
+ if (v.template is<T>())
+ {
+ return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
+ }
+ else
+ {
+ return dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
+ }
+ }
+};
+
+template <typename F, typename V, typename R, typename T>
+struct dispatcher<F, V, R, T>
+{
+ VARIANT_INLINE static R apply_const(V const& v, F&& f)
+ {
+ return f(unwrapper<T>::apply_const(v.template get_unchecked<T>()));
+ }
+
+ VARIANT_INLINE static R apply(V& v, F&& f)
+ {
+ return f(unwrapper<T>::apply(v.template get_unchecked<T>()));
+ }
+};
+
+template <typename F, typename V, typename R, typename T, typename... Types>
+struct binary_dispatcher_rhs;
+
+template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
+struct binary_dispatcher_rhs<F, V, R, T0, T1, Types...>
+{
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+ {
+ if (rhs.template is<T1>()) // call binary functor
+ {
+ return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
+ unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
+ }
+ }
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+ {
+ if (rhs.template is<T1>()) // call binary functor
+ {
+ return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
+ unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
+ }
+ }
+};
+
+template <typename F, typename V, typename R, typename T0, typename T1>
+struct binary_dispatcher_rhs<F, V, R, T0, T1>
+{
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+ {
+ return f(unwrapper<T0>::apply_const(lhs.template get_unchecked<T0>()),
+ unwrapper<T1>::apply_const(rhs.template get_unchecked<T1>()));
+ }
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+ {
+ return f(unwrapper<T0>::apply(lhs.template get_unchecked<T0>()),
+ unwrapper<T1>::apply(rhs.template get_unchecked<T1>()));
+ }
+};
+
+template <typename F, typename V, typename R, typename T, typename... Types>
+struct binary_dispatcher_lhs;
+
+template <typename F, typename V, typename R, typename T0, typename T1, typename... Types>
+struct binary_dispatcher_lhs<F, V, R, T0, T1, Types...>
+{
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+ {
+ if (lhs.template is<T1>()) // call binary functor
+ {
+ return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
+ unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
+ }
+ else
+ {
+ return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply_const(lhs, rhs, std::forward<F>(f));
+ }
+ }
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+ {
+ if (lhs.template is<T1>()) // call binary functor
+ {
+ return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
+ unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
+ }
+ else
+ {
+ return binary_dispatcher_lhs<F, V, R, T0, Types...>::apply(lhs, rhs, std::forward<F>(f));
+ }
+ }
+};
+
+template <typename F, typename V, typename R, typename T0, typename T1>
+struct binary_dispatcher_lhs<F, V, R, T0, T1>
+{
+ VARIANT_INLINE static R apply_const(V const& lhs, V const& rhs, F&& f)
+ {
+ return f(unwrapper<T1>::apply_const(lhs.template get_unchecked<T1>()),
+ unwrapper<T0>::apply_const(rhs.template get_unchecked<T0>()));
+ }
+
+ VARIANT_INLINE static R apply(V& lhs, V& rhs, F&& f)
+ {
+ return f(unwrapper<T1>::apply(lhs.template get_unchecked<T1>()),
+ unwrapper<T0>::apply(rhs.template get_unchecked<T0>()));
+ }
+};
+
+template <typename F, typename V, typename R, typename... Types>
+struct binary_dispatcher;
+
+template <typename F, typename V, typename R, typename T, typename... Types>
+struct binary_dispatcher<F, V, R, T, Types...>
+{
+ VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
+ {
+ if (v0.template is<T>())
+ {
+ if (v1.template is<T>())
+ {
+ return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
+ unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
+ }
+ }
+ else if (v1.template is<T>())
+ {
+ return binary_dispatcher_lhs<F, V, R, T, Types...>::apply_const(v0, v1, std::forward<F>(f));
+ }
+ return binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
+ }
+
+ VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
+ {
+ if (v0.template is<T>())
+ {
+ if (v1.template is<T>())
+ {
+ return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
+ unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
+ }
+ else
+ {
+ return binary_dispatcher_rhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
+ }
+ }
+ else if (v1.template is<T>())
+ {
+ return binary_dispatcher_lhs<F, V, R, T, Types...>::apply(v0, v1, std::forward<F>(f));
+ }
+ return binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
+ }
+};
+
+template <typename F, typename V, typename R, typename T>
+struct binary_dispatcher<F, V, R, T>
+{
+ VARIANT_INLINE static R apply_const(V const& v0, V const& v1, F&& f)
+ {
+ return f(unwrapper<T>::apply_const(v0.template get_unchecked<T>()),
+ unwrapper<T>::apply_const(v1.template get_unchecked<T>())); // call binary functor
+ }
+
+ VARIANT_INLINE static R apply(V& v0, V& v1, F&& f)
+ {
+ return f(unwrapper<T>::apply(v0.template get_unchecked<T>()),
+ unwrapper<T>::apply(v1.template get_unchecked<T>())); // call binary functor
+ }
+};
+
+// comparator functors
+struct equal_comp
+{
+ template <typename T>
+ bool operator()(T const& lhs, T const& rhs) const
+ {
+ return lhs == rhs;
+ }
+};
+
+struct less_comp
+{
+ template <typename T>
+ bool operator()(T const& lhs, T const& rhs) const
+ {
+ return lhs < rhs;
+ }
+};
+
+template <typename Variant, typename Comp>
+class comparer
+{
+public:
+ explicit comparer(Variant const& lhs) noexcept
+ : lhs_(lhs) {}
+ comparer& operator=(comparer const&) = delete;
+ // visitor
+ template <typename T>
+ bool operator()(T const& rhs_content) const
+ {
+ T const& lhs_content = lhs_.template get_unchecked<T>();
+ return Comp()(lhs_content, rhs_content);
+ }
+
+private:
+ Variant const& lhs_;
+};
+
+// hashing visitor
+struct hasher
+{
+ template <typename T>
+ std::size_t operator()(const T& hashable) const
+ {
+ return std::hash<T>{}(hashable);
+ }
+};
+
+} // namespace detail
+
+struct no_init
+{
+};
+
+template <typename... Types>
+class variant
+{
+ static_assert(sizeof...(Types) > 0, "Template parameter type list of variant can not be empty");
+ static_assert(!detail::disjunction<std::is_reference<Types>...>::value, "Variant can not hold reference types. Maybe use std::reference_wrapper?");
+
+private:
+ static const std::size_t data_size = detail::static_max<sizeof(Types)...>::value;
+ static const std::size_t data_align = detail::static_max<alignof(Types)...>::value;
+public:
+ struct adapted_variant_tag;
+ using types = std::tuple<Types...>;
+private:
+ using first_type = typename std::tuple_element<0, types>::type;
+ using data_type = typename std::aligned_storage<data_size, data_align>::type;
+ using helper_type = detail::variant_helper<Types...>;
+
+ std::size_t type_index;
+ data_type data;
+
+public:
+ VARIANT_INLINE variant() noexcept(std::is_nothrow_default_constructible<first_type>::value)
+ : type_index(sizeof...(Types)-1)
+ {
+ static_assert(std::is_default_constructible<first_type>::value, "First type in variant must be default constructible to allow default construction of variant");
+ new (&data) first_type();
+ }
+
+ VARIANT_INLINE variant(no_init) noexcept
+ : type_index(detail::invalid_value) {}
+
+ // http://isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
+ template <typename T, typename Traits = detail::value_traits<T, Types...>,
+ typename Enable = typename std::enable_if<Traits::is_valid && !std::is_same<variant<Types...>, typename Traits::value_type>::value>::type >
+ VARIANT_INLINE variant(T&& val) noexcept(std::is_nothrow_constructible<typename Traits::target_type, T&&>::value)
+ : type_index(Traits::index)
+ {
+ new (&data) typename Traits::target_type(std::forward<T>(val));
+ }
+
+ VARIANT_INLINE variant(variant<Types...> const& old)
+ : type_index(old.type_index)
+ {
+ helper_type::copy(old.type_index, &old.data, &data);
+ }
+
+ VARIANT_INLINE variant(variant<Types...>&& old) noexcept(std::is_nothrow_move_constructible<types>::value)
+ : type_index(old.type_index)
+ {
+ helper_type::move(old.type_index, &old.data, &data);
+ }
+
+private:
+ VARIANT_INLINE void copy_assign(variant<Types...> const& rhs)
+ {
+ helper_type::destroy(type_index, &data);
+ type_index = detail::invalid_value;
+ helper_type::copy(rhs.type_index, &rhs.data, &data);
+ type_index = rhs.type_index;
+ }
+
+ VARIANT_INLINE void move_assign(variant<Types...>&& rhs)
+ {
+ helper_type::destroy(type_index, &data);
+ type_index = detail::invalid_value;
+ helper_type::move(rhs.type_index, &rhs.data, &data);
+ type_index = rhs.type_index;
+ }
+
+public:
+ VARIANT_INLINE variant<Types...>& operator=(variant<Types...>&& other)
+ {
+ move_assign(std::move(other));
+ return *this;
+ }
+
+ VARIANT_INLINE variant<Types...>& operator=(variant<Types...> const& other)
+ {
+ copy_assign(other);
+ return *this;
+ }
+
+ // conversions
+ // move-assign
+ template <typename T>
+ VARIANT_INLINE variant<Types...>& operator=(T&& rhs) noexcept
+ {
+ variant<Types...> temp(std::forward<T>(rhs));
+ move_assign(std::move(temp));
+ return *this;
+ }
+
+ // copy-assign
+ template <typename T>
+ VARIANT_INLINE variant<Types...>& operator=(T const& rhs)
+ {
+ variant<Types...> temp(rhs);
+ copy_assign(temp);
+ return *this;
+ }
+
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE bool is() const
+ {
+ return type_index == detail::direct_type<T, Types...>::index;
+ }
+
+ template <typename T,typename std::enable_if<
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE bool is() const
+ {
+ return type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index;
+ }
+
+ VARIANT_INLINE bool valid() const
+ {
+ return type_index != detail::invalid_value;
+ }
+
+ template <typename T, typename... Args>
+ VARIANT_INLINE void set(Args&&... args)
+ {
+ helper_type::destroy(type_index, &data);
+ type_index = detail::invalid_value;
+ new (&data) T(std::forward<Args>(args)...);
+ type_index = detail::direct_type<T, Types...>::index;
+ }
+
+ // get_unchecked<T>()
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get_unchecked()
+ {
+ return *reinterpret_cast<T*>(&data);
+ }
+
+#ifdef HAS_EXCEPTIONS
+ // get<T>()
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<T, Types...>::index)
+ {
+ return *reinterpret_cast<T*>(&data);
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+#endif
+
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get_unchecked() const
+ {
+ return *reinterpret_cast<T const*>(&data);
+ }
+
+#ifdef HAS_EXCEPTIONS
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<T, Types...>::index)
+ {
+ return *reinterpret_cast<T const*>(&data);
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+#endif
+
+ // get_unchecked<T>() - T stored as recursive_wrapper<T>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get_unchecked()
+ {
+ return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
+ }
+
+#ifdef HAS_EXCEPTIONS
+ // get<T>() - T stored as recursive_wrapper<T>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
+ {
+ return (*reinterpret_cast<recursive_wrapper<T>*>(&data)).get();
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+#endif
+
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get_unchecked() const
+ {
+ return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
+ }
+
+#ifdef HAS_EXCEPTIONS
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<recursive_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<recursive_wrapper<T>, Types...>::index)
+ {
+ return (*reinterpret_cast<recursive_wrapper<T> const*>(&data)).get();
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+#endif
+
+ // get_unchecked<T>() - T stored as std::reference_wrapper<T>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get_unchecked()
+ {
+ return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
+ }
+
+#ifdef HAS_EXCEPTIONS
+ // get<T>() - T stored as std::reference_wrapper<T>
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<std::reference_wrapper<T>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T& get()
+ {
+ if (type_index == detail::direct_type<std::reference_wrapper<T>, Types...>::index)
+ {
+ return (*reinterpret_cast<std::reference_wrapper<T>*>(&data)).get();
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+#endif
+
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get_unchecked() const
+ {
+ return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
+ }
+
+#ifdef HAS_EXCEPTIONS
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<std::reference_wrapper<T const>, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE T const& get() const
+ {
+ if (type_index == detail::direct_type<std::reference_wrapper<T const>, Types...>::index)
+ {
+ return (*reinterpret_cast<std::reference_wrapper<T const> const*>(&data)).get();
+ }
+ else
+ {
+ throw bad_variant_access("in get<T>()");
+ }
+ }
+#endif
+
+ // This function is deprecated because it returns an internal index field.
+ // Use which() instead.
+ MAPBOX_VARIANT_DEPRECATED VARIANT_INLINE std::size_t get_type_index() const
+ {
+ return type_index;
+ }
+
+ VARIANT_INLINE int which() const noexcept
+ {
+ return static_cast<int>(sizeof...(Types)-type_index - 1);
+ }
+
+ template <typename T, typename std::enable_if<
+ (detail::direct_type<T, Types...>::index != detail::invalid_value)>::type* = nullptr>
+ VARIANT_INLINE static constexpr int which() noexcept
+ {
+ return static_cast<int>(sizeof...(Types)-detail::direct_type<T, Types...>::index - 1);
+ }
+
+ // visitor
+ // unary
+ template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static visit(V const& v, F&& f)
+ -> decltype(detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f)))
+ {
+ return detail::dispatcher<F, V, R, Types...>::apply_const(v, std::forward<F>(f));
+ }
+ // non-const
+ template <typename F, typename V, typename R = typename detail::result_of_unary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static visit(V& v, F&& f)
+ -> decltype(detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f)))
+ {
+ return detail::dispatcher<F, V, R, Types...>::apply(v, std::forward<F>(f));
+ }
+
+ // binary
+ // const
+ template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static binary_visit(V const& v0, V const& v1, F&& f)
+ -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f)))
+ {
+ return detail::binary_dispatcher<F, V, R, Types...>::apply_const(v0, v1, std::forward<F>(f));
+ }
+ // non-const
+ template <typename F, typename V, typename R = typename detail::result_of_binary_visit<F, first_type>::type>
+ auto VARIANT_INLINE static binary_visit(V& v0, V& v1, F&& f)
+ -> decltype(detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f)))
+ {
+ return detail::binary_dispatcher<F, V, R, Types...>::apply(v0, v1, std::forward<F>(f));
+ }
+
+ // match
+ // unary
+ template <typename... Fs>
+ auto VARIANT_INLINE match(Fs&&... fs) const
+ -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
+ {
+ return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
+ }
+ // non-const
+ template <typename... Fs>
+ auto VARIANT_INLINE match(Fs&&... fs)
+ -> decltype(variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...)))
+ {
+ return variant::visit(*this, ::mapbox::util::make_visitor(std::forward<Fs>(fs)...));
+ }
+
+ ~variant() noexcept // no-throw destructor
+ {
+ helper_type::destroy(type_index, &data);
+ }
+
+ // comparison operators
+ // equality
+ VARIANT_INLINE bool operator==(variant const& rhs) const
+ {
+ assert(valid() && rhs.valid());
+ if (this->which() != rhs.which())
+ {
+ return false;
+ }
+ detail::comparer<variant, detail::equal_comp> visitor(*this);
+ return visit(rhs, visitor);
+ }
+
+ VARIANT_INLINE bool operator!=(variant const& rhs) const
+ {
+ return !(*this == rhs);
+ }
+
+ // less than
+ VARIANT_INLINE bool operator<(variant const& rhs) const
+ {
+ assert(valid() && rhs.valid());
+ if (this->which() != rhs.which())
+ {
+ return this->which() < rhs.which();
+ }
+ detail::comparer<variant, detail::less_comp> visitor(*this);
+ return visit(rhs, visitor);
+ }
+ VARIANT_INLINE bool operator>(variant const& rhs) const
+ {
+ return rhs < *this;
+ }
+ VARIANT_INLINE bool operator<=(variant const& rhs) const
+ {
+ return !(*this > rhs);
+ }
+ VARIANT_INLINE bool operator>=(variant const& rhs) const
+ {
+ return !(*this < rhs);
+ }
+};
+
+// unary visitor interface
+// const
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V const& v) -> decltype(V::visit(v, std::forward<F>(f)))
+{
+ return V::visit(v, std::forward<F>(f));
+}
+
+// non-const
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V& v) -> decltype(V::visit(v, std::forward<F>(f)))
+{
+ return V::visit(v, std::forward<F>(f));
+}
+
+// binary visitor interface
+// const
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V const& v0, V const& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
+{
+ return V::binary_visit(v0, v1, std::forward<F>(f));
+}
+
+// non-const
+template <typename F, typename V>
+auto VARIANT_INLINE apply_visitor(F&& f, V& v0, V& v1) -> decltype(V::binary_visit(v0, v1, std::forward<F>(f)))
+{
+ return V::binary_visit(v0, v1, std::forward<F>(f));
+}
+
+// getter interface
+
+#ifdef HAS_EXCEPTIONS
+template <typename ResultType, typename T>
+auto get(T& var)->decltype(var.template get<ResultType>())
+{
+ return var.template get<ResultType>();
+}
+#endif
+
+template <typename ResultType, typename T>
+ResultType& get_unchecked(T& var)
+{
+ return var.template get_unchecked<ResultType>();
+}
+
+#ifdef HAS_EXCEPTIONS
+template <typename ResultType, typename T>
+auto get(T const& var)->decltype(var.template get<ResultType>())
+{
+ return var.template get<ResultType>();
+}
+#endif
+
+template <typename ResultType, typename T>
+ResultType const& get_unchecked(T const& var)
+{
+ return var.template get_unchecked<ResultType>();
+}
+} // namespace util
+} // namespace mapbox
+
+// hashable iff underlying types are hashable
+namespace std {
+template <typename... Types>
+struct hash< ::mapbox::util::variant<Types...>> {
+ std::size_t operator()(const ::mapbox::util::variant<Types...>& v) const noexcept
+ {
+ return ::mapbox::util::apply_visitor(::mapbox::util::detail::hasher{}, v);
+ }
+};
+}
+
+#endif // MAPBOX_UTIL_VARIANT_HPP
diff --git a/include/mapbox/variant_io.hpp b/include/mapbox/variant_io.hpp
new file mode 100644
index 0000000..1456cc5
--- /dev/null
+++ b/include/mapbox/variant_io.hpp
@@ -0,0 +1,45 @@
+#ifndef MAPBOX_UTIL_VARIANT_IO_HPP
+#define MAPBOX_UTIL_VARIANT_IO_HPP
+
+#include <iosfwd>
+
+#include <mapbox/variant.hpp>
+
+namespace mapbox {
+namespace util {
+
+namespace detail {
+// operator<< helper
+template <typename Out>
+class printer
+{
+public:
+ explicit printer(Out& out)
+ : out_(out) {}
+ printer& operator=(printer const&) = delete;
+
+ // visitor
+ template <typename T>
+ void operator()(T const& operand) const
+ {
+ out_ << operand;
+ }
+
+private:
+ Out& out_;
+};
+}
+
+// operator<<
+template <typename CharT, typename Traits, typename... Types>
+VARIANT_INLINE std::basic_ostream<CharT, Traits>&
+operator<<(std::basic_ostream<CharT, Traits>& out, variant<Types...> const& rhs)
+{
+ detail::printer<std::basic_ostream<CharT, Traits>> visitor(out);
+ apply_visitor(visitor, rhs);
+ return out;
+}
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_VARIANT_IO_HPP
diff --git a/include/mapbox/variant_visitor.hpp b/include/mapbox/variant_visitor.hpp
new file mode 100644
index 0000000..481eb65
--- /dev/null
+++ b/include/mapbox/variant_visitor.hpp
@@ -0,0 +1,38 @@
+#ifndef MAPBOX_UTIL_VARIANT_VISITOR_HPP
+#define MAPBOX_UTIL_VARIANT_VISITOR_HPP
+
+namespace mapbox {
+namespace util {
+
+template <typename... Fns>
+struct visitor;
+
+template <typename Fn>
+struct visitor<Fn> : Fn
+{
+ using type = Fn;
+ using Fn::operator();
+
+ visitor(Fn fn) : Fn(fn) {}
+};
+
+template <typename Fn, typename... Fns>
+struct visitor<Fn, Fns...> : Fn, visitor<Fns...>
+{
+ using type = visitor;
+ using Fn::operator();
+ using visitor<Fns...>::operator();
+
+ visitor(Fn fn, Fns... fns) : Fn(fn), visitor<Fns...>(fns...) {}
+};
+
+template <typename... Fns>
+visitor<Fns...> make_visitor(Fns... fns)
+{
+ return visitor<Fns...>(fns...);
+}
+
+} // namespace util
+} // namespace mapbox
+
+#endif // MAPBOX_UTIL_VARIANT_VISITOR_HPP
diff --git a/package/config.xml b/package/config.xml
new file mode 100644
index 0000000..8aaf856
--- /dev/null
+++ b/package/config.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<widget xmlns="http://www.w3.org/ns/widgets" id="tbtnavi" version="0.1">
+ <name>tbtnavi</name>
+ <icon src="icon.svg"/>
+ <content src="bin/tbtnavi" type="application/vnd.agl.native"/>
+ <description>This is the turn-by-turn navigation application. </description>
+ <author>TOYOTA</author>
+ <license>APL 2.0</license>
+ <feature name="urn:AGL:widget:required-api">
+ <param name="windowmanager" value="ws"/>
+ <param name="homescreen" value="ws"/>
+ </feature>
+ <feature name="urn:AGL:widget:required-permission">
+ <param name="urn:AGL:permission::system:run-by-default" value="required"/>
+ <param name="urn:AGL:permission::public:no-htdocs" value="required" />
+ <param name="http://tizen.org/privilege/internal/dbus" value="required"/>
+ </feature>
+</widget>
diff --git a/package/icon.svg b/package/icon.svg
new file mode 100644
index 0000000..6628784
--- /dev/null
+++ b/package/icon.svg
@@ -0,0 +1,283 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+
+<svg
+ xmlns:i="&amp;ns_ai;"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 320 320"
+ style="enable-background:new 0 0 320 320;"
+ xml:space="preserve"
+ id="svg2"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="icon.svg"><metadata
+ id="metadata1292"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs1290" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="2560"
+ inkscape:window-height="1464"
+ id="namedview1288"
+ showgrid="false"
+ inkscape:zoom="0.7375"
+ inkscape:cx="-697.62712"
+ inkscape:cy="160"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" /><style
+ type="text/css"
+ id="style4">
+ .st0{display:none;}
+ .st1{display:inline;}
+ .st2{opacity:0.4;fill:url(#SVGID_1_);}
+ .st3{fill:url(#SVGID_2_);}
+ .st4{fill:#FFFFFF;}
+ .st5{font-family:'Roboto-Regular';}
+ .st6{font-size:25px;}
+ .st7{letter-spacing:6;}
+ .st8{fill:url(#SVGID_3_);}
+ .st9{fill:url(#SVGID_4_);}
+ .st10{fill:url(#SVGID_5_);}
+ .st11{fill:url(#SVGID_6_);}
+ .st12{fill:url(#SVGID_7_);}
+ .st13{fill:url(#SVGID_8_);}
+ .st14{fill:url(#SVGID_9_);}
+ .st15{fill:url(#SVGID_10_);}
+ .st16{fill:url(#SVGID_11_);}
+ .st17{fill:url(#SVGID_12_);}
+ .st18{fill:url(#SVGID_13_);}
+ .st19{fill:url(#SVGID_14_);}
+ .st20{fill:url(#SVGID_15_);}
+ .st21{fill:url(#SVGID_16_);}
+ .st22{fill:url(#SVGID_17_);}
+ .st23{fill:url(#SVGID_18_);}
+ .st24{opacity:0.29;}
+ .st25{fill:url(#SVGID_19_);}
+ .st26{fill:url(#SVGID_20_);}
+ .st27{fill:url(#SVGID_21_);}
+ .st28{fill:url(#SVGID_22_);}
+ .st29{fill:url(#SVGID_23_);}
+ .st30{fill:url(#SVGID_24_);}
+ .st31{fill:url(#SVGID_25_);}
+ .st32{fill:url(#SVGID_26_);}
+ .st33{fill:url(#SVGID_27_);}
+ .st34{fill:url(#SVGID_28_);}
+ .st35{fill:url(#SVGID_29_);}
+ .st36{fill:url(#SVGID_30_);}
+ .st37{fill:url(#SVGID_31_);}
+ .st38{fill:url(#SVGID_32_);}
+ .st39{fill:url(#SVGID_33_);}
+ .st40{fill:url(#SVGID_34_);}
+ .st41{fill:url(#SVGID_35_);}
+ .st42{fill:url(#SVGID_36_);}
+ .st43{opacity:0.4;fill:url(#SVGID_37_);}
+ .st44{fill:url(#SVGID_38_);}
+ .st45{fill:url(#SVGID_39_);}
+ .st46{fill:url(#SVGID_40_);}
+ .st47{fill:url(#SVGID_41_);}
+ .st48{fill:url(#SVGID_42_);}
+ .st49{fill:url(#SVGID_43_);}
+ .st50{fill:url(#SVGID_44_);}
+ .st51{display:inline;opacity:0.29;}
+ .st52{display:inline;fill:url(#SVGID_45_);}
+ .st53{display:inline;fill:url(#SVGID_46_);}
+ .st54{display:inline;fill:#FFFFFF;}
+ .st55{display:inline;fill:url(#SVGID_47_);}
+ .st56{display:inline;fill:url(#SVGID_48_);}
+ .st57{display:inline;fill:url(#SVGID_49_);}
+ .st58{display:inline;fill:url(#SVGID_50_);}
+ .st59{display:inline;fill:url(#SVGID_51_);}
+ .st60{display:inline;fill:url(#SVGID_52_);}
+ .st61{opacity:0.4;fill:url(#SVGID_53_);}
+ .st62{fill:url(#SVGID_54_);}
+ .st63{fill:url(#SVGID_55_);}
+ .st64{fill:url(#SVGID_56_);}
+ .st65{fill:url(#SVGID_57_);}
+ .st66{fill:url(#SVGID_58_);}
+ .st67{opacity:0.4;fill:url(#SVGID_59_);}
+ .st68{fill:url(#SVGID_60_);}
+ .st69{fill:url(#SVGID_61_);}
+ .st70{fill:url(#SVGID_62_);}
+ .st71{fill:url(#SVGID_63_);}
+ .st72{fill:url(#SVGID_64_);}
+ .st73{fill:url(#SVGID_65_);}
+ .st74{fill:url(#SVGID_66_);}
+ .st75{fill:url(#SVGID_67_);}
+ .st76{fill:url(#SVGID_68_);}
+ .st77{fill:url(#SVGID_69_);}
+ .st78{fill:url(#SVGID_70_);}
+ .st79{fill:url(#SVGID_71_);}
+ .st80{fill:url(#SVGID_72_);}
+ .st81{fill:url(#SVGID_73_);}
+ .st82{fill:url(#SVGID_74_);}
+ .st83{fill:url(#SVGID_75_);}
+ .st84{fill:url(#SVGID_76_);}
+ .st85{fill:url(#SVGID_77_);}
+ .st86{fill:url(#SVGID_78_);}
+ .st87{fill:url(#SVGID_79_);}
+ .st88{fill:url(#SVGID_80_);}
+ .st89{fill:url(#SVGID_81_);}
+ .st90{fill:url(#SVGID_82_);}
+ .st91{fill:url(#SVGID_83_);}
+ .st92{fill:url(#SVGID_84_);}
+ .st93{fill:url(#SVGID_85_);}
+ .st94{fill:url(#SVGID_86_);}
+ .st95{opacity:0.4;fill:url(#SVGID_87_);}
+ .st96{fill:url(#SVGID_88_);}
+ .st97{fill:url(#SVGID_89_);}
+ .st98{fill:url(#SVGID_90_);}
+ .st99{display:inline;fill:url(#SVGID_91_);}
+ .st100{display:inline;fill:url(#SVGID_92_);}
+ .st101{fill:url(#SVGID_93_);}
+ .st102{fill:url(#SVGID_94_);}
+ .st103{opacity:0.4;fill:url(#SVGID_95_);}
+ .st104{fill:url(#SVGID_96_);}
+ .st105{fill:url(#SVGID_97_);}
+ .st106{fill:url(#SVGID_98_);}
+ .st107{fill:url(#SVGID_99_);}
+ .st108{fill:url(#SVGID_100_);}
+ .st109{fill:url(#SVGID_101_);}
+ .st110{display:inline;fill:url(#SVGID_102_);}
+ .st111{display:inline;fill:url(#SVGID_103_);}
+ .st112{fill:url(#SVGID_104_);}
+ .st113{fill:url(#SVGID_105_);}
+ .st114{fill:url(#SVGID_106_);}
+ .st115{fill:url(#SVGID_107_);}
+ .st116{fill:url(#SVGID_108_);}
+ .st117{opacity:0.4;fill:url(#SVGID_109_);}
+ .st118{fill:url(#SVGID_110_);}
+ .st119{fill:url(#SVGID_111_);}
+ .st120{fill:url(#SVGID_112_);}
+ .st121{fill:url(#SVGID_113_);}
+ .st122{fill:url(#SVGID_114_);}
+ .st123{opacity:0.4;fill:url(#SVGID_115_);}
+ .st124{fill:url(#SVGID_116_);}
+ .st125{fill:url(#SVGID_117_);}
+ .st126{fill:url(#SVGID_118_);}
+ .st127{fill:url(#SVGID_119_);}
+ .st128{fill:url(#SVGID_120_);}
+ .st129{fill:url(#SVGID_121_);}
+ .st130{fill:url(#SVGID_122_);}
+</style><switch
+ id="switch6"><g
+ i:extraneous="self"
+ id="g8"><g
+ id="Settings_Active"><circle
+ class="st24"
+ cx="159.7"
+ cy="133.4"
+ r="101.9"
+ id="circle1230" /><linearGradient
+ id="SVGID_119_"
+ gradientUnits="userSpaceOnUse"
+ x1="115.9317"
+ y1="254.1836"
+ x2="256.3852"
+ y2="-133.5267"><stop
+ offset="0"
+ style="stop-color:#8BC53F"
+ id="stop1233" /><stop
+ offset="2.015080e-02"
+ style="stop-color:#7CCB56;stop-opacity:0.9678"
+ id="stop1235" /><stop
+ offset="6.089833e-02"
+ style="stop-color:#62D67D;stop-opacity:0.9028"
+ id="stop1237" /><stop
+ offset="0.1057"
+ style="stop-color:#4BDFA0;stop-opacity:0.8312"
+ id="stop1239" /><stop
+ offset="0.1543"
+ style="stop-color:#38E7BE;stop-opacity:0.7537"
+ id="stop1241" /><stop
+ offset="0.2077"
+ style="stop-color:#28EED6;stop-opacity:0.6684"
+ id="stop1243" /><stop
+ offset="0.2681"
+ style="stop-color:#1CF3E8;stop-opacity:0.572"
+ id="stop1245" /><stop
+ offset="0.3394"
+ style="stop-color:#13F6F5;stop-opacity:0.4581"
+ id="stop1247" /><stop
+ offset="0.4323"
+ style="stop-color:#0EF8FD;stop-opacity:0.3098"
+ id="stop1249" /><stop
+ offset="0.6264"
+ style="stop-color:#0DF9FF;stop-opacity:0"
+ id="stop1251" /></linearGradient><circle
+ class="st127"
+ cx="159.7"
+ cy="133.4"
+ r="101.9"
+ id="circle1253" /><linearGradient
+ id="SVGID_120_"
+ gradientUnits="userSpaceOnUse"
+ x1="4.0481"
+ y1="287.9492"
+ x2="320.4859"
+ y2="-15.4029"
+ gradientTransform="matrix(1 5.464556e-03 -5.464556e-03 1 -2.0192 -3.0212)"><stop
+ offset="0"
+ style="stop-color:#59FF7F"
+ id="stop1256" /><stop
+ offset="1"
+ style="stop-color:#6BFBFF"
+ id="stop1258" /></linearGradient><path
+ class="st128"
+ d="M160,238.8c-0.2,0-0.4,0-0.6,0c-58-0.3-104.9-47.7-104.6-105.7C55.2,75.3,102.3,28.5,160,28.5 c0.2,0,0.4,0,0.6,0c58,0.3,104.9,47.7,104.6,105.7l0,0C264.8,192,217.7,238.8,160,238.8z M160,32.2 c-55.7,0-101.2,45.2-101.5,100.9c-0.3,55.9,45,101.7,100.9,102c0.2,0,0.4,0,0.6,0c55.7,0,101.2-45.2,101.5-100.9 c0.3-55.9-45-101.7-100.9-102C160.4,32.2,160.2,32.2,160,32.2z"
+ id="path1260" /><g
+ id="g1262"><text
+ transform="matrix(1 0 0 1 75.4379 284.7129)"
+ class="st4 st5 st6 st7"
+ id="text1264">SETTINGS</text>
+<g
+ id="g1266"><g
+ id="g1268"><g
+ id="g1270"><linearGradient
+ id="SVGID_121_"
+ gradientUnits="userSpaceOnUse"
+ x1="79.1804"
+ y1="226.0817"
+ x2="282.752"
+ y2="-4.8609"><stop
+ offset="0"
+ style="stop-color:#59FF7F"
+ id="stop1273" /><stop
+ offset="1"
+ style="stop-color:#6BFBFF"
+ id="stop1275" /></linearGradient><path
+ class="st129"
+ d="M159.9,163.9c-16.3,0-29.5-13.2-29.5-29.4s13.2-29.4,29.5-29.4v3.9c-14.1,0-25.5,11.4-25.5,25.5 c0,14,11.5,25.5,25.5,25.5c14.1,0,25.6-11.4,25.6-25.5h3.9C189.4,150.7,176.2,163.9,159.9,163.9z"
+ id="path1277" /></g><g
+ id="g1279"><linearGradient
+ id="SVGID_122_"
+ gradientUnits="userSpaceOnUse"
+ x1="79.2457"
+ y1="226.1393"
+ x2="282.8174"
+ y2="-4.8033"><stop
+ offset="0"
+ style="stop-color:#59FF7F"
+ id="stop1282" /><stop
+ offset="1"
+ style="stop-color:#6BFBFF"
+ id="stop1284" /></linearGradient><path
+ class="st130"
+ d="M171.7,197.4h-23.4c-2.2,0-4-1.8-4-3.9V181c-2-0.7-4-1.5-6-2.5l-8.8,8.8c-1.5,1.5-4,1.5-5.6-0.1 l-16.6-16.6c-1.6-1.6-1.6-4.1-0.1-5.6l8.7-8.7c-1-2-1.8-4-2.5-6.1h-12.3c-2.2,0-3.9-1.8-3.9-4v-23.4c0-2.2,1.8-4,3.9-4h12.3 c0.9-2.6,1.9-5.1,3.2-7.4l3.5,1.8c-1.4,2.6-2.5,5.3-3.4,8.1l-0.4,1.4h-15.2l0,23.5l15.2,0.1l0.4,1.4c0.9,2.8,2,5.5,3.4,8 l0.7,1.3L110,167.8l16.6,16.6l10.9-10.8l1.3,0.7c2.6,1.4,5.2,2.5,8,3.3l1.4,0.4v15.4l23.5,0l0.1-15.4l1.4-0.4 c2.7-0.8,5.4-1.9,7.9-3.3l1.3-0.7l10.9,10.9l16.6-16.6l-10.8-11l0.7-1.3c1.4-2.6,2.5-5.2,3.3-7.9l0.4-1.4h15.4l0-23.5 l-15.3-0.1l-0.4-1.4c-0.8-2.8-1.9-5.5-3.3-8l-0.7-1.3l10.8-10.8l-16.6-16.6l-10.8,10.7l-1.3-0.7c-2.6-1.4-5.3-2.5-8.1-3.4 l-1.4-0.4V75.6l-23.5,0l-0.1,15.1l-1.4,0.4c-2.8,0.9-5.6,2-8.1,3.4l-1.3,0.7l-10.7-10.7L107.2,104c-1.5-1.5-1.5-4,0.1-5.6 l16.5-16.5c0.8-0.8,1.8-1.3,2.9-1.2c1,0,2,0.4,2.7,1.1l8.7,8.6c2-1,4-1.8,6.2-2.5V75.6c0-2.2,1.8-3.9,4-3.9h23.4 c2.2,0,4,1.8,4,3.9v12.3c2.1,0.7,4.1,1.6,6.1,2.5l8.7-8.7c0.7-0.7,1.7-1.1,2.7-1.1h0c1.1,0,2.1,0.4,2.9,1.2l16.6,16.6 c0.8,0.8,1.2,1.8,1.2,2.9c0,1-0.4,2-1.1,2.7l-8.8,8.8c1,2,1.8,4,2.5,6h12.4c2.2,0,3.9,1.8,3.9,4v23.4c0,2.2-1.8,4-3.9,4 h-12.5c-0.7,2-1.5,4-2.5,6l8.9,8.9c1.5,1.5,1.5,4-0.1,5.6l-16.6,16.6c-0.8,0.8-1.8,1.2-2.9,1.2h0c-1,0-2-0.4-2.7-1.1 l-8.9-8.9c-1.9,1-3.9,1.8-5.9,2.5v12.5C175.7,195.6,173.9,197.4,171.7,197.4z"
+ id="path1286" /></g></g></g></g></g></g></switch></svg> \ No newline at end of file
diff --git a/package/package.pro b/package/package.pro
new file mode 100644
index 0000000..ae6921b
--- /dev/null
+++ b/package/package.pro
@@ -0,0 +1,19 @@
+
+DISTFILES = icon.svg config.xml
+
+copy_icon.target = $$OUT_PWD/root/icon.svg
+copy_icon.depends = $$_PRO_FILE_PWD_/icon.svg
+copy_icon.commands = $(COPY_FILE) \"$$replace(copy_icon.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_icon.target, /, $$QMAKE_DIR_SEP)\"
+QMAKE_EXTRA_TARGETS += copy_icon
+PRE_TARGETDEPS += $$copy_icon.target
+
+copy_config.target = $$OUT_PWD/root/config.xml
+copy_config.depends = $$_PRO_FILE_PWD_/config.xml
+copy_config.commands = $(COPY_FILE) \"$$replace(copy_config.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_config.target, /, $$QMAKE_DIR_SEP)\"
+QMAKE_EXTRA_TARGETS += copy_config
+PRE_TARGETDEPS += $$copy_config.target
+
+wgt.target = package
+wgt.commands = wgtpkg-pack -f -o tbtnavi.wgt root
+
+QMAKE_EXTRA_TARGETS += wgt
diff --git a/tbtnavi.pro b/tbtnavi.pro
new file mode 100644
index 0000000..579a952
--- /dev/null
+++ b/tbtnavi.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+SUBDIRS = app package
+package.depends += app