krz/moonrise

Night-sky companion for iPhone, Apple Watch and Vision Pro: what's up tonight, the Moon, planets, launches and missions, and a Library of the solar system. SwiftUI app with a Cloudflare Workers backend. astronomy cloudflare-workers ios night-sky space swiftui visionos watchos

Packages/MoonriseKit/Tests/SkyRendererTests/DeepSkyTests.swift

59d401dca1a327705632d1e2e20f00f807dee828
moonrise/Packages/MoonriseKit/Tests/SkyRendererTests/DeepSkyTests.swift history · blame · raw

56 lines · 2833 bytes

4 symbols in this file
 1import Foundation
 2import SkyEngine
 3import SwiftUI
 4import Testing
 5@testable import SkyRenderer
 6
 7@Test func messierCatalogueFollowsOpenNGC() throws {
 8    let objects = Catalog.deepSky
 9    // M102 is a duplicate of M101 in OpenNGC.
10    #expect(objects.map(\.messier) == Array(1...101) + Array(103...110))
11    let m31 = try #require(objects.first { $0.messier == 31 })
12    #expect(m31.kind == .galaxy)
13    #expect(m31.positionAngle == 35)
14    #expect(abs(m31.ra - 10.685) < 0.01 && abs(m31.dec - 41.269) < 0.01)
15    #expect(objects.first { $0.messier == 13 }?.kind == .globularCluster)
16    #expect(objects.first { $0.messier == 57 }?.kind == .planetaryNebula)
17    #expect(objects.first { $0.messier == 42 }?.kind == .nebula)
18    #expect(objects.first { $0.messier == 45 }?.kind == .openCluster)
19    #expect(objects.allSatisfy { $0.page == "m\($0.messier)" })
20}
21
22@Test func tapOnASymbolFindsTheMessierObject() throws {
23    let scene = try SkyScene(date: evening, observer: chicago)
24    let m57 = try #require(scene.deepSky.first { $0.object.messier == 57 })
25    #expect(m57.position.altitude > 30)
26    let p = Projection(centerAzimuth: m57.position.azimuth, centerAltitude: m57.position.altitude, fieldOfView: 60, size: CGSize(width: 393, height: 852))
27    let pt = try #require(p.point(m57.position))
28    #expect(scene.object(at: CGPoint(x: pt.x + 4, y: pt.y), projection: p) == .deepSky(57))
29    #expect(scene.object(at: CGPoint(x: pt.x + 4, y: pt.y), projection: p, deepSky: false) != .deepSky(57))
30}
31
32/// The symbol frame's east vector matches where a point east of the object projects.
33@MainActor
34@Test func symbolFrameHasEastAnticlockwiseFromNorth() throws {
35    let scene = try SkyScene(date: evening, observer: chicago)
36    let view = SkyView(scene: scene)
37    for m in [31, 13, 57] {
38        let d = try #require(scene.deepSky.first { $0.object.messier == m })
39        let p = Projection(centerAzimuth: 180, centerAltitude: 45, fieldOfView: 100, size: CGSize(width: 393, height: 852))
40        let f = try #require(view.symbolFrame(d, p))
41        let o = d.object
42        let east = SkyEngine.horizontal(j2000: [(o.ra + 0.1 / cos(o.dec * .pi / 180), o.dec)], at: evening, from: chicago)[0]
43        let e = try #require(p.point(east))
44        let measured = CGVector(dx: (e.x - f.center.x) * 10, dy: (e.y - f.center.y) * 10)
45        #expect(hypot(measured.dx - f.east.dx, measured.dy - f.east.dy) < 0.05 * hypot(f.east.dx, f.east.dy), "M\(m)")
46    }
47}
48
49@MainActor
50@Test func deepSkyRendersAtEveryZoom() throws {
51    let scene = try SkyScene(date: evening, observer: chicago)
52    for fov in [30.0, 100.0] {
53        let renderer = ImageRenderer(content: SkyView(scene: scene, centerAzimuth: 90, centerAltitude: 50, fieldOfView: fov, showDeepSky: true).frame(width: 393, height: 852))
54        #expect(renderer.cgImage != nil)
55    }
56}