-
Notifications
You must be signed in to change notification settings - Fork 1
/
math.typ
127 lines (122 loc) · 4.59 KB
/
math.typ
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
#import "is.typ": same-type
// =================================
// Math
// =================================
/// Returns an array with the minimum of `a` and `b` as the first element and the maximum as the second:
/// #codesnippet[```typ
/// #let (min, max) = math.minmax(a, b)
/// ```]
/// Works with any comparable type.
///
/// // Tests
/// #test(
/// `math.minmax(50, 60) == (50, 60)`,
/// `math.minmax(60, 50) == (50, 60)`,
/// `math.minmax(5deg, -4deg) == (-4deg, 5deg)`,
/// `math.minmax(-5cm, -4cm) == (-5cm, -4cm)`,
/// )
///
/// - a (integer, float, length, relative length, fraction, ratio): First value.
/// - b (integer, float, length, relative length, fraction, ratio): Second value.
/// -> integer, float, length, relative length, fraction, ratio
#let minmax( a, b ) = (
calc.min(a, b),
calc.max(a, b)
)
/// Clamps a value between `min` and `max`.
///
/// In contrast to @@clamp() this function works for other values
/// than numbers, as long as they are comparable.
/// #codesnippet[```typ
/// text-size = math.clamp(0.8em, 1.2em, text-size)
/// ```]
/// Works with any comparable type.
///
/// // Tests
/// #test(
/// `math.clamp(0, 100, 50) == 50`,
/// `math.clamp(33%, 99%, 100%) == 99%`,
/// `math.clamp(-5in, 8in, -6in) == -5in`,
/// `math.clamp(-5in, 8in, 4in) == 4in`,
/// )
///
/// - min (integer, float, length, relative length, fraction, ratio): Minimum for `value`.
/// - min (integer, float, length, relative length, fraction, ratio): Maximum for `value`.
/// - value (integer, float, length, relative length, fraction, ratio): The value to clamp.
/// -> any
#let clamp( min, max, value ) = {
assert.eq(type(min), type(max),
message:"Can't clamp values of different types!"
)
assert.eq(type(min), type(value),
message:"Can't clamp values of different types!"
)
if value < min { return min }
else if value > max { return max }
else { return value }
}
/// Calculates the linear interpolation of `t` between `min` and `max`.
///
/// `t` should be a value between 0 and 1, but the interpolation works
/// with other values, too. To constrain the result into the given
/// interval, use @@clamp():
/// #codesnippet[```typ
/// #let width = math.lerp(0%, 100%, x)
/// #let width = math.lerp(0%, 100%, math.clamp(0, 1, x))
/// ```]
///
/// // Tests
/// #test(
/// `math.lerp(0, 100, .5) == 50`,
/// `math.lerp(0%, 100%, 1.1) == 110%`,
/// `math.lerp(-4em, 3em, -2) == -18em`,
/// `math.lerp(56.7, 423.8, 1) == 423.8`,
/// `math.lerp(56.7mm, 423.8mm, 0) == 56.7mm`,
/// )
///
/// - min (integer, float, length, relative length, fraction, ratio): Minimum for `value`.
/// - max (integer, float, length, relative length, fraction, ratio): Maximum for `value`.
/// - t (float): Interpolation parameter .
/// -> integer, float, length, relative length, fraction, ratio
#let lerp( min, max, t ) = {
assert.eq(type(min), type(max),
message:"Can't lerp values of different types!"
)
return (1 - t) * min + t * max;
}
/// Maps a `value` from the interval `[min, max]` into the interval `[range-min, range-max]`:
/// #codesnippet[```typ
/// #let text-weight = int(math.map(8pt, 16pt, 400, 800, text-size))
/// ```]
///
/// The types of `min`, `max` and `value` and the types of `range-min` and `range-max` have to be the same.
///
/// // Tests
/// #test(
/// `math.map(8pt, 16pt, 400, 800, 8pt) == 400`,
/// `math.map(8pt, 16pt, 400, 800, 16pt) == 800`,
/// `math.map(8pt, 16pt, 400, 800, 4pt) == 200`,
/// `math.map(8pt, 16pt, 400, 800, 32pt) == 1600`,
/// `math.map(0%, 100%, 5.6em, 0.8em, 100%) == 0.8em`,
/// `math.map(0%, 100%, 5.6em, 0.8em, 0%) == 5.6em`,
/// )
///
/// - min (integer, float, length, relative length, fraction, ratio): Minimum of the initial interval.
/// - min (integer, float, length, relative length, fraction, ratio): Maximum of the initial interval.
/// - range-min (integer, float, length, relative length, fraction, ratio): Minimum of the target interval.
/// - range-min (integer, float, length, relative length, fraction, ratio): Maximum of the target interval.
/// - value (integer, float, length, relative length, fraction, ratio): The value to map.
/// -> integer, float, length, relative length, fraction, ratio
#let map( min, max, range-min, range-max, value ) = {
assert.eq(type(min), type(max),
message:"Can't map values from ranges of different types!"
)
assert.eq(type(range-min), type(range-max),
message:"Can't map values to ranges of different types!"
)
assert.eq(type(min), type(value),
message:"Can't map values with different types as the initial range!"
)
let t = (value - min) / (max - min)
return (1 - t) * range-min + t * range-max;
}