Waypoint bug fixes

This commit is contained in:
Garth Vander Houwen 2023-04-09 11:04:08 -07:00
parent 32cceea4bf
commit e28a970945
7 changed files with 130 additions and 165 deletions

View file

@ -21,9 +21,6 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate {
// Apple Park
static let DefaultLocation = CLLocation(latitude: 37.3346, longitude: -122.0090)
//static let DefaultAltitude = CLLocationDistance(integerLiteral: 0)
//static let DefaultSpeed = CLLocationSpeed(integerLiteral: 0)
//static let DefaultHeading = CLLocationDirection(integerLiteral: 0)
static var currentLocation: CLLocation {
@ -72,12 +69,12 @@ class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate {
}
// Extra Smart positioning logic throwing out bad readings from the phone GPS
let age = -mostRecentLocation.timestamp.timeIntervalSinceNow
print("Location: HA-\(mostRecentLocation.horizontalAccuracy) VA-\(mostRecentLocation.verticalAccuracy) AGE-\(age)")
manager.stopUpdatingLocation()
if age > 10 || mostRecentLocation.horizontalAccuracy < 0 || mostRecentLocation.horizontalAccuracy > 100 {
print("Bad Location: HA-\(mostRecentLocation.horizontalAccuracy) VA-\(mostRecentLocation.verticalAccuracy) AGE-\(age)")
manager.startUpdatingLocation()
} else {
print("Good Location: HA-\(mostRecentLocation.horizontalAccuracy) VA-\(mostRecentLocation.verticalAccuracy) AGE-\(age)")
lastLocation = mostRecentLocation
}
}

View file

@ -13,17 +13,18 @@ func degreesToRadians(_ number: Double) -> Double {
struct MapViewSwiftUI: UIViewRepresentable {
var onLongPress: (_ waypointCoordinate: CLLocationCoordinate2D) -> Void
var onWaypointEdit: (_ waypointId: Int ) -> Void
var onLongPress: ((CLLocationCoordinate2D) -> Void)
var onWaypointEdit: ((Int) -> Void)
let mapView = MKMapView()
// Parameters
let positions: [PositionEntity]
let waypoints: [WaypointEntity]
let mapViewType: MKMapType
let userTrackingMode: MKUserTrackingMode
let showNodeHistory: Bool
let showRouteLines: Bool
// User Defaults Values
@AppStorage("meshMapRecentering") private var recenter: Bool = false
@AppStorage("meshMapShowNodeHistory") private var showNodeHistory = false
@AppStorage("meshMapShowRouteLines") private var showRouteLines = false
// Offline Map Tiles
@AppStorage("lastUpdatedLocalMapFile") private var lastUpdatedLocalMapFile = 0
@State private var loadedLastUpdatedLocalMapFile = 0
@ -116,56 +117,50 @@ struct MapViewSwiftUI: UIViewRepresentable {
}
}
DispatchQueue.main.async {
let latest = positions
.filter { $0.latest == true }
.sorted { $0.nodePosition?.num ?? 0 > $1.nodePosition?.num ?? -1 }
let annotationCount = waypoints.count + (showNodeHistory ? positions.count : latest.count)
if annotationCount != mapView.annotations.count {
print("Annotation Count: \(annotationCount) Map Annotations: \(mapView.annotations.count)")
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotations(waypoints)
if showRouteLines {
// Remove all existing PolyLine Overlays
for overlay in mapView.overlays {
if overlay is MKPolyline {
mapView.removeOverlay(overlay)
}
}
var lineIndex = 0
for position in latest {
let nodePositions = positions.filter { $0.nodePosition?.num ?? 0 == position.nodePosition?.num ?? -1 }
let lineCoords = nodePositions.map ({
(position) -> CLLocationCoordinate2D in
return position.nodeCoordinate!
})
let polyline = MKPolyline(coordinates: lineCoords, count: nodePositions.count)
polyline.title = "\(String(position.nodePosition?.num ?? 0))"
mapView.addOverlay(polyline)
lineIndex += 1
// There are 18 colors for lines, start over if we are at index 17
if lineIndex > 17 {
lineIndex = 0
}
}
}
if userTrackingMode == MKUserTrackingMode.none {
mapView.showsUserLocation = false
mapView.addAnnotations(showNodeHistory ? positions : latest)
if recenter {
mapView.fit(annotations:showNodeHistory || showRouteLines ? positions : latest, andShow: false)
}
} else {
// Centering Done by tracking mode
mapView.addAnnotations(showNodeHistory ? positions : latest)
mapView.showsUserLocation = true
}
mapView.setUserTrackingMode(userTrackingMode, animated: true)
let latest = positions
.filter { $0.latest == true }
.sorted { $0.nodePosition?.num ?? 0 > $1.nodePosition?.num ?? -1 }
let annotationCount = waypoints.count + (showNodeHistory ? positions.count : latest.count)
print("Annotation Count: \(annotationCount) Map Annotations: \(mapView.annotations.count)")
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotations(waypoints)
mapView.addAnnotations(showNodeHistory ? positions : latest)
// Remove all existing PolyLine Overlays
for overlay in mapView.overlays {
if overlay is MKPolyline {
mapView.removeOverlay(overlay)
}
}
if showRouteLines {
var lineIndex = 0
for position in latest {
let nodePositions = positions.filter { $0.nodePosition?.num ?? 0 == position.nodePosition?.num ?? -1 }
let lineCoords = nodePositions.map ({
(position) -> CLLocationCoordinate2D in
return position.nodeCoordinate!
})
let polyline = MKPolyline(coordinates: lineCoords, count: nodePositions.count)
polyline.title = "\(String(position.nodePosition?.num ?? 0))"
mapView.addOverlay(polyline)
lineIndex += 1
// There are 18 colors for lines, start over if we are at index 17
if lineIndex > 17 {
lineIndex = 0
}
}
}
if userTrackingMode == MKUserTrackingMode.none {
mapView.showsUserLocation = false
if recenter {
mapView.fit(annotations:showNodeHistory || showRouteLines ? positions : latest, andShow: false)
}
} else {
// Centering Done by tracking mode
mapView.showsUserLocation = true
}
mapView.setUserTrackingMode(userTrackingMode, animated: true)
}
func makeCoordinator() -> MapCoordinator {
@ -181,9 +176,6 @@ struct MapViewSwiftUI: UIViewRepresentable {
self.parent = parent
super.init()
self.longPressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPressHandler))
self.longPressRecognizer.minimumPressDuration = 0.5
self.longPressRecognizer.cancelsTouchesInView = true
self.longPressRecognizer.delegate = self
self.parent.mapView.addGestureRecognizer(longPressRecognizer)
}
@ -326,23 +318,20 @@ struct MapViewSwiftUI: UIViewRepresentable {
}
}
@objc func longPressHandler(_ gesture: UILongPressGestureRecognizer) {
@objc func longPressHandler(_ sender: UILongPressGestureRecognizer) {
if gesture.state != UIGestureRecognizer.State.ended {
return
} else if gesture.state != UIGestureRecognizer.State.began {
// Screen Position - CGPoint
let location = longPressRecognizer.location(in: self.parent.mapView)
// Map Coordinate - CLLocationCoordinate2D
let coordinate = self.parent.mapView.convert(location, toCoordinateFrom: self.parent.mapView)
let annotation = MKPointAnnotation()
annotation.title = "Dropped Pin"
annotation.coordinate = coordinate
parent.mapView.addAnnotation(annotation)
UINotificationFeedbackGenerator().notificationOccurred(.success)
parent.onLongPress(coordinate)
if sender.state == .began {
let point = sender.location(in: sender.view)
if let mapView = sender.view as? MKMapView {
let coordinate = mapView.convert(point, toCoordinateFrom: mapView)
let annotation = MKPointAnnotation()
print("Handler Coord - \(coordinate)")
annotation.title = "Dropped Pin"
annotation.coordinate = coordinate
parent.mapView.addAnnotation(annotation)
UINotificationFeedbackGenerator().notificationOccurred(.success)
parent.onLongPress(coordinate)
}
}
}

View file

@ -12,8 +12,7 @@ struct WaypointFormView: View {
@EnvironmentObject var bleManager: BLEManager
@Environment(\.dismiss) private var dismiss
@State var coordinate: CLLocationCoordinate2D
@State var waypointId: Int = 0
@State var coordinate: WaypointCoordinate
@FocusState private var iconIsFocused: Bool
@ -23,21 +22,21 @@ struct WaypointFormView: View {
@State private var latitude: Double = 0
@State private var longitude: Double = 0
@State private var expires: Bool = false
@State private var expire: Date = Date() // = Date.now.addingTimeInterval(60 * 120) // 1 minute * 120 = 2 Hours
@State private var expire: Date = Date.now.addingTimeInterval(60 * 480) // 1 minute * 480 = 8 Hours
@State private var locked: Bool = false
@State private var lockedTo: Int64 = 0
var body: some View {
Form {
let distance = CLLocation(latitude: LocationHelper.currentLocation.coordinate.latitude, longitude: LocationHelper.currentLocation.coordinate.longitude).distance(from: CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude))
Section(header: Text((waypointId > 0) ? "Editing Waypoint" : "Create Waypoint")) {
let distance = CLLocation(latitude: LocationHelper.currentLocation.coordinate.latitude, longitude: LocationHelper.currentLocation.coordinate.longitude).distance(from: CLLocation(latitude: coordinate.coordinate?.latitude ?? 0, longitude: coordinate.coordinate?.longitude ?? 0))
Section(header: Text((coordinate.waypointId > 0) ? "Editing Waypoint" : "Create Waypoint")) {
HStack {
Text("Location: \(String(format: "%.5f", latitude) + "," + String(format: "%.5f", longitude))")
.textSelection(.enabled)
.foregroundColor(Color.gray)
.font(.caption2)
if coordinate.latitude != LocationHelper.DefaultLocation.coordinate.latitude && coordinate.longitude != LocationHelper.DefaultLocation.coordinate.longitude {
if coordinate.coordinate?.latitude ?? -1 != LocationHelper.DefaultLocation.coordinate.latitude && coordinate.coordinate?.longitude ?? 0 != LocationHelper.DefaultLocation.coordinate.longitude {
DistanceText(meters: distance)
.foregroundColor(Color.gray)
.font(.caption2)
@ -128,16 +127,20 @@ struct WaypointFormView: View {
Button {
var newWaypoint = Waypoint()
if waypointId > 0 {
newWaypoint.id = UInt32(waypointId)
if coordinate.waypointId > 0 {
newWaypoint.id = UInt32(coordinate.waypointId)
let waypoint = getWaypoint(id: Int64(coordinate.waypointId), context: bleManager.context!)
newWaypoint.latitudeI = waypoint.latitudeI
newWaypoint.longitudeI = waypoint.longitudeI
} else {
newWaypoint.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
newWaypoint.latitudeI = Int32(Double(coordinate.coordinate?.latitude ?? 0) * 1e7)
newWaypoint.longitudeI = Int32(Double(coordinate.coordinate?.longitude ?? 0) * 1e7)
}
newWaypoint.name = name.count > 0 ? name : "Dropped Pin"
newWaypoint.description_p = description
newWaypoint.latitudeI = Int32(coordinate.latitude * 1e7)
newWaypoint.longitudeI = Int32(coordinate.longitude * 1e7)
// Unicode scalar value for the icon emoji string
let unicodeScalers = icon.unicodeScalars
// First element as an UInt32
@ -157,10 +160,8 @@ struct WaypointFormView: View {
newWaypoint.expire = 0
}
if bleManager.sendWaypoint(waypoint: newWaypoint) {
waypointId = 0
dismiss()
} else {
waypointId = 0
dismiss()
print("Send waypoint failed")
}
@ -183,11 +184,11 @@ struct WaypointFormView: View {
.controlSize(.large)
.padding(.bottom)
if waypointId > 0 {
if coordinate.waypointId > 0 {
Menu {
Button("For me", action: {
let waypoint = getWaypoint(id: Int64(waypointId), context: bleManager.context!)
let waypoint = getWaypoint(id: Int64(coordinate.waypointId), context: bleManager.context!)
bleManager.context!.delete(waypoint)
do {
try bleManager.context!.save()
@ -198,13 +199,13 @@ struct WaypointFormView: View {
Button("For everyone", action: {
var newWaypoint = Waypoint()
if waypointId > 0 {
newWaypoint.id = UInt32(waypointId)
if coordinate.waypointId > 0 {
newWaypoint.id = UInt32(coordinate.waypointId)
}
newWaypoint.name = name.count > 0 ? name : "Dropped Pin"
newWaypoint.description_p = description
newWaypoint.latitudeI = Int32(coordinate.latitude * 1e7)
newWaypoint.longitudeI = Int32(coordinate.longitude * 1e7)
newWaypoint.latitudeI = Int32(coordinate.coordinate?.latitude ?? 0 * 1e7)
newWaypoint.longitudeI = Int32(coordinate.coordinate?.longitude ?? 0 * 1e7)
// Unicode scalar value for the icon emoji string
let unicodeScalers = icon.unicodeScalars
// First element as an UInt32
@ -220,10 +221,8 @@ struct WaypointFormView: View {
}
newWaypoint.expire = 1
if bleManager.sendWaypoint(waypoint: newWaypoint) {
waypointId = 0
dismiss()
} else {
waypointId = 0
dismiss()
print("Send waypoint failed")
}
@ -239,14 +238,9 @@ struct WaypointFormView: View {
.padding(.bottom)
}
}
.onChange(of: waypointId) { newId in
print(newId)
}
.onAppear {
if waypointId > 0 {
let waypoint = getWaypoint(id: Int64(waypointId), context: bleManager.context!)
waypointId = Int(waypoint.id)
if coordinate.waypointId > 0 {
let waypoint = getWaypoint(id: Int64(coordinate.waypointId), context: bleManager.context!)
name = waypoint.name ?? "Dropped Pin"
description = waypoint.longDescription ?? ""
icon = String(UnicodeScalar(Int(waypoint.icon)) ?? "📍")
@ -269,8 +263,8 @@ struct WaypointFormView: View {
expires = false
expire = Date.now.addingTimeInterval(60 * 120)
icon = "📍"
latitude = coordinate.latitude
longitude = coordinate.longitude
latitude = coordinate.coordinate?.latitude ?? 0
longitude = coordinate.coordinate?.longitude ?? 0
}
}
}

View file

@ -14,11 +14,8 @@ struct NodeDetail: View {
@EnvironmentObject var bleManager: BLEManager
@Environment(\.colorScheme) var colorScheme: ColorScheme
@AppStorage("meshMapType") private var meshMapType = "standard"
@AppStorage("meshMapShowNodeHistory") private var meshMapShowNodeHistory = false
@AppStorage("meshMapShowRouteLines") private var meshMapShowRouteLines = false
@State private var mapType: MKMapType = .standard
@State var waypointCoordinate: CLLocationCoordinate2D?
@State var editingWaypoint: Int = 0
@State var waypointCoordinate: WaypointCoordinate?
@State private var loadedWeather: Bool = false
@State private var showingDetailsPopover = false
@State private var showingForecast = false
@ -64,19 +61,14 @@ struct NodeDetail: View {
// let todaysPositions = positionArray.filter { $0.time! >= Calendar.current.startOfDay(for: Date()) }
ZStack {
MapViewSwiftUI(onLongPress: { coord in
waypointCoordinate = coord
editingWaypoint = 0
presentingWaypointForm = true
waypointCoordinate = WaypointCoordinate(id: .init(), coordinate: coord, waypointId: 0)
}, onWaypointEdit: { wpId in
if wpId > 0 {
editingWaypoint = wpId
presentingWaypointForm = true
waypointCoordinate = WaypointCoordinate(id: .init(), coordinate: nil, waypointId: Int64(wpId))
}
}, positions: lastTenThousand, waypoints: Array(waypoints),
mapViewType: mapType,
userTrackingMode: MKUserTrackingMode.none,
showNodeHistory: meshMapShowNodeHistory,
showRouteLines: meshMapShowRouteLines,
customMapOverlay: self.customMapOverlay
)
VStack(alignment: .leading) {
@ -210,11 +202,11 @@ struct NodeDetail: View {
}
}
.edgesIgnoringSafeArea([.leading, .trailing])
.sheet(isPresented: $presentingWaypointForm ) {// , onDismiss: didDismissSheet) {
WaypointFormView(coordinate: waypointCoordinate ?? LocationHelper.DefaultLocation.coordinate, waypointId: editingWaypoint)
.presentationDetents([.medium, .large])
.presentationDragIndicator(.automatic)
}
.sheet(item: $waypointCoordinate, content: { wpc in
WaypointFormView(coordinate: wpc)
.presentationDetents([.medium, .large])
.presentationDragIndicator(.automatic)
})
.navigationBarTitle(String(node.user?.longName ?? NSLocalizedString("unknown", comment: "")), displayMode: .inline)
.navigationBarItems(trailing:
ZStack {

View file

@ -10,6 +10,14 @@ import MapKit
import CoreLocation
import CoreData
// A simple struct with waypoint data
struct WaypointCoordinate: Identifiable {
let id: UUID
let coordinate: CLLocationCoordinate2D?
let waypointId: Int64
}
struct NodeMap: View {
@Environment(\.managedObjectContext) var context
@ -31,8 +39,6 @@ struct NodeMap: View {
}
@AppStorage("meshMapType") private var meshMapType = "hybridFlyover"
@AppStorage("meshMapUserTrackingMode") private var meshMapUserTrackingMode = 0
@AppStorage("meshMapShowNodeHistory") private var meshMapShowNodeHistory = false
@AppStorage("meshMapShowRouteLines") private var meshMapShowRouteLines = false
@FetchRequest(sortDescriptors: [NSSortDescriptor(key: "time", ascending: true)],
predicate: NSPredicate(format: "time >= %@ && nodePosition != nil", Calendar.current.startOfDay(for: Date()) as NSDate), animation: .none)
@ -46,9 +52,7 @@ struct NodeMap: View {
@State private var mapType: MKMapType = .standard
@State private var userTrackingMode: MKUserTrackingMode = .none
@State var waypointCoordinate: CLLocationCoordinate2D = LocationHelper.DefaultLocation.coordinate
@State var editingWaypoint: Int = 0
@State private var presentingWaypointForm = false
@State var waypointCoordinate: WaypointCoordinate?
@State private var customMapOverlay: MapViewSwiftUI.CustomMapOverlay? = MapViewSwiftUI.CustomMapOverlay(
mapName: "offlinemap",
tileType: "png",
@ -60,25 +64,17 @@ struct NodeMap: View {
NavigationStack {
ZStack {
MapViewSwiftUI(onLongPress: { coord in
waypointCoordinate = coord
editingWaypoint = 0
if waypointCoordinate.distance(from: LocationHelper.DefaultLocation.coordinate) == 0.0 {
print("Apple Park")
} else {
presentingWaypointForm = true
}
MapViewSwiftUI(
onLongPress: { coord in
waypointCoordinate = WaypointCoordinate(id: .init(), coordinate: coord, waypointId: 0)
}, onWaypointEdit: { wpId in
if wpId > 0 {
editingWaypoint = wpId
presentingWaypointForm = true
waypointCoordinate = WaypointCoordinate(id: .init(), coordinate: nil, waypointId: Int64(wpId))
}
}, positions: Array(positions),
waypoints: Array(waypoints),
mapViewType: mapType,
userTrackingMode: userTrackingMode,
showNodeHistory: meshMapShowNodeHistory,
showRouteLines: meshMapShowRouteLines,
customMapOverlay: self.customMapOverlay
)
VStack {
@ -95,12 +91,11 @@ struct NodeMap: View {
}
.ignoresSafeArea(.all, edges: [.top, .leading, .trailing])
.frame(maxHeight: .infinity)
.sheet(isPresented: $presentingWaypointForm ) {// , onDismiss: didDismissSheet) {
WaypointFormView(coordinate: waypointCoordinate, waypointId: editingWaypoint)
.sheet(item: $waypointCoordinate, content: { wpc in
WaypointFormView(coordinate: wpc)
.presentationDetents([.medium, .large])
.presentationDragIndicator(.automatic)
}
})
}
.navigationBarItems(leading:
MeshtasticLogo(), trailing:

View file

@ -43,28 +43,26 @@ struct AppSettings: View {
let accuracy = Measurement(value: locationHelper.lastLocation?.horizontalAccuracy ?? 300, unit: UnitLength.meters)
let altitiude = Measurement(value: locationHelper.lastLocation?.altitude ?? 0, unit: UnitLength.meters)
let speed = Measurement(value: locationHelper.lastLocation?.speed ?? 0, unit: UnitSpeed.kilometersPerHour)
Label("Coordinates \(String(format: "%.5f", locationHelper.lastLocation?.coordinate.latitude ?? 0)), \(String(format: "%.5f", locationHelper.lastLocation?.coordinate.longitude ?? 0))", systemImage: "mappin")
.textSelection(.enabled)
HStack {
Label("GPS Accuracy \(accuracy.formatted())", systemImage: "scope")
.font(.caption)
if LocationHelper.currentLocation.verticalAccuracy > 0 {
Label("Altitude \(altitiude.formatted())", systemImage: "mountain.2")
.font(.caption)
}
Label("Accuracy \(accuracy.formatted())", systemImage: "scope")
.font(.callout)
Label("Sats \(LocationHelper.satsInView)", systemImage: "sparkles")
.font(.callout)
}
if locationHelper.lastLocation?.courseAccuracy ?? 0 > 0 || locationHelper.lastLocation?.speedAccuracy ?? 0 > 0 {
HStack {
if locationHelper.lastLocation?.courseAccuracy ?? 0 > 0 {
Label("Heading \(String(format: "%.2f", locationHelper.lastLocation?.course ?? 0))°", systemImage: "location.circle")
.font(.caption)
}
if locationHelper.lastLocation?.speedAccuracy ?? 0 > 0 {
Label("Speed \(speed.formatted())", systemImage: "speedometer")
.font(.caption)
}
}
Label("Coordinates \(String(format: "%.5f", locationHelper.lastLocation?.coordinate.latitude ?? 0)), \(String(format: "%.5f", locationHelper.lastLocation?.coordinate.longitude ?? 0))", systemImage: "mappin")
.font(.callout)
.textSelection(.enabled)
if LocationHelper.currentLocation.verticalAccuracy > 0 {
Label("Altitude \(altitiude.formatted())", systemImage: "mountain.2")
.font(.callout)
}
if locationHelper.lastLocation?.courseAccuracy ?? 0 > 0 {
Label("Heading \(String(format: "%.2f", locationHelper.lastLocation?.course ?? 0))°", systemImage: "location.circle")
.font(.callout)
}
if locationHelper.lastLocation?.speedAccuracy ?? 0 > 0 {
Label("Speed \(speed.formatted())", systemImage: "speedometer")
.font(.callout)
}
Toggle(isOn: $userSettings.provideLocation) {

View file

@ -64,7 +64,7 @@ struct Settings: View {
}
.tag(SettingsSidebar.appSettings)
let node = nodes.first(where: { $0.num == connectedNodeNum })
if node?.myInfo?.adminIndex ?? 0 > 0 {
//if node?.myInfo?.adminIndex ?? 0 > 0 {
Section("Configure") {
Picker("Configuring Node", selection: $selectedNode) {
if selectedNode == 0 {
@ -83,7 +83,7 @@ struct Settings: View {
}
}
}
.pickerStyle(.menu)
.pickerStyle(.automatic)
.labelsHidden()
.onChange(of: selectedNode) { newValue in
if selectedNode > 0 {
@ -101,7 +101,7 @@ struct Settings: View {
}
}
}
}
//}
Section("radio.configuration") {