From f060e58e35b1b3020d8611ed0635fd51fbc5ad75 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Sat, 27 Sep 2025 06:52:54 -0700 Subject: [PATCH] Clean up mesh map fetch request and distance filter logic --- Meshtastic/Enums/AppSettingsEnums.swift | 1 - .../CoreData/PositionEntityExtension.swift | 59 +++++++++++-------- .../Nodes/Helpers/Map/MapSettingsForm.swift | 22 +++---- 3 files changed, 47 insertions(+), 35 deletions(-) diff --git a/Meshtastic/Enums/AppSettingsEnums.swift b/Meshtastic/Enums/AppSettingsEnums.swift index 7be3a1ae..b67598e8 100644 --- a/Meshtastic/Enums/AppSettingsEnums.swift +++ b/Meshtastic/Enums/AppSettingsEnums.swift @@ -62,7 +62,6 @@ enum MeshMapDistances: Double, CaseIterable, Identifiable { case oneThousandMiles = 1609000 case fifteenHundredMiles = 2414016 case twentyFiveHundredMiles = 4023360 - case fiveThouandMiles = 8046720 var id: Double { self.rawValue } var description: String { let distanceFormatter = MKDistanceFormatter() diff --git a/Meshtastic/Extensions/CoreData/PositionEntityExtension.swift b/Meshtastic/Extensions/CoreData/PositionEntityExtension.swift index 3c7ec96c..3efa9af3 100644 --- a/Meshtastic/Extensions/CoreData/PositionEntityExtension.swift +++ b/Meshtastic/Extensions/CoreData/PositionEntityExtension.swift @@ -13,33 +13,44 @@ import SwiftUI extension PositionEntity { - @MainActor static func allPositionsFetchRequest() -> NSFetchRequest { - let request: NSFetchRequest = PositionEntity.fetchRequest() - request.fetchLimit = 1000 - request.returnsObjectsAsFaults = false - request.includesSubentities = true - request.returnsDistinctResults = true - request.sortDescriptors = [NSSortDescriptor(key: "time", ascending: false)] - let positionPredicate = NSPredicate(format: "nodePosition != nil && (nodePosition.user.shortName != nil || nodePosition.user.shortName != '') && latest == true") + @MainActor + static func allPositionsFetchRequest() -> NSFetchRequest { - if let pointOfInterest = LocationsHandler.currentLocation { + let request: NSFetchRequest = PositionEntity.fetchRequest() + request.sortDescriptors = [NSSortDescriptor(key: "time", ascending: false)] + let positionPredicate = NSPredicate(format: "nodePosition != nil AND nodePosition.user != nil AND latest == true AND nodePosition.user.shortName != ''") + request.predicate = positionPredicate + + // Distance Predicate + if let cl = LocationsHandler.currentLocation { - if pointOfInterest.latitude != LocationsHandler.DefaultLocation.latitude && pointOfInterest.longitude != LocationsHandler.DefaultLocation.longitude { - let d: Double = UserDefaults.meshMapDistance * 1.1 - let r: Double = 6371009 - let meanLatitidue = pointOfInterest.latitude * .pi / 180 - let deltaLatitude = d / r * 180 / .pi - let deltaLongitude = d / (r * cos(meanLatitidue)) * 180 / .pi - let minLatitude: Double = pointOfInterest.latitude - deltaLatitude - let maxLatitude: Double = pointOfInterest.latitude + deltaLatitude - let minLongitude: Double = pointOfInterest.longitude - deltaLongitude - let maxLongitude: Double = pointOfInterest.longitude + deltaLongitude - let distancePredicate = NSPredicate(format: "(%lf <= (longitudeI / 1e7)) AND ((longitudeI / 1e7) <= %lf) AND (%lf <= (latitudeI / 1e7)) AND ((latitudeI / 1e7) <= %lf)", minLongitude, maxLongitude, minLatitude, maxLatitude) - request.predicate = NSCompoundPredicate(type: .and, subpredicates: [positionPredicate, distancePredicate]) - } else { - request.predicate = positionPredicate - } + let d: Double = UserDefaults.meshMapDistance * 1.1 + let r: Double = 6371009 // Earth's mean radius in meters + + // Calculate Bounding Box + let meanLatitidue = cl.latitude * .pi / 180 + let deltaLatitude = d / r * 180 / .pi + let deltaLongitude = d / (r * cos(meanLatitidue)) * 180 / .pi + + let minLatitude: Double = cl.latitude - deltaLatitude + let maxLatitude: Double = cl.latitude + deltaLatitude + let minLongitude: Double = cl.longitude - deltaLongitude + let maxLongitude: Double = cl.longitude + deltaLongitude + + // Scale bounding box values by 1e7 and use integer attributes (longitudeI, latitudeI) + let scale: Double = 1e7 + let minLongitudeI = Int(minLongitude * scale) + let maxLongitudeI = Int(maxLongitude * scale) + let minLatitudeI = Int(minLatitude * scale) + let maxLatitudeI = Int(maxLatitude * scale) + + // Use integer comparison in the predicate + let distancePredicate = NSPredicate(format: "(%ld <= longitudeI) AND (longitudeI <= %ld) AND (%ld <= latitudeI) AND (latitudeI <= %ld)", + minLongitudeI, maxLongitudeI, minLatitudeI, maxLatitudeI) + + request.predicate = NSCompoundPredicate(type: .and, subpredicates: [positionPredicate, distancePredicate]) } + return request } var latitude: Double? { diff --git a/Meshtastic/Views/Nodes/Helpers/Map/MapSettingsForm.swift b/Meshtastic/Views/Nodes/Helpers/Map/MapSettingsForm.swift index baa2f919..a8b8f464 100644 --- a/Meshtastic/Views/Nodes/Helpers/Map/MapSettingsForm.swift +++ b/Meshtastic/Views/Nodes/Helpers/Map/MapSettingsForm.swift @@ -45,18 +45,20 @@ struct MapSettingsForm: View { UserDefaults.mapLayer = newMapLayer } if meshMap { - HStack { - Label("Show nodes", systemImage: "lines.measurement.horizontal") - Picker("", selection: $meshMapDistance) { - ForEach(MeshMapDistances.allCases) { di in - Text(di.description) - .tag(di.id) + if LocationsHandler.currentLocation != nil { + HStack { + Label("Show nodes", systemImage: "lines.measurement.horizontal") + Picker("", selection: $meshMapDistance) { + ForEach(MeshMapDistances.allCases) { di in + Text(di.description) + .tag(di.id) + } } + .pickerStyle(DefaultPickerStyle()) + } + .onChange(of: meshMapDistance) { _, newMeshMapDistance in + UserDefaults.meshMapDistance = newMeshMapDistance } - .pickerStyle(DefaultPickerStyle()) - } - .onChange(of: meshMapDistance) { _, newMeshMapDistance in - UserDefaults.meshMapDistance = newMeshMapDistance } Toggle(isOn: $enableMapWaypoints) { Label {