From 30d24cbc67ef416672a3386b10be8fe6711c65d7 Mon Sep 17 00:00:00 2001 From: zheng_wenlong Date: Fri, 2 Nov 2018 14:13:07 +0900 Subject: use mapbox as navigation --- app/qml/CustomLabel.qml | 9 + app/qml/DateAndTime.qml | 37 +++++ app/qml/Main.qml | 28 ++++ app/qml/MapWindow.qml | 434 ++++++++++++++++++++++++++++++++++++++++++++++++ app/qml/qmldir | 3 + 5 files changed, 511 insertions(+) create mode 100644 app/qml/CustomLabel.qml create mode 100644 app/qml/DateAndTime.qml create mode 100644 app/qml/Main.qml create mode 100644 app/qml/MapWindow.qml create mode 100644 app/qml/qmldir (limited to 'app/qml') diff --git a/app/qml/CustomLabel.qml b/app/qml/CustomLabel.qml new file mode 100644 index 0000000..12387a1 --- /dev/null +++ b/app/qml/CustomLabel.qml @@ -0,0 +1,9 @@ +import QtQuick 2.1 + +Text { + verticalAlignment: Text.AlignVCenter + font.family: "Lato" + font.weight: Font.Light + color: "#000000" + font.pixelSize: 24 +} diff --git a/app/qml/DateAndTime.qml b/app/qml/DateAndTime.qml new file mode 100644 index 0000000..65afb0b --- /dev/null +++ b/app/qml/DateAndTime.qml @@ -0,0 +1,37 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.0 + +Item { + id: dateAndTime + + width: 53 * hspan + height: 33 * vspan + + property int hspan: 4 + property int vspan: 1 + property var currentDate: new Date(); + + RowLayout { + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + spacing: 10 + + CustomLabel { + font.capitalization: Font.AllUppercase + text: Qt.formatDateTime(dateAndTime.currentDate, "HH:mm") + + color: "#000000" + } + } + + Timer { + interval: 60000 + running: true + repeat: true + + onTriggered: { + dateAndTime.currentDate = new Date(); + } + } +} diff --git a/app/qml/Main.qml b/app/qml/Main.qml new file mode 100644 index 0000000..a2861e5 --- /dev/null +++ b/app/qml/Main.qml @@ -0,0 +1,28 @@ +import QtGraphicalEffects 1.0 +import QtLocation 5.9 +import QtPositioning 5.0 +import QtQuick 2.0 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.0 + +import com.mapbox.cheap_ruler 1.0 +import "qrc:/qml" + +ApplicationWindow { + id: window + + title: "QT MapboxGL Turn By Turn Navigation Demo" + height: 768 + width: 1024 + visible: true + + Item { + anchors.centerIn: parent + width: parent.width + height: parent.height + + MapWindow { + anchors.fill: parent + } + } +} diff --git a/app/qml/MapWindow.qml b/app/qml/MapWindow.qml new file mode 100644 index 0000000..3772c31 --- /dev/null +++ b/app/qml/MapWindow.qml @@ -0,0 +1,434 @@ +import QtLocation 5.9 +import QtPositioning 5.0 +import QtQuick 2.0 + +import com.mapbox.cheap_ruler 1.0 + +Item { + id: mapWindow + + // Km/h + property int carSpeed: 180 + property bool navigating: false + + property real rotateAngle: 0 + property var startPoint: QtPositioning.coordinate(36.12549, -115.173498) + property var endPoint: QtPositioning.coordinate(36.0659063, -115.1800443) + + states: [ + State { + name: "" + PropertyChanges { target: map; tilt: 0; bearing: 0; zoomLevel: map.zoomLevel } + }, + State { + name: "navigating" + PropertyChanges { target: map; tilt: 60; zoomLevel: 20 } + } + ] + + transitions: [ + Transition { + to: "*" + RotationAnimation { target: map; property: "bearing"; duration: 100; direction: RotationAnimation.Shortest } + NumberAnimation { target: map; property: "zoomLevel"; duration: 100 } + NumberAnimation { target: map; property: "tilt"; duration: 100 } + } + ] + + state: navigating ? "navigating" : "" + + Image { + id: backgroud + anchors.left: parent.left + anchors.top: parent.top + width: parent.width + height: 100 + + source: "qrc:simple-bottom-background-white.png" + z: 1 + } + + Image { + id: carCurrent + anchors.left: parent.left + anchors.top: parent.top + z: 3 + + visible: !mapWindow.navigating + source: "qrc:car-focus.png" + + MouseArea { + id: area + + anchors.fill: parent + + onClicked: { + mapWindow.navigating = true + currentDistanceAnimation.start(); + } + } + + scale: area.pressed ? 0.85 : 1.0 + + Behavior on scale { + NumberAnimation {} + } + } + + Image { + id: turnDirection + anchors.left: carCurrent.right + anchors.top: parent.top + anchors.leftMargin: 20 + + z: 3 + } + + CustomLabel { + id: distance + anchors.left: carCurrent.right + anchors.bottom: backgroud.bottom + z: 3 + + font.pixelSize: 38 + } + + CustomLabel { + id: turnInstructions + anchors.left: turnDirection.right + anchors.top: parent.top + anchors.leftMargin: 30 + anchors.topMargin: (backgroud.height-turnInstructions.height)/2 + z: 3 + + font.pixelSize: 38 + } + + 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: "pk.eyJ1IjoidG1wc2FudG9zIiwiYSI6ImNqMWVzZWthbDAwMGIyd3M3ZDR0aXl3cnkifQ.FNxMeWCZgmujeiHjl44G9Q" + } + + PluginParameter { + name: "mapboxgl.mapping.cache.directory" + value: "/home/0/app-data/navigation/" + } + } + + center: mapWindow.navigating ? ruler.currentPosition : startPoint + zoomLevel: 5 + minimumZoomLevel: 0 + maximumZoomLevel: 20 + tilt: 0 + + copyrightsVisible: false + + MouseArea { + anchors.fill: parent + + onWheel: { + mapWindow.navigating = false + wheel.accepted = false + } + } + gesture.onPanStarted: { + mapWindow.navigating = false + } + + gesture.onPinchStarted: { + mapWindow.navigating = false + } + + RotationAnimation on bearing { + id: bearingAnimation + + duration: 250 + alwaysRunToEnd: false + direction: RotationAnimation.Shortest + running: mapWindow.navigating + } + + Location { + id: previousLocation + coordinate: QtPositioning.coordinate(0, 0); + } + + onCenterChanged: { + if (previousLocation.coordinate === center || !mapWindow.navigating) + return; + + bearingAnimation.to = previousLocation.coordinate.azimuthTo(center); + bearingAnimation.start(); + + previousLocation.coordinate = center; + } + + function updateRoute() { + routeQuery.clearWaypoints(); + routeQuery.addWaypoint(startMarker.coordinate); + routeQuery.addWaypoint(endMarker.coordinate); + } + + MapQuickItem { + id: startMarker + + sourceItem: Image { + id: greenMarker + source: "qrc:///marker-green.png" + } + + coordinate : startPoint + anchorPoint.x: greenMarker.width / 2 + anchorPoint.y: greenMarker.height / 2 + + MouseArea { + drag.target: parent + anchors.fill: parent + + onReleased: { + map.updateRoute(); + } + } + } + + MapQuickItem { + id: endMarker + + sourceItem: Image { + id: redMarker + source: "qrc:///marker-end.png" + } + + coordinate : endPoint + anchorPoint.x: redMarker.width / 2 + anchorPoint.y: redMarker.height / 2 + + MouseArea { + drag.target: parent + anchors.fill: parent + + onReleased: { + map.updateRoute(); + } + } + } + + 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; + ruler.currentDistance = 0; + + currentDistanceAnimation.stop(); + currentDistanceAnimation.to = ruler.distance; + } + } + } + + MapQuickItem { + zoomLevel: map.zoomLevel + + sourceItem: Image { + id: carMarker + source: "qrc:///car-marker2.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; + } + } + + CheapRuler { + id: ruler + + PropertyAnimation on currentDistance { + id: currentDistanceAnimation + + duration: ruler.distance / mapWindow.carSpeed * 60 * 60 * 1000 + alwaysRunToEnd: false + } + + onCurrentDistanceChanged: { + var total = 0; + var total2 = 0; + var i = 0; + var j = 0; + var alltime = routeModel.get(0).travelTime; + var alldistance = routeModel.get(0).distance; + + // XXX: Use car speed in meters to pre-warn the turn instruction + while (total - mapWindow.carSpeed < ruler.currentDistance * 1000 && i < routeModel.get(0).segments.length) + { + total += routeModel.get(0).segments[i++].maneuver.distanceToNextInstruction; + } + + while (total2 < ruler.currentDistance * 1000 && j < routeModel.get(0).segments.length) + { + total2 += routeModel.get(0).segments[j++].maneuver.distanceToNextInstruction; + } + + var dis = (total2 - ruler.currentDistance * 1000).toFixed(1); + if(dis > 1000) + { + distance.text = (dis / 1000).toFixed(1) + " km"; + } + else + { + distance.text = dis + " m"; + } + + var travaltimesec=((1 - (ruler.currentDistance * 1000)/alldistance)*alltime).toFixed(0); + + if((travaltimesec/3600)>=1) + { + travaltime.text = (travaltimesec/3600).toFixed(0) + "h" + ((travaltimesec%3600)/60).toFixed(0) + "min"; + } + else + { + travaltime.text = (travaltimesec/60).toFixed(0) + "min"; + } + + turnInstructions.text = routeModel.get(0).segments[i - 1].maneuver.instructionText; + + if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionForward) + { + turnDirection.source = "qrc:arrow-0.png"; + } + else if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionLightRight) + { + turnDirection.source = "qrc:arrow-r-30.png"; + } + else if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionRight) + { + turnDirection.source = "qrc:arrow-r-45.png"; + } + else if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionHardRight) + { + turnDirection.source = "qrc:arrow-r-75.png"; + } + else if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionUTurnRight) + { + turnDirection.source = "qrc:arrow-r-180.png"; + } + else if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionLightLeft) + { + turnDirection.source = "qrc:arrow-l-30.png"; + } + else if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionLeft) + { + turnDirection.source = "qrc:arrow-l-45.png"; + } + else if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionHardLeft) + { + turnDirection.source = "qrc:arrow-l-75.png"; + } + else if(routeModel.get(0).segments[i - 1].maneuver.direction === RouteManeuver.DirectionUTurnLeft) + { + turnDirection.source = "qrc:arrow-l-180.png"; + } + else + { + turnDirection.source = "qrc:arrow-0.png"; + } + + } + } + } + + 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: "pk.eyJ1IjoicXRzZGsiLCJhIjoiY2l5azV5MHh5MDAwdTMybzBybjUzZnhxYSJ9.9rfbeqPjX2BusLRDXHCOBA" + } + } + + Component.onCompleted: { + if (map) { + map.updateRoute(); + } + } + } + + RouteQuery { + id: routeQuery + } + + Image { + id: bottombackgroud + anchors.left: parent.left + anchors.bottom: parent.bottom + width: parent.width + height: 100 + + source: "qrc:simple-bottom-background-white.png" + z: 1 + } + + CustomLabel { + id: travaltime + anchors.left: bottombackgroud.left + anchors.verticalCenter: bottombackgroud.verticalCenter + visible: mapWindow.navigating + z: 3 + font.pixelSize: 38 + } + + Row { + anchors.horizontalCenter: bottombackgroud.horizontalCenter + anchors.verticalCenter: bottombackgroud.verticalCenter + width: bottombackgroud.width / 4 + spacing: 10 + z:3 + DateAndTime {} + } +} diff --git a/app/qml/qmldir b/app/qml/qmldir new file mode 100644 index 0000000..c59f9cd --- /dev/null +++ b/app/qml/qmldir @@ -0,0 +1,3 @@ +CustomLabel 1.0 CustomLabel.qml +DateAndTime 1.0 DateAndTime.qml +MapWindow 1.0 MapWindow.qml -- cgit 1.2.3-korg