forked from nicklockwood/ShapeScript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEuclid+Extensions.swift
More file actions
153 lines (142 loc) · 4.13 KB
/
Euclid+Extensions.swift
File metadata and controls
153 lines (142 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//
// Euclid+Extensions.swift
// ShapeScript Lib
//
// Created by Nick Lockwood on 19/10/2021.
// Copyright © 2021 Nick Lockwood. All rights reserved.
//
import Euclid
public extension Color {
init?(hexString: String) {
var string = hexString
if hexString.hasPrefix("#") {
string = String(string.dropFirst())
}
switch string.count {
case 3:
string += "f"
fallthrough
case 4:
let chars = Array(string)
let red = chars[0]
let green = chars[1]
let blue = chars[2]
let alpha = chars[3]
string = "\(red)\(red)\(green)\(green)\(blue)\(blue)\(alpha)\(alpha)"
case 6:
string += "ff"
case 8:
break
default:
return nil
}
guard let rgba = Double("0x" + string).flatMap({
UInt32(exactly: $0)
}) else {
return nil
}
let red = Double((rgba & 0xFF00_0000) >> 24) / 255
let green = Double((rgba & 0x00FF_0000) >> 16) / 255
let blue = Double((rgba & 0x0000_FF00) >> 8) / 255
let alpha = Double((rgba & 0x0000_00FF) >> 0) / 255
self.init(unchecked: [red, green, blue, alpha])
}
}
extension Color {
init(unchecked components: [Double]) {
if let color = Color(components) {
self = color
} else {
assertionFailure()
self = .clear
}
}
}
extension Angle {
var halfturns: Double {
radians / .pi
}
init(halfturns: Double) {
self.init(radians: halfturns * .pi)
}
static func halfturns(_ halfturns: Double) -> Angle {
self.init(halfturns: halfturns)
}
}
extension Rotation {
var rollYawPitchInHalfTurns: [Double] {
[roll.halfturns, yaw.halfturns, pitch.halfturns]
}
init(rollYawPitchInHalfTurns: [Double]) {
var roll = 0.0, yaw = 0.0, pitch = 0.0
switch rollYawPitchInHalfTurns.count {
case 3...:
pitch = rollYawPitchInHalfTurns[2]
fallthrough
case 2:
yaw = rollYawPitchInHalfTurns[1]
fallthrough
case 1:
roll = rollYawPitchInHalfTurns[0]
default:
break
}
self.init(
roll: .halfturns(roll),
yaw: .halfturns(yaw),
pitch: .halfturns(pitch)
)
}
}
#if canImport(UIKit)
import UIKit
#elseif canImport(AppKit)
import AppKit
#endif
#if canImport(CoreText)
private extension NSAttributedString {
convenience init(string: String, font: String?, color: Color?, linespacing: Double?) {
var fontName = (font ?? "Helvetica") as CFString
#if canImport(CoreGraphics)
fontName = CGFont(fontName)?.postScriptName ?? fontName
#endif
let font = CTFontCreateWithName(fontName as CFString, 1, nil)
var attributes = [NSAttributedString.Key.font: font as Any]
#if canImport(AppKit) || canImport(UIKit)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = CGFloat(linespacing ?? 0)
attributes[.paragraphStyle] = paragraphStyle
attributes[.foregroundColor] = color.map(OSColor.init)
#endif
self.init(string: string, attributes: attributes)
}
}
#endif
extension Path {
/// Create an array of text paths
static func text(
_ text: [TextValue],
width: Double? = nil,
detail: Int = 2
) -> [Path] {
#if canImport(CoreText)
let attributedString = NSMutableAttributedString()
for text in text {
var string = text.string
if attributedString.length > 0 {
string = "\n\(string)"
}
attributedString.append(NSAttributedString(
string: string,
font: text.font,
color: text.color,
linespacing: text.linespacing
))
}
return Path.text(attributedString, width: width, detail: detail)
#else
// TODO: throw error when CoreText not available
return []
#endif
}
}