From 27dd2fea7e7999c30721b2ec90f146d48b726725 Mon Sep 17 00:00:00 2001 From: Daniel Grbac Bravo Date: Fri, 1 Mar 2024 17:59:12 +0100 Subject: [PATCH] feat: removed RoutePoint, using CLocationCoordinate2D instead. created Basic PolyLine of Route --- windrider-ios.xcodeproj/project.pbxproj | 4 +- windrider-ios/ContentView.swift | 6 +- windrider-ios/Route.swift | 98 +++++++++++++++---------- windrider-ios/RouteMapView.swift | 47 +++--------- windrider-ios/windrider_iosApp.swift | 3 +- 5 files changed, 76 insertions(+), 82 deletions(-) diff --git a/windrider-ios.xcodeproj/project.pbxproj b/windrider-ios.xcodeproj/project.pbxproj index 10877c6..9d4f901 100644 --- a/windrider-ios.xcodeproj/project.pbxproj +++ b/windrider-ios.xcodeproj/project.pbxproj @@ -105,14 +105,14 @@ isa = PBXGroup; children = ( 653CDEE52B909823000D4E8B /* windrider_iosApp.swift */, - 653CDEEB2B909825000D4E8B /* Assets.xcassets */, - 653CDEED2B909825000D4E8B /* Preview Content */, 655D4EAC2B90BAC5008B6B2B /* MapView.swift */, 655D4EAE2B90C072008B6B2B /* ConditionPreviewView.swift */, 655D4EB02B90C250008B6B2B /* WindCondition.swift */, 655D4EB22B90C4BD008B6B2B /* ContentView.swift */, 652D84302B9200B100AE8CCD /* RouteMapView.swift */, 652D84322B92019B00AE8CCD /* Route.swift */, + 653CDEEB2B909825000D4E8B /* Assets.xcassets */, + 653CDEED2B909825000D4E8B /* Preview Content */, ); path = "windrider-ios"; sourceTree = ""; diff --git a/windrider-ios/ContentView.swift b/windrider-ios/ContentView.swift index 734a76e..6691b12 100644 --- a/windrider-ios/ContentView.swift +++ b/windrider-ios/ContentView.swift @@ -9,8 +9,6 @@ import Foundation import SwiftUI struct ContentView: View { - var condition: WindCondition - let randomRoute = Route(points: [RoutePoint(latitude: 53.22240, longitude: 6.53929, direction: 0, timestamp: Date()), RoutePoint(latitude: 53.22240, longitude: 6.53929, direction: 0, timestamp: Date())]) var body: some View { ZStack{ RouteMapView(route: randomRoute) @@ -22,8 +20,6 @@ struct ContentView: View { struct ContentView_Previews: PreviewProvider { static var previews: some View { // Creating an example condition to use in our preview - let exampleCondition = WindCondition(direction: "NW", speed: 15.5, headwindPercentage: 60) - // Returning the view configured with the example condition - ContentView(condition: exampleCondition) + ContentView() } } diff --git a/windrider-ios/Route.swift b/windrider-ios/Route.swift index 1bd2266..3215253 100644 --- a/windrider-ios/Route.swift +++ b/windrider-ios/Route.swift @@ -6,56 +6,80 @@ // import Foundation +import CoreLocation +import MapKit +import SwiftUI struct Route: Codable { let routeId: String? - let points: [RoutePoint] + let points: [CLLocationCoordinate2D] - init(points: [RoutePoint]) { - self.routeId = nil + + init(routeId: String? = nil, points: [CLLocationCoordinate2D]) { + self.routeId = routeId self.points = points } - // finds the bounding box of the route - // returns the two points that define the bounding box - public func caluateBoundingBox(route: Route) -> [RoutePoint]{ - var minLat: Double = 90 - var maxLat: Double = -90 - var minLon: Double = 180 - var maxLon: Double = -180 - for point in route.points { - if point.latitude < minLat { - minLat = point.latitude - } - if point.latitude > maxLat { - maxLat = point.latitude - } - if point.longitude < minLon { - minLon = point.longitude - } - if point.longitude > maxLon { - maxLon = point.longitude - } + func calcuateCenterCoordinate() -> CLLocationCoordinate2D { + var maxLat: CLLocationDegrees = -90 + var maxLon: CLLocationDegrees = -180 + var minLat: CLLocationDegrees = 90 + var minLon: CLLocationDegrees = 180 + + for coordinate in points { + let lat = Double(coordinate.latitude) + let long = Double(coordinate.longitude) + + maxLat = max(maxLat, lat) + maxLon = max(maxLon, long) + minLat = min(minLat, lat) + minLon = min(minLon, long) } - return [RoutePoint(latitude: minLat, longitude: minLon, direction: 0, timestamp: Date()), RoutePoint(latitude: maxLat, longitude: maxLon, direction: 0, timestamp: Date())] + + let center = CLLocationCoordinate2D(latitude: (minLat + maxLat) / 2, longitude: (minLon + maxLon) / 2) + return center } -} - + // CodingKeys enum to map the properties to the JSON keys + // everything below is for Codable conformance + enum CodingKeys: String, CodingKey { + case routeId + case points + } -struct RoutePoint: Codable { - let latitude: Double - let longitude: Double - let direction: Double - let timestamp: Date + // Custom initializer from Decoder + init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + routeId = try container.decodeIfPresent(String.self, forKey: .routeId) + + var pointsArrayForInit = [CLLocationCoordinate2D]() + var pointsContainer = try container.nestedUnkeyedContainer(forKey: .points) + while !pointsContainer.isAtEnd { + let point = try pointsContainer.decode(Point.self) + let coordinate = CLLocationCoordinate2D(latitude: point.latitude, longitude: point.longitude) + pointsArrayForInit.append(coordinate) + } + points = pointsArrayForInit + } - init(latitude: Double, longitude: Double, direction: Double, timestamp: Date) { - self.latitude = latitude - self.longitude = longitude - self.direction = direction - self.timestamp = timestamp + // Custom encoder + func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(routeId, forKey: .routeId) + + var pointsContainer = container.nestedUnkeyedContainer(forKey: .points) + for point in points { + let pointToEncode = Point(latitude: point.latitude, longitude: point.longitude) + try pointsContainer.encode(pointToEncode) + } + + } + + // Helper struct to decode/encode CLLocationCoordinate2D since it's not directly Codable + private struct Point: Codable { + let latitude: CLLocationDegrees + let longitude: CLLocationDegrees } } - diff --git a/windrider-ios/RouteMapView.swift b/windrider-ios/RouteMapView.swift index a08082b..ed341f6 100644 --- a/windrider-ios/RouteMapView.swift +++ b/windrider-ios/RouteMapView.swift @@ -6,37 +6,17 @@ // import SwiftUI +import CoreLocation import MapKit -func calculateRegion(boundingBox: [RoutePoint]) -> MKCoordinateRegion { - let minLat = boundingBox[0].latitude - let maxLat = boundingBox[1].latitude - let minLon = boundingBox[0].longitude - let maxLon = boundingBox[1].longitude - - let center = CLLocationCoordinate2D(latitude: (minLat + maxLat) / 2, longitude: (minLon + maxLon) / 2) - let span = MKCoordinateSpan(latitudeDelta: (maxLat - minLat) * 1.1, longitudeDelta: (maxLon - minLon) * 1.1) - - return MKCoordinateRegion(center: center, span: span) -} - - - struct RouteMapView: View { var route: Route - @State private var region: MKCoordinateRegion - - init(route: Route) { - self.route = route - let boundingBox = route.caluateBoundingBox(route: route) // Assuming this is a correct method call - self._region = State(initialValue: calculateRegion(boundingBox: boundingBox)) - } - + var body: some View { ZStack{ - Map(){ - + Map{ + MapPolyline(coordinates: route.points, contourStyle: .geodesic).stroke(lineWidth: 3).stroke(Color.purple) } .ignoresSafeArea() @@ -44,20 +24,15 @@ struct RouteMapView: View { } } - +let randomRoute = Route(points: [CLLocationCoordinate2D(latitude: 53.22207, longitude: 6.53912), + CLLocationCoordinate2D(latitude: 53.22139, longitude: 6.53978), + CLLocationCoordinate2D(latitude: 53.22170, longitude: 6.54061), + CLLocationCoordinate2D(latitude: 53.22137, longitude: 6.54112), + CLLocationCoordinate2D(latitude: 53.22163, longitude: 6.54163), + CLLocationCoordinate2D(latitude: 53.22187, longitude: 6.54117) + ]) struct RouteMapView_Previews: PreviewProvider { - static func createRandomRoute() -> Route { - var points = [RoutePoint]() - for _ in 0...100 { - points.append(RoutePoint(latitude: Double.random(in: 53.0...54.0), longitude: Double.random(in: 6.0...7.0), direction: Double.random(in: 0...360), timestamp: Date())) - } - return Route(points: points) - } - static var previews: some View { - // Now this call is valid because createRandomRoute is a static method - let randomRoute = createRandomRoute() - RouteMapView(route: randomRoute) } } diff --git a/windrider-ios/windrider_iosApp.swift b/windrider-ios/windrider_iosApp.swift index 955de14..220dcfd 100644 --- a/windrider-ios/windrider_iosApp.swift +++ b/windrider-ios/windrider_iosApp.swift @@ -10,10 +10,9 @@ import SwiftData @main struct WindRider_App: App { - let exampleCondition = WindCondition(direction: "NW", speed: 10, headwindPercentage: 12) var body: some Scene { WindowGroup { - ContentView(condition:exampleCondition) + ContentView() } } }