Skip to content

Commit 9c69fa8

Browse files
committed
Improve handling of greek letters in star names
1 parent 8bc8eb6 commit 9c69fa8

6 files changed

Lines changed: 235 additions & 25 deletions

File tree

Sources/SwiftAstro/StarCatalog/BrightStar+Nameable.swift

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,14 @@ import Foundation
55
extension SwiftAstro.BrightStar : SwiftAstro.AstronomicallyNameable {
66

77
public var name: String? {
8-
namedInNotes ?? commonlyNamed
9-
}
10-
11-
private var namedInNotes: String? {
12-
guard
13-
let namingRemark = notes?.filter({ note in
14-
note.noteCategory == .starNames
15-
}).first?.remark,
16-
let name = namingRemark.split(separator: ";").first
17-
else {
18-
return nil
8+
if let greek = bayerGreek, let constellation = constellation {
9+
var n = greek.letter
10+
if let number = greek.number { n += "\(number)" }
11+
n += " \(constellation)"
12+
return n
1913
}
2014

21-
return name.trimmingCharacters(in: .whitespaces)
22-
}
23-
24-
private var commonlyNamed: String? {
25-
guard let commonName = commonName else { return nil }
26-
let parts = commonName
27-
.components(separatedBy: .whitespaces)
28-
.filter { p in !p.isEmpty }
29-
30-
return parts.joined(separator: " ")
15+
return nil
3116
}
3217

3318
}

Sources/SwiftAstro/StarCatalog/BrightStar.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,15 @@ extension SwiftAstro {
1111
/// Harvard Revised Star Number (Bright Star Number).
1212
public let number: Int
1313

14-
/// Common name of the star.
15-
public let commonName: String?
16-
14+
/// Flamsteed number of the star.
15+
public let flamsteedNumber: Int?
16+
17+
/// Bayer greek designation of the star.
18+
public let bayerGreek: Greek?
19+
20+
/// Constellation genitive of the star.
21+
public let constellation: String?
22+
1723
/// Durchmusterung Identification.
1824
public let durchmusterungIdentification: String?
1925

Sources/SwiftAstro/StarCatalog/BrightStarCatalog.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,25 @@ private extension SwiftAstro.BrightStarCatalog {
7272
componentsSeparation = nil
7373
}
7474

75+
let flamsteedNumber: Int?
76+
if let flamsteed: Int = line.cols(6, 2) {
77+
flamsteedNumber = flamsteed
78+
} else {
79+
flamsteedNumber = nil
80+
}
81+
82+
let bayerGreek: SwiftAstro.Greek?
83+
if let greek: String = line.cols(8, 4) {
84+
bayerGreek = SwiftAstro.Greek(hrCoding: greek)
85+
} else {
86+
bayerGreek = nil
87+
}
88+
7589
let star = SwiftAstro.BrightStar(
7690
number: number,
77-
commonName: line.cols(5, 10),
91+
flamsteedNumber: flamsteedNumber,
92+
bayerGreek: bayerGreek,
93+
constellation: line.cols(12, 3),
7894
durchmusterungIdentification: line.cols(15, 11),
7995
henryDraperCatalogNumber: line.cols(26, 6),
8096
saoCatalogNumber: line.cols(32, 6),
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import Foundation
2+
3+
// MARK: - Greek
4+
5+
extension SwiftAstro {
6+
7+
public struct Greek {
8+
public let simbad: Simbad
9+
public let letter: String
10+
public let number: Int?
11+
12+
public init(simbad: Simbad, number: Int? = nil) {
13+
self.simbad = simbad
14+
self.letter = simbad.asLetter
15+
self.number = number
16+
}
17+
18+
init?(simbad: Simbad?, number: Int?) {
19+
guard let simbad = simbad else { return nil }
20+
self.init(simbad: simbad, number: number)
21+
}
22+
23+
public init?(simbadCoding: String) {
24+
guard let (coding, number) = Self.split(simbadCoding) else {
25+
return nil
26+
}
27+
28+
self.init(
29+
simbad: Simbad.fromSimbadCoding(coding),
30+
number: number)
31+
}
32+
33+
public init?(hrCoding: String) {
34+
guard let (coding, number) = Self.split(hrCoding) else {
35+
return nil
36+
}
37+
38+
self.init(
39+
simbad: Simbad.fromHRCoding(coding),
40+
number: number)
41+
}
42+
43+
public init?(greekLetter: String) {
44+
guard let (coding, number) = Self.split(greekLetter) else {
45+
return nil
46+
}
47+
48+
self.init(simbad: Simbad.fromLetter(coding), number: number)
49+
}
50+
51+
private static func split(_ string: String) -> (String, Int?)? {
52+
let digitIndex = string.firstIndex { c in c.isNumber }
53+
guard let idx = digitIndex else { return (string, nil) }
54+
let coding = string[string.startIndex..<idx]
55+
let digits = string[idx..<string.endIndex]
56+
guard let number = Int(digits) else { return nil }
57+
return (String(coding), number)
58+
}
59+
60+
}
61+
62+
}
63+
64+
// MARK: - Simbad
65+
66+
extension SwiftAstro.Greek {
67+
68+
public enum Simbad: Hashable {
69+
case alf, bet, gam, del, eps, zet, eta, tet
70+
case iot, kap, lam, mu, nu, ksi, omi, pi
71+
case rho, sig, tau, ups, phi, khi, psi, ome
72+
73+
private static let simbadLookup: [String: Simbad] = [
74+
"alf": .alf, "bet": .bet, "gam": .gam, "del": .del,
75+
"eps": .eps, "zet": .zet, "eta": .eta, "tet": .tet,
76+
"iot": .iot, "kap": .kap, "lam": .lam, "mu" : .mu,
77+
"nu" : .nu, "ksi": .ksi, "omi": .omi, "pi" : .pi,
78+
"rho": .rho, "sig": .sig, "tau": .tau, "ups": .ups,
79+
"phi": .phi, "khi": .khi, "psi": .psi, "ome": .omi
80+
]
81+
82+
private static let hrLookup: [String: Simbad] = [
83+
"alp": .alf, "bet": .bet, "gam": .gam, "del": .del,
84+
"eps": .eps, "zet": .zet, "eta": .eta, "the": .tet,
85+
"iot": .iot, "kap": .kap, "lam": .lam, "mu" : .mu,
86+
"nu" : .nu, "xi" : .ksi, "omi": .omi, "pi" : .pi,
87+
"rho": .rho, "sig": .sig, "tau": .tau, "ups": .ups,
88+
"phi": .phi, "chi": .khi, "psi": .psi, "ome": .omi
89+
]
90+
91+
private static let letterLookup: [Simbad: String] = [
92+
.alf: "α", .bet: "β", .gam: "γ", .del: "δ",
93+
.eps: "ε", .zet: "ζ", .eta: "η", .tet: "θ",
94+
.iot: "ι", .kap: "κ", .lam: "λ", .mu : "µ",
95+
.nu : "ν", .ksi: "ξ", .omi: "o", .pi : "π",
96+
.rho: "ρ", .sig: "σ", .tau: "τ", .ups: "υ",
97+
.phi: "φ", .khi: "χ", .psi: "ψ", .ome: "ω",
98+
]
99+
100+
static func fromSimbadCoding(_ coding: String) -> Simbad? {
101+
simbadLookup[coding.lowercased()]
102+
}
103+
104+
static func fromHRCoding(_ coding: String) -> Simbad? {
105+
hrLookup[coding.lowercased()]
106+
}
107+
108+
static func fromLetter(_ letter: String) -> Simbad? {
109+
(letterLookup.first { (s, g) in letter == g })?.0
110+
}
111+
112+
var asLetter: String { Self.letterLookup[self]! }
113+
114+
}
115+
116+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import XCTest
2+
@testable import SwiftAstro
3+
4+
final class BrightStarCatalogTests: XCTestCase {
5+
6+
func test919() throws {
7+
let bsc = SwiftAstro.brightStarCatalog
8+
let hr919 = try XCTUnwrap(bsc[919])
9+
10+
XCTAssertEqual(hr919.flamsteedNumber, 11)
11+
XCTAssertEqual(hr919.bayerGreek?.simbad, .tau)
12+
XCTAssertEqual(hr919.bayerGreek?.number, 3)
13+
XCTAssertEqual(hr919.constellation, "Eri")
14+
}
15+
16+
func test972() throws {
17+
let bsc = SwiftAstro.brightStarCatalog
18+
let hr947 = try XCTUnwrap(bsc[972])
19+
20+
XCTAssertEqual(hr947.name, "ζ Ari")
21+
XCTAssertEqual(hr947.constellation, "Ari")
22+
}
23+
24+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import XCTest
2+
@testable import SwiftAstro
3+
4+
final class GreekTests: XCTestCase {
5+
6+
func testSimbad() throws {
7+
let g = SwiftAstro.Greek(simbad: .ome)
8+
XCTAssertEqual(g.simbad, .ome)
9+
XCTAssertEqual(g.letter, "ω")
10+
}
11+
12+
func testSimbadCoding() throws {
13+
let g = try XCTUnwrap(SwiftAstro.Greek(simbadCoding: "tet"))
14+
XCTAssertEqual(g.simbad, .tet)
15+
XCTAssertEqual(g.letter, "θ")
16+
17+
let noSuch = SwiftAstro.Greek(simbadCoding: "nonsense")
18+
XCTAssertNil(noSuch)
19+
}
20+
21+
func testHRCoding() throws {
22+
let g = try XCTUnwrap(SwiftAstro.Greek(hrCoding: "the"))
23+
XCTAssertEqual(g.simbad, .tet)
24+
XCTAssertEqual(g.letter, "θ")
25+
26+
let noSuch = SwiftAstro.Greek(hrCoding: "nonsense")
27+
XCTAssertNil(noSuch)
28+
}
29+
30+
func testGreekLetter() throws {
31+
let g = try XCTUnwrap(SwiftAstro.Greek(greekLetter: "ξ"))
32+
XCTAssertEqual(g.simbad, .ksi)
33+
XCTAssertEqual(g.letter, "ξ")
34+
35+
let noSuch = SwiftAstro.Greek(simbadCoding: "a")
36+
XCTAssertNil(noSuch)
37+
}
38+
39+
func testSimbadWithNumber() throws {
40+
let g = try XCTUnwrap(SwiftAstro.Greek(simbadCoding: "alf02"))
41+
XCTAssertEqual(g.simbad, .alf)
42+
XCTAssertEqual(g.letter, "α")
43+
XCTAssertEqual(g.number, 2)
44+
45+
let noSuch = SwiftAstro.Greek(simbadCoding: "alf02yyy")
46+
XCTAssertNil(noSuch)
47+
}
48+
49+
func testGreekLetterWithNumber() throws {
50+
let g = try XCTUnwrap(SwiftAstro.Greek(greekLetter: "σ5"))
51+
XCTAssertEqual(g.simbad, .sig)
52+
XCTAssertEqual(g.letter, "σ")
53+
XCTAssertEqual(g.number, 5)
54+
}
55+
56+
func testHRCodingWithNumber() throws {
57+
let g = try XCTUnwrap(SwiftAstro.Greek(hrCoding: "Eta1"))
58+
XCTAssertEqual(g.simbad, .eta)
59+
XCTAssertEqual(g.letter, "η")
60+
XCTAssertEqual(g.number, 1)
61+
}
62+
63+
}

0 commit comments

Comments
 (0)