日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

孩子喜歡飛機,于是我給她做了一個雷達

來源: 責編: 時間:2023-11-28 17:12:13 242觀看
導讀今年夏天,我計劃帶著我的孩子出國。她很興奮。在此之前,我和妻子決定大肆宣傳一下這次的飛行之旅,主要是為了確保女兒能安穩地度過3小時的飛行時間??赡苁俏覀冃麄饔悬c過頭了,以至于當我們不得不坐出租車去機場時,我蹣跚

今年夏天,我計劃帶著我的孩子出國。uPZ28資訊網——每日最新資訊28at.com

她很興奮。uPZ28資訊網——每日最新資訊28at.com

在此之前,我和妻子決定大肆宣傳一下這次的飛行之旅,主要是為了確保女兒能安穩地度過3小時的飛行時間。uPZ28資訊網——每日最新資訊28at.com

可能是我們宣傳有點過頭了,以至于當我們不得不坐出租車去機場時,我蹣跚學步的孩子感到震驚——她原本以為會從我們家直接走上飛機。uPZ28資訊網——每日最新資訊28at.com

我們登機后,發生了一件令人難以置信的事情。uPZ28資訊網——每日最新資訊28at.com

原來,當機組人員發現你和一個癡迷于飛機的可愛小孩在一起時,他們會邀請你們去看看駕駛艙。uPZ28資訊網——每日最新資訊28at.com

這激發了我女兒對飛機的癡迷。uPZ28資訊網——每日最新資訊28at.com

從那之后,她一直要求我在天上為她尋找飛機,當我為她找到一架飛機時,她很高興。uPZ28資訊網——每日最新資訊28at.com

上周,我們在花園里待了一個小時,她坐在我的肩上,看著飛機一架接一架地在夜空中閃爍。uPZ28資訊網——每日最新資訊28at.com

后來我找到了FlightRadar24,它能顯示覆蓋在地圖上的飛機位置,但美中不足的是,我必須自己調整方向。uPZ28資訊網——每日最新資訊28at.com

圖片uPZ28資訊網——每日最新資訊28at.com

但是,對于一個孩子來說,她可能并不真正理解或關心地圖是什么。uPZ28資訊網——每日最新資訊28at.com

所以我們有了繼續解決的新問題,比如方向,比如可用性。uPZ28資訊網——每日最新資訊28at.com

作為一名非物理移動技術主管,我確實不知道從哪里開始為孩子打造一匹搖馬,但沒有什么能阻止我把這個想法變成一個很酷的應用程序。uPZ28資訊網——每日最新資訊28at.com

在雷達上顯示附近的航班

通過研究制定的要求:uPZ28資訊網——每日最新資訊28at.com

  • 該應用程序需要保持正確的方向,隨設備旋轉,以便顯示飛機的正確方向。
  • 該應用程序必須根據飛機的高度將飛機圖標顯示為更大或更小。
  • 該應用程序必須很有趣,要有一種復古兒童玩具的感覺,而不是嚴肅的商業應用程序。

這些要求導致了一些構成概念驗證的活動部分:uPZ28資訊網——每日最新資訊28at.com

  • 保持方向是差異化產品的核心要求,因為現有解決方案缺少這一點。我不關心詳細的航班信息,我只是想制作一個很酷的雷達。iOS 核心位置API已被涵蓋,每次用戶重新調整設備方向時都會提供委托回調。
  • 最重要的組件是Flight Data API。OpenSky Network正是我所需要的。一個簡單的REST API,免費供非商業用途,包含某個區域的航班實時數據。我們希望每隔幾秒就對這個端點執行操作,以進行真實的雷達掃描。
  • 為了調用 API,還需要一些位置數據。Core Location可供查詢距用戶位置+/-1度的緯度,精度為0.1度(約10公里),以確保用戶的位置足夠模糊。我們也只需要在每個會話中獲取一次該數據。
  • 最后,我們需要重新掌握三角學技能,將飛行位置數據與我們自己的定向坐標進行比較。這將使我們能夠根據附近的飛機在天空中與我們的相對位置,將其繪制到屏幕上的正確位置。

概念驗證

對于圖標,我選擇了一幅女兒戴著可愛飛行員帽的卡通畫。所以我們已經有了應用程序名稱:Aviator。uPZ28資訊網——每日最新資訊28at.com

方向

第一個關鍵差異化產品要求是保持方向。uPZ28資訊網——每日最新資訊28at.com

為了使用便利,屏幕上的對象需要與其現實生活中的位置相對應。因此,當用戶旋轉時,屏幕本身也會旋轉并保持指向北。uPZ28資訊網——每日最新資訊28at.com

final class LocationManager: CLLocationManager, CLLocationManagerDelegate {            static let shared = LocationManager()        private(set) var rotationAngleSubject = CurrentValueSubject<Double, Never>(0)        override private init() {        super.init()        requestWhenInUseAuthorization()        delegate = self        startUpdatingHeading()    }        func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {        rotationAngleSubject.send(-newHeading.magneticHeading)    }}

同時,為了獲得好看的指南針效果,我還繪制了一組隨旋轉角度變化的矩形。uPZ28資訊網——每日最新資訊28at.com

@State private var rotationAngle: Angle = .degrees(0)var body: some View {    ZStack {        ForEach(0..<36) {            let angle = Angle.degrees(Double($0 * 10)) + rotationAngle            Rectangle()                .frame(width: $0 == 0 ? 16 : 8, height: $0 == 0 ? 3 : 2)                .foregroundColor($0 == 0 ? .red : .blue)                .rotationEffect(angle)                .offset(x: 120 * cos(CGFloat(angle.radians)), y: 120 * sin(CGFloat(angle.radians)))                .animation(.bouncy, value: rotationAngle)        }    }    .onReceive(LocationManager.shared.rotationAngleSubject) { angle in        rotationAngle = Angle.degrees(angle)    }}

看起來相當不錯,而且也完美地響應了我的真實位置。uPZ28資訊網——每日最新資訊28at.com

圖片uPZ28資訊網——每日最新資訊28at.com

可能你會注意到一個有趣的視覺故障,因為動畫邏輯將0度和360度視為單獨的數字——當我經過正北時,所有矩形都會旋轉。uPZ28資訊網——每日最新資訊28at.com

航班數據

熱身結束,接下來是重要的部分。uPZ28資訊網——每日最新資訊28at.com

OpenSky Network API允許用戶給定一系列緯度和經度,通過一個簡單的請求返回該范圍內的本地航班數組。這意味著,只需將其粘貼到瀏覽器中,即可找出我可以看到的頭頂上空的航班數據。uPZ28資訊網——每日最新資訊28at.com

REST API記錄良好,但數據按順序顯示為列表屬性。uPZ28資訊網——每日最新資訊28at.com

圖片uPZ28資訊網——每日最新資訊28at.com

我們需要去解碼它,讓其按順序從JSON響應中解析出字段。uPZ28資訊網——每日最新資訊28at.com

struct Flight: Decodable {    let icao24: String     let callsign: String?    let origin_country: String?     let time_position: Int?    let last_contact: Int    let longitude: Double    let latitude: Double    // ...     init(from decoder: Decoder) throws {        var container = try decoder.unkeyedContainer()        icao24 = try container.decode(String.self)        callsign = try? container.decode(String?.self)        origin_country = try container.decode(String.self)        time_position = try? container.decode(Int?.self)        last_contact = try container.decode(Int.self)        longitude = try container.decode(Double.self)        latitude = try container.decode(Double.self)        // ...    }}

我們還可以編寫一個簡單的API,根據用戶的位置坐標執行請求。uPZ28資訊網——每日最新資訊28at.com

final class FlightAPI {        func fetchLocalFlightData(coordinate: CLLocationCoordinate2D) async throws -> [Flight] {                let lamin = String(format: "%.1f", coordinate.latitude - 0.25)        let lamax = String(format: "%.1f", coordinate.latitude + 0.25)        let lomin = String(format: "%.1f", coordinate.longitude - 0.5)        let lomax = String(format: "%.1f", coordinate.longitude + 0.5)        let url = URL(string: "https://opensky-network.org/api/states/all?lamin=/(lamin)&lamax=/(lamax)&lomin=/(lomin)&lomax=/(lomax)")!        let data = try await URLSession.shared.data(from: url).0        return try JSONDecoder().decode([Flight].self, from: data)    }}

這樣飛行數據就被很好地解析為內存中對象的數組,也變得易于處理。uPZ28資訊網——每日最新資訊28at.com

初步結果

如何實際測試飛機圖紙的準確性?uPZ28資訊網——每日最新資訊28at.com

我們可以在這些所有東西下面畫一張地圖:AviatorView頂部的指南針,繪制到屏幕上的飛機,以及樸素的SwiftUI視圖。uPZ28資訊網——每日最新資訊28at.com

@State private var cameraPosition: MapCameraPosition = .camera(MapCamera(        centerCoordinate: CLLocationCoordinate2D(latitude: 51.0, longitude: 0.0),        distance: 100_000,        heading: 0))var body: some View {    ZStack {        Map(position: $cameraPosition) { }         airplanes        compass    }}

這是我第一次熬夜跑出來的結果,與作為事實來源的FlightRadar進行比較。uPZ28資訊網——每日最新資訊28at.com

圖片uPZ28資訊網——每日最新資訊28at.com

可以看到,天空中飛機的數量和集群看起來都差不多,但位置卻相差甚遠。忽然,我靈光一閃,原來還需要使用注釋在地圖上繪制飛機。uPZ28資訊網——每日最新資訊28at.com

MVP

這個想法我已經醞釀了一整天:我們使用地圖,然后在其精確地理位置的頂部繪制飛機形狀的注釋,最終,我想找到一種方法來隱藏實際地圖,并僅將飛機顯示為雷達位置上的標記。uPZ28資訊網——每日最新資訊28at.com

這應該會給我們帶來我們想要的很酷的、完全定向的雷達效果。uPZ28資訊網——每日最新資訊28at.com

地圖注釋

在iOS 17中,在地圖上繪制注釋非常簡單。uPZ28資訊網——每日最新資訊28at.com

import MapKitimport SwiftUIstruct FlightMapView: View {        @Binding var cameraPosition: MapCameraPosition        let flights: [Flight]    var body: some View {        Map(position: $cameraPosition) {            planeMapAnnotations        }        .mapStyle(.imagery)        .allowsHitTesting(false)    }}

在這里,出于雷達的目的,我們希望防止命中測試——即我不希望地圖是交互式的。在構想中,地圖是不可見的,用戶只能看到航班及其位置。uPZ28資訊網——每日最新資訊28at.com

飛機縮放

定位之后,尺寸調整是下一個核心問題,現有的解決方案根本無法很好地處理這個問題。uPZ28資訊網——每日最新資訊28at.com

我使用飛行高度在地圖注釋中添加了一些簡單的對數縮放,以便更高的飛機在屏幕上顯得更大。此外,我使用飛機的真實屬性,結合核心位置中的用戶方向,來顯示飛機面向正確的方向。uPZ28資訊網——每日最新資訊28at.com

@State private var rotationAngle: Angle = .degrees(0)private var planeMapAnnotations: some MapContent {    ForEach(flights, id: /.icao24) { flight in        Annotation(flight.icao24, coordinate: flight.coordinate) {            let rotation = rotationAngle.degrees + flight.true_track            let scale = min(2, max(log10(height + 1), 0.5))            Image(systemName: "airplane")                .rotationEffect(.degrees(rotation))                .scaleEffect(scale)            }        }        .tint(.white)    }}

用戶調研

現在是進行終極測試的時候了。uPZ28資訊網——每日最新資訊28at.com

我和女兒一起去看飛機,現在我們有了真實的地圖注釋,能在地圖上顯示用戶的位置和方向。最重要的是,它能夠準確地找到飛機!uPZ28資訊網——每日最新資訊28at.com

圖片uPZ28資訊網——每日最新資訊28at.com

這獲得了巨大成功,因為我們在這上面找到了飛機。uPZ28資訊網——每日最新資訊28at.com

初步測試還得出了兩條重要信息。uPZ28資訊網——每日最新資訊28at.com

首先,縮放邏輯是不正確的??纯磦惗爻鞘袡C場地面上的小飛機。由于應用程序的重點是定位天空中的飛機,因此我們需要反轉縮放比例,較低的平面必須顯示得更大,因為我們是用眼睛來發現它們的。uPZ28資訊網——每日最新資訊28at.com

其次,我的孩子不關心地圖,只關心飛機。如果我想消除噪音并專注于發現飛機,我需要刪除地圖,并開始建造我的雷達!uPZ28資訊網——每日最新資訊28at.com

更新縮放邏輯

我輕松地修復了飛機的縮放邏輯。uPZ28資訊網——每日最新資訊28at.com

經過一番嘗試和錯誤后,為了查看屏幕上看起來不錯的內容,并給出合理的尺寸分布,我選擇了縮放:uPZ28資訊網——每日最新資訊28at.com

min(2, max(4.7 - log10(flight.geo_altitude + 1), 0.7))

這些縮放來自我的本地開銷掃描:uPZ28資訊網——每日最新資訊28at.com

Scale:  1.0835408863965839Scale:  0.8330645861650874Scale:  1.095791123396205Scale:  1.1077242935783653Scale:  2.0Scale:  1.4864702267977097Scale:  0.7

創建雷達

我幾乎準備好建造我所設想的雷達了,但是出現了一個問題。uPZ28資訊網——每日最新資訊28at.com

API穩健性

開源OpenSky API不斷超時,返回502錯誤,或者有時生成帶有空數據的200響應。uPZ28資訊網——每日最新資訊28at.com

這其實也不是問題,畢竟這不是個企業級應用程序,而且這個API不需要我花任何費用。他們沒有SLA,我也覺得自己沒有資格獲得SLA。不過為了幫助提高客戶端的穩健性,我在API調用中實現了一些基本的重試邏輯:uPZ28資訊網——每日最新資訊28at.com

private func fetchFlights(at coordinate: CLLocationCoordinate2D, retries: Int = 3) async {    do {        try await api.fetchLocalFlightData(coordinate: coordinate)    } catch {        if retries > 0 {            try await fetchFlights(at: coordinate, retries: retries - 1)        }    }}

第二天,API運行良好,除了某些高流量時刻外。uPZ28資訊網——每日最新資訊28at.com

覆蓋地圖

最重要的降噪任務是使實際地圖不可見。沒有這個雷達就無法工作。uPZ28資訊網——每日最新資訊28at.com

我能夠使用MapPolygon來做到這一點,表面上設計這樣你就可以放置疊加層來突出顯示地圖的各個部分。但我想用它來隱藏除注釋之外的所有內容。uPZ28資訊網——每日最新資訊28at.com

struct FlightMapView: View {    var body: some View {        Map(position: $cameraPosition) {            planeMapAnnotations            MapPolygon(overlay(coordinate: coordinate))        }        .mapStyle(.imagery)        .allowsHitTesting(false)    }    // ...       private func rectangle(around coordinate: CLLocationCoordinate2D) -> [CLLocationCoordinate2D] {        [            CLLocationCoordinate2D(latitude: coordinate.latitude - 1, longitude: coordinate.longitude - 1),            CLLocationCoordinate2D(latitude: coordinate.latitude - 1, longitude: coordinate.longitude + 1),            CLLocationCoordinate2D(latitude: coordinate.latitude + 1, longitude: coordinate.longitude + 1),            CLLocationCoordinate2D(latitude: coordinate.latitude + 1, longitude: coordinate.longitude - 1)        ]    }        private func overlay(coordinate: CLLocationCoordinate2D) -> MKPolygon {        let rectangle = rectangle(around: coordinate)        return MKPolygon(coordinates: rectangle, count: rectangle.count)    }}

這種方法很有效!uPZ28資訊網——每日最新資訊28at.com

我們現在可以看到飛機,但看不到地圖,就像我們想要的那樣。uPZ28資訊網——每日最新資訊28at.com

最關鍵的是,蘋果將疊加層設計為位于地圖頂部、注釋下方,如果他們采取其他方式,我女兒的新玩具就會跛行。uPZ28資訊網——每日最新資訊28at.com

繪制雷達

核心需求的最后一部分是雷達視圖,這本質上是一組直線、同心圓和20度的旋轉角梯度。uPZ28資訊網——每日最新資訊28at.com

難不倒我。uPZ28資訊網——每日最新資訊28at.com

用戶調研2

經過三個晚上的辛苦工作,女兒終于開始對我創造的玩具表現出一些興趣。uPZ28資訊網——每日最新資訊28at.com

圖片uPZ28資訊網——每日最新資訊28at.com

我們已經證明了這個概念,并構建了一個 MVP,可以實現我們設定的核心初始目標。uPZ28資訊網——每日最新資訊28at.com

現在可以考慮把它放到App Store上了。uPZ28資訊網——每日最新資訊28at.com

當然在此之前還需要進行其他的優化。uPZ28資訊網——每日最新資訊28at.com

比如讓雷達有360度寬角漸變,從綠色,到透明,到透明,到透明,再到黑色。uPZ28資訊網——每日最新資訊28at.com

private var radarLine: some View {    Circle()        .fill(            AngularGradient(                gradient: Gradient(colors: [                    Color.black, Color.black, Color.black, Color.black,                    Color.black.opacity(0.8), Color.black.opacity(0.6),                    Color.black.opacity(0.4), Color.black.opacity(0.2),                    Color.clear, Color.clear, Color.clear, Color.clear,                    Color.clear, Color.clear, Color.clear, Color.clear,                    Color.clear, Color.clear, Color.clear, Color.green]),                center: .center,                startAngle: .degrees(rotationDegree),                endAngle: .degrees(rotationDegree + 360)            )        )        .rotationEffect(Angle(degrees: rotationDegree))        .animation(.linear(duration: 6).repeatForever(autoreverses: false), value: rotationDegree)}

除此之外,我添加了CRT屏幕效果和電視掃描線,使應用程序看起來就像是在舊雷達掃描儀上繪制的。uPZ28資訊網——每日最新資訊28at.com

#include <metal_stdlib>using namespace metal;[[ stitchable ]] half4 crtScreen(    float2 position,    half4 color,    float time) {        if (all(abs(color.rgb - half3(0.0, 0.0, 0.0)) < half3(0.01, 0.01, 0.01))) {        return color;    }        const half scanlineIntensity = 0.2;    const half scanlineFrequency = 400.0;    half scanlineValue = sin((position.y + time * 10.0) * scanlineFrequency * 3.14159h) * scanlineIntensity;    return half4(color.rgb - scanlineValue, color.a);}

我還創建了一個視圖修改器,可以將CRT效果應用到喜歡的任何視圖。uPZ28資訊網——每日最新資訊28at.com

extension View {        func crtScreenEffect(startTime: Date) -> some View {        modifier(CRTScreen(startTime: startTime))    }}struct CRTScreen: ViewModifier {        let startTime: Date        func body(content: Content) -> some View {        content            .colorEffect(                ShaderLibrary.crtScreen(                    .float(startTime.timeIntervalSinceNow)                )            )    }}

圖片uPZ28資訊網——每日最新資訊28at.com

目前該應用程序已經上線了App Store。uPZ28資訊網——每日最新資訊28at.com


uPZ28資訊網——每日最新資訊28at.com

圖片uPZ28資訊網——每日最新資訊28at.com

同時下個版本的新功能也已經在構想中了,包括但不限于:uPZ28資訊網——每日最新資訊28at.com

  • 向地圖添加縮放級別,以將雷達限制為僅檢測較近的飛機。
  • 使用OpenSky Network API的高級版本顯示直升機、衛星和飛機尺寸類別。
  • 切換飛機上的出發地和目的地國家/地區顯示。
  • 使用更先進的金屬著色器改善CRT屏幕效果。
  • 實施滑塊控件來過濾掉某些距離和高度,例如隱藏所有低矮、遙遠的飛機。
  • 實施“滑稽模式”,在雷達上呈現不明飛行物、巨型蟲子和外星人。

本文鏈接:http://www.www897cc.com/showinfo-26-34927-0.html孩子喜歡飛機,于是我給她做了一個雷達

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: C++數據與量值是如何被組織的?

下一篇: 理解C++之構造函數

標簽:
  • 熱門焦點
  • 直屏旗艦來了 iQOO 12和K70 Pro同臺競技

    旗艦機基本上使用的都是雙曲面屏幕,這就讓很多喜歡直屏的愛好者在苦等一款直屏旗艦,這次,你們等到了。據博主數碼閑聊站帶來的最新爆料稱,Redmi下代旗艦K70 Pro和iQOO 12兩款手
  • 從 Pulsar Client 的原理到它的監控面板

    背景前段時間業務團隊偶爾會碰到一些 Pulsar 使用的問題,比如消息阻塞不消費了、生產者消息發送緩慢等各種問題。雖然我們有個監控頁面可以根據 topic 維度查看他的發送狀態,
  • 19個 JavaScript 單行代碼技巧,讓你看起來像個專業人士

    今天這篇文章跟大家分享18個JS單行代碼,你只需花幾分鐘時間,即可幫助您了解一些您可能不知道的 JS 知識,如果您已經知道了,就當作復習一下,古人云,溫故而知新嘛?,F在,我們就開始今
  • 從零到英雄:高并發與性能優化的神奇之旅

    作者 | 波哥審校 | 重樓作為公司的架構師或者程序員,你是否曾經為公司的系統在面對高并發和性能瓶頸時感到手足無措或者焦頭爛額呢?筆者在出道那會為此是吃盡了苦頭的,不過也得
  • 一條抖音4億人圍觀 ! 這家MCN比無憂傳媒還野

    作者:Hiu 來源:互聯網品牌官01 擦邊少女空降熱搜,幕后推手曝光被網友譽為&ldquo;純欲天花板&rdquo;的女網紅井川里予,近期因為一組哥特風照片登上熱搜,引發了一場互聯網世界關于
  • 大廠卷向扁平化

    來源:新熵作者丨南枝 編輯丨月見大廠職級不香了。俗話說,兵無常勢,水無常形,互聯網企業調整職級體系并不稀奇。7月13日,淘寶天貓集團啟動了近年來最大的人力制度改革,目前已形成一
  • 蘋果、三星、惠普等暫停向印度出口筆記本和平板電腦

    集微網消息,據彭博社報道,在8月3日印度突然禁止在沒有許可證的情況下向印度進口電腦/平板及顯示器等產品后,蘋果、三星電子和惠普等大公司暫停向印度
  • OPPO K11搭載高性能石墨散熱系統:旗艦同款 性能涼爽釋放

    日前OPPO官方宣布,將于7月25日14:30舉辦新品發布會,屆時全新的OPPO K11將正式與大家見面,將主打旗艦影像,和同檔位競品相比,其最大的賣點就是將配備索尼
  • 聯想小新Pad Pro 12.6將要推出,搭載高通驍龍 870 處理器

    聯想小新Pad Pro 12.6將于秋季新品會上推出,官方按照慣例直接在發布會前給出了機型的所有參數。聯想小新 Pad Pro 12.6 將搭載高通驍龍 870 處理器,重量為 5
Top 主站蜘蛛池模板: 大冶市| 土默特右旗| 昭觉县| 博罗县| 万全县| 贵南县| 洛阳市| 宜良县| 济阳县| 龙川县| 乌鲁木齐市| 阜平县| 师宗县| 英山县| 楚雄市| 仪征市| 科技| 玉田县| 迁西县| 将乐县| 宜川县| 灌南县| 浠水县| 阜平县| 清新县| 白玉县| 拉孜县| 新民市| 安阳县| 德安县| 阳西县| 禹城市| 平湖市| 南和县| 平乡县| 密山市| 海伦市| 绥化市| 法库县| 鲁甸县| 博客|