/
util.clj
117 lines (104 loc) · 3.67 KB
/
util.clj
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
(ns afterglow.util
"Utility functions that are likely to be widely useful"
{:author "James Elliott"}
(:require [clojure.math.numeric-tower :as math]
[com.evocomputing.colors :as colors]))
(defn ubyte
"Convert small integer to its signed byte equivalent. Necessary for convenient handling of DMX values
in the range 0-255, since Java does not have unsigned numbers."
[val]
(if (>= val 128)
(byte (- val 256))
(byte val)))
(defn unsign
"Convert a signed byte to its unsigned int equivalent, in the range 0-255."
[val]
(bit-and val 0xff))
(defn valid-dmx-value?
"Checks that the supplied value is within the legal range for a DMX
channel assignment."
[v]
(<= 0 v 255))
(defn find-closest-key
"Finds the key closest to the one specified in a sorted map."
[sm k]
(if-let [a (first (rsubseq sm <= k))]
(let [a (key a)]
(if (= a k)
a
(if-let [b (first (subseq sm >= k))]
(let [b (key b)]
(if (< (math/abs (- k b)) (math/abs (- k a)))
b
a))
a)))
(when-let [found (first (subseq sm >= k))]
(key found))))
(def float-epsilon
"The tolerance value for comparing two floating point numbers. If
the difference between the values is smaller than this, after
scaling appropriately for very small or very large numbers, they
will be considered equal."
0.00001)
(defn- scale
"Calculate a suitable scale factor for floating point comparison
tolerance."
[x y]
(if (or (zero? x) (zero? y))
1
(math/abs x)))
(defn float=
"Compare two floating point numbers for equality, with a tolerance
specified by `epsilon`, which defaults to `float-epsilon` if not
provided."
([x y] (float= x y float-epsilon))
([x y epsilon] (<= (math/abs (- x y))
(* (scale x y) epsilon))))
(defn float<
"Checks whether `x` is less than `y` with an equality tolerance
specified by `epsilon`, which defaults to `float-epsilon` if not
provided."
([x y] (float< x y float-epsilon))
([x y epsilon] (< x
(- y (* (scale x y) epsilon)))))
(defn float>
"Checks whether `x` is greater than `y` with an equality tolerance
specified by `epsilon`, which defaults to `float-epsilon` if not
provided."
([x y] (float< y x))
([x y epsilon] (float< y x epsilon)))
(defn float<=
"Checks whether `x` is less than or equal to `y` with an equality
tolerance specified by `epsilon`, which defaults to `float-epsilon`
if not provided."
([x y] (not (float> x y)))
([x y epsilon] (not (float> x y epsilon))))
(defn float>=
"Checks whether `x` is greater than or equal to `y` with an equality
tolerance specified by `epsilon`, which defaults to `float-epsilon`
if not provided."
([x y] (not (float< x y)))
([x y epsilon] (not (float< x y epsilon))))
(defn contrasting-text-color
"If the default text color of white will be hard to read against a
cell assigned the specified color, returns black. Otherwise returns
white. Both are in the form of hex strings suitable for use in a CSS
style."
[color]
(if (and color
;; Calculate the perceived brightness of the color.
(let [[r g b] (map #(/ % 255) [(colors/red color) (colors/green color) (colors/blue color)])]
(> (Math/sqrt (+ (* 0.299 r r) (* 0.587 g g) (* 0.114 b b))) 0.6)))
"#000"
"#fff"))
(defn normalize-cue-variable-value
"Given a raw value that has been looked up for a cue variable,
convert it to the appropriate type based on the variable
specification."
[var-spec raw]
(when (some? raw)
(case (:type var-spec)
:boolean (boolean raw)
:integer (Math/round (double raw))
:color raw
(double raw))))