red-colors 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -0
- data/data/colormaps/cividis.json +258 -0
- data/data/colormaps/coolwarm.json +107 -0
- data/data/colormaps/crest.json +258 -0
- data/data/colormaps/flare.json +258 -0
- data/data/colormaps/gist_earth.json +49 -0
- data/data/colormaps/gist_ncar.json +55 -0
- data/data/colormaps/icefire.json +258 -0
- data/data/colormaps/inferno.json +258 -0
- data/data/colormaps/magma.json +258 -0
- data/data/colormaps/mako.json +258 -0
- data/data/colormaps/nipy_spectral.json +71 -0
- data/data/colormaps/pink.json +200 -0
- data/data/colormaps/plasma.json +258 -0
- data/data/colormaps/rocket.json +258 -0
- data/data/colormaps/turbo.json +258 -0
- data/data/colormaps/twilight.json +512 -0
- data/data/colormaps/viridis.json +258 -0
- data/data/colormaps/vlag.json +258 -0
- data/lib/colors.rb +17 -5
- data/lib/colors/abstract_color.rb +4 -0
- data/lib/colors/colormap.rb +143 -0
- data/lib/colors/colormap_data.rb +44 -0
- data/lib/colors/colormap_data/matplotlib_builtin.rb +990 -0
- data/lib/colors/colormap_data/seaborn_builtin.rb +10 -0
- data/lib/colors/colormap_registry.rb +62 -0
- data/lib/colors/convert.rb +269 -0
- data/lib/colors/helper.rb +2 -1
- data/lib/colors/husl.rb +7 -100
- data/lib/colors/linear_segmented_colormap.rb +137 -0
- data/lib/colors/listed_colormap.rb +45 -0
- data/lib/colors/named_colors.rb +10 -20
- data/lib/colors/rgb.rb +20 -10
- data/lib/colors/rgba.rb +14 -8
- data/lib/colors/utils.rb +18 -0
- data/lib/colors/version.rb +1 -1
- data/lib/colors/xterm256.rb +56 -0
- data/lib/colors/xyy.rb +48 -0
- data/lib/colors/xyz.rb +2 -55
- data/red-colors.gemspec +3 -1
- data/test/test-husl.rb +45 -53
- data/test/test-linear-segmented-colormap.rb +138 -0
- data/test/test-listed-colormap.rb +134 -0
- data/test/test-rgb.rb +76 -1
- data/test/test-xterm256.rb +76 -0
- data/test/test-xyz.rb +1 -1
- metadata +50 -15
@@ -0,0 +1,10 @@
|
|
1
|
+
module Colors
|
2
|
+
module ColormapRegistry
|
3
|
+
register_listed_colormap("rocket")
|
4
|
+
register_listed_colormap("mako")
|
5
|
+
register_listed_colormap("icefire")
|
6
|
+
register_listed_colormap("vlag")
|
7
|
+
register_listed_colormap("flare")
|
8
|
+
register_listed_colormap("crest")
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Colors
|
2
|
+
module ColormapRegistry
|
3
|
+
@registry = {}
|
4
|
+
|
5
|
+
def self.[](name)
|
6
|
+
return name if name.is_a?(Colormap)
|
7
|
+
|
8
|
+
name = String.try_convert(name)
|
9
|
+
if @registry.key?(name)
|
10
|
+
return @registry[name]
|
11
|
+
else
|
12
|
+
raise ArgumentError, "Unknown colormap name: %p" % name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.register(cmap, name: nil, override_builtin: false)
|
17
|
+
case name
|
18
|
+
when String, Symbol
|
19
|
+
name = name.to_s
|
20
|
+
when nil
|
21
|
+
name = cmap.name
|
22
|
+
if name.nil?
|
23
|
+
raise ArgumentError, "`name` cannot be omitted for unnamed colormaps"
|
24
|
+
end
|
25
|
+
else
|
26
|
+
name = String.try_convert(name)
|
27
|
+
if name.nil?
|
28
|
+
raise ArgumentError, "`name` must be convertible to a String by to_str"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if @registry.key?(name)
|
33
|
+
existing = @registry[name]
|
34
|
+
if BUILTIN_COLORMAPS.key?(name)
|
35
|
+
unless override_builtin
|
36
|
+
raise ArgumentError,
|
37
|
+
"Trying to re-register a builtin colormap: %p" % name
|
38
|
+
end
|
39
|
+
end
|
40
|
+
warn "Trying to re-register the colormap %p which already exists" % name
|
41
|
+
end
|
42
|
+
|
43
|
+
unless cmap.is_a?(Colormap)
|
44
|
+
raise ArgumentError,
|
45
|
+
"Invalid value for registering a colormap (%p for a Colormap)" % cmap
|
46
|
+
end
|
47
|
+
|
48
|
+
@registry[name] = cmap
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.unregister(name)
|
52
|
+
if @registry.key?(name)
|
53
|
+
if BUILTIN_COLORMAPS.key?(name)
|
54
|
+
raise ArgumentError,
|
55
|
+
"Unable to unregister the colormap %p which is a builtin colormap" % name
|
56
|
+
end
|
57
|
+
else
|
58
|
+
@registry.delete(name)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,269 @@
|
|
1
|
+
require "matrix"
|
2
|
+
|
3
|
+
module Colors
|
4
|
+
module Convert
|
5
|
+
module_function
|
6
|
+
|
7
|
+
# Sort alphabetically by FROM name such as degree, LCh, LUV and so on.
|
8
|
+
|
9
|
+
# Utilities
|
10
|
+
|
11
|
+
private def dot_product(matrix, vector)
|
12
|
+
matrix.map do |row|
|
13
|
+
product = 0.0
|
14
|
+
row.zip(vector) do |value1, value2|
|
15
|
+
product += value1 * value2
|
16
|
+
end
|
17
|
+
product
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private def matrix_inv(matrix)
|
22
|
+
matrix = Matrix[*matrix]
|
23
|
+
matrix.inv.to_a
|
24
|
+
end
|
25
|
+
|
26
|
+
def max_chroma(l, h)
|
27
|
+
h_rad = degree_to_radian(h)
|
28
|
+
sin_h = Math.sin(h_rad).to_r
|
29
|
+
cos_h = Math.cos(h_rad).to_r
|
30
|
+
|
31
|
+
max = Float::INFINITY
|
32
|
+
luminance_bounds(l).each do |line|
|
33
|
+
len = line[1] / (sin_h - line[0] * cos_h)
|
34
|
+
max = len if 0 <= len && len < max
|
35
|
+
end
|
36
|
+
max
|
37
|
+
end
|
38
|
+
|
39
|
+
private def luminance_bounds(l)
|
40
|
+
sub1 = (l + 16)**3 / 1560896r
|
41
|
+
sub2 = sub1 > XYZ::EPSILON ? sub1 : l/XYZ::KAPPA
|
42
|
+
|
43
|
+
bounds = Array.new(6) { [0r, 0r] }
|
44
|
+
0.upto(2) do |ch|
|
45
|
+
m1 = M_XYZ_RGB[ch][0].to_r
|
46
|
+
m2 = M_XYZ_RGB[ch][1].to_r
|
47
|
+
m3 = M_XYZ_RGB[ch][2].to_r
|
48
|
+
|
49
|
+
[0, 1].each do |t|
|
50
|
+
top1 = (284517r * m1 - 94839r * m3) * sub2
|
51
|
+
top2 = (838422r * m3 + 769860r * m2 + 731718r * m1) * l * sub2 - 769860r * t * l
|
52
|
+
bottom = (632260r * m3 - 126452r * m2) * sub2 + 126452r * t
|
53
|
+
|
54
|
+
bounds[ch*2 + t][0] = top1 / bottom
|
55
|
+
bounds[ch*2 + t][1] = top2 / bottom
|
56
|
+
end
|
57
|
+
end
|
58
|
+
bounds
|
59
|
+
end
|
60
|
+
|
61
|
+
# degree -> ???
|
62
|
+
|
63
|
+
DEG2RAD = 0.01745329251994329577r # 2 * pi / 360
|
64
|
+
def degree_to_radian(d)
|
65
|
+
d * DEG2RAD
|
66
|
+
end
|
67
|
+
|
68
|
+
# LCh -> ???
|
69
|
+
|
70
|
+
def lch_to_husl(l, c, h)
|
71
|
+
if l > 99.9999999 || l < 1e-8
|
72
|
+
s = 0r
|
73
|
+
else
|
74
|
+
mx = max_chroma(l, h)
|
75
|
+
s = c / mx * 100r
|
76
|
+
end
|
77
|
+
|
78
|
+
h = 0r if c < 1e-8
|
79
|
+
|
80
|
+
[h, s/100r, l/100r]
|
81
|
+
end
|
82
|
+
|
83
|
+
def lch_to_luv(l, c, h)
|
84
|
+
h_rad = degree_to_radian(h)
|
85
|
+
u = Math.cos(h_rad).to_r * c
|
86
|
+
v = Math.sin(h_rad).to_r * c
|
87
|
+
[l, u, v]
|
88
|
+
end
|
89
|
+
|
90
|
+
def lch_to_xyz(l, c, h)
|
91
|
+
luv_to_xyz(*lch_to_luv(l, c, h))
|
92
|
+
end
|
93
|
+
|
94
|
+
# linear-sRGB -> ???
|
95
|
+
|
96
|
+
def linear_srgb_to_srgb(r, g, b)
|
97
|
+
[r, g, b].map do |v|
|
98
|
+
# the following is an optimization technique for `1.055*v**(1/2.4) - 0.055`.
|
99
|
+
# x^y ~= exp(y*log(x)) ~= exp2(y*log2(y)); the middle form is faster
|
100
|
+
#
|
101
|
+
# See https://github.com/JuliaGraphics/Colors.jl/issues/351#issuecomment-532073196
|
102
|
+
# for more detail benchmark in Julia language.
|
103
|
+
if v <= 0.0031308
|
104
|
+
12.92*v
|
105
|
+
else
|
106
|
+
1.055 * Math.exp(1/2.4 * Math.log(v)) - 0.055
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Luv -> ???
|
112
|
+
|
113
|
+
def luv_to_husl(l, u, v)
|
114
|
+
lch_to_husl(*luv_to_lch(l, u, v))
|
115
|
+
end
|
116
|
+
|
117
|
+
def luv_to_lch(l, u, v)
|
118
|
+
c = Math.sqrt(u*u + v*v).to_r
|
119
|
+
hard = Math.atan2(v, u).to_r
|
120
|
+
h = hard * 180 / Math::PI.to_r
|
121
|
+
h += 360r if h < 0
|
122
|
+
[l, c, h]
|
123
|
+
end
|
124
|
+
|
125
|
+
def luv_to_xyz(l, u, v)
|
126
|
+
return [0r, 0r, 0r] if l <= 1e-8
|
127
|
+
|
128
|
+
wp_u, wp_v = WHITE_POINT_D65.uv_values
|
129
|
+
var_u = u / (13 * l) + wp_u
|
130
|
+
var_v = v / (13 * l) + wp_v
|
131
|
+
y = if l < 8
|
132
|
+
l / XYZ::KAPPA
|
133
|
+
else
|
134
|
+
((l + 16r) / 116r)**3
|
135
|
+
end
|
136
|
+
x = -(9 * y * var_u) / ((var_u - 4) * var_v - var_u * var_v)
|
137
|
+
z = (9 * y - (15 * var_v * y) - (var_v * x)) / (3 * var_v)
|
138
|
+
[x, y, z]
|
139
|
+
end
|
140
|
+
|
141
|
+
# RGB -> ???
|
142
|
+
|
143
|
+
RGB2XYZ = [
|
144
|
+
[ 0.41239079926595948129, 0.35758433938387796373, 0.18048078840183428751 ],
|
145
|
+
[ 0.21263900587151035754, 0.71516867876775592746, 0.07219231536073371500 ],
|
146
|
+
[ 0.01933081871559185069, 0.11919477979462598791, 0.95053215224966058086 ]
|
147
|
+
]
|
148
|
+
|
149
|
+
def rgb_to_xyz(r, g, b)
|
150
|
+
dot_product(RGB2XYZ, srgb_to_linear_srgb(r, g, b))
|
151
|
+
end
|
152
|
+
|
153
|
+
def rgb_to_xterm256(r, g, b)
|
154
|
+
i = closest_xterm256_rgb_index(r)
|
155
|
+
j = closest_xterm256_rgb_index(g)
|
156
|
+
k = closest_xterm256_rgb_index(b)
|
157
|
+
|
158
|
+
r0 = xterm256_rgb_index_to_rgb_value(i)
|
159
|
+
g0 = xterm256_rgb_index_to_rgb_value(j)
|
160
|
+
b0 = xterm256_rgb_index_to_rgb_value(k)
|
161
|
+
d0 = (r - r0)**2 + (g - g0)**2 + (b - b0)**2
|
162
|
+
|
163
|
+
l = closest_xterm256_gray_index(r, g, b)
|
164
|
+
gr = xterm256_gray_index_to_gray_level(l)
|
165
|
+
d1 = (r - gr)**2 + (g - gr)**2 + (b - gr)**2
|
166
|
+
|
167
|
+
if d0 > d1
|
168
|
+
xterm256_gray_index_to_code(l)
|
169
|
+
else
|
170
|
+
xterm256_rgb_indices_to_code(i, j, k)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def xterm256_rgb_index_to_rgb_value(i)
|
175
|
+
(i == 0) ? 0 : (40*i + 55)/255.0
|
176
|
+
end
|
177
|
+
|
178
|
+
def closest_xterm256_rgb_index(x)
|
179
|
+
([x*255 - 55, 0].max / 40.0).round
|
180
|
+
end
|
181
|
+
|
182
|
+
def xterm256_gray_index_to_gray_level(i)
|
183
|
+
(10*i + 8)/255.0
|
184
|
+
end
|
185
|
+
|
186
|
+
def closest_xterm256_gray_index(r, g, b)
|
187
|
+
((255*(r + g + b) - 24)/30.0).round.clamp(0, 23)
|
188
|
+
end
|
189
|
+
|
190
|
+
def xterm256_rgb_indices_to_code(i, j, k)
|
191
|
+
6*(6*i + j) + k + 16
|
192
|
+
end
|
193
|
+
|
194
|
+
def xterm256_gray_index_to_code(i)
|
195
|
+
i + 232
|
196
|
+
end
|
197
|
+
|
198
|
+
# sRGB -> ???
|
199
|
+
|
200
|
+
def srgb_from_linear_srgb(r, g, b)
|
201
|
+
a = 0.055r
|
202
|
+
[r, g, b].map do |v|
|
203
|
+
if v < 0.0031308
|
204
|
+
12.92r * v
|
205
|
+
else
|
206
|
+
(1 + a) * v**(1/2.4r) - a
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def srgb_to_linear_srgb(r, g, b)
|
212
|
+
a = 0.055r
|
213
|
+
[r, g, b].map do |v|
|
214
|
+
if v > 0.04045
|
215
|
+
((v + a) / (1 + a)) ** 2.4r
|
216
|
+
else
|
217
|
+
v / 12.92r
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
# xyY -> ???
|
223
|
+
|
224
|
+
def xyy_to_xyz(x, y, large_y)
|
225
|
+
large_x = large_y*x/y
|
226
|
+
large_z = large_y*(1 - x - y)/y
|
227
|
+
[large_x, large_y, large_z]
|
228
|
+
end
|
229
|
+
|
230
|
+
# XYZ -> ???
|
231
|
+
|
232
|
+
# sRGB reference points
|
233
|
+
R_xyY = [0.64r, 0.33r, 1r]
|
234
|
+
G_xyY = [0.30r, 0.60r, 1r]
|
235
|
+
B_xyY = [0.15r, 0.06r, 1r]
|
236
|
+
D65_xyY = [0.3127r, 0.3290r, 1r]
|
237
|
+
|
238
|
+
R_XYZ = xyy_to_xyz(*R_xyY)
|
239
|
+
G_XYZ = xyy_to_xyz(*G_xyY)
|
240
|
+
B_XYZ = xyy_to_xyz(*B_xyY)
|
241
|
+
D65_XYZ = xyy_to_xyz(*D65_xyY)
|
242
|
+
|
243
|
+
M_P = [
|
244
|
+
[R_XYZ[0], G_XYZ[0], B_XYZ[0]],
|
245
|
+
[R_XYZ[1], G_XYZ[1], B_XYZ[1]],
|
246
|
+
[R_XYZ[2], G_XYZ[2], B_XYZ[2]]
|
247
|
+
]
|
248
|
+
|
249
|
+
M_S = dot_product(matrix_inv(M_P), D65_XYZ)
|
250
|
+
|
251
|
+
M_RGB_XYZ = (0 ... 3).map do |i|
|
252
|
+
(0 ... 3).map {|j| (M_S[j] * M_P[i][j]).round(4) }
|
253
|
+
end
|
254
|
+
|
255
|
+
M_XYZ_RGB = matrix_inv(M_RGB_XYZ).map do |row|
|
256
|
+
row.map {|v| v.round(4) }
|
257
|
+
end
|
258
|
+
|
259
|
+
def xyz_to_rgb(x, y, z)
|
260
|
+
r, g, b = dot_product(M_XYZ_RGB, [x, y, z])
|
261
|
+
r, g, b = srgb_from_linear_srgb(r, g, b)
|
262
|
+
[
|
263
|
+
r.clamp(0r, 1r),
|
264
|
+
g.clamp(0r, 1r),
|
265
|
+
b.clamp(0r, 1r)
|
266
|
+
]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
data/lib/colors/helper.rb
CHANGED
@@ -7,7 +7,8 @@ module Colors
|
|
7
7
|
|
8
8
|
private def check_range(value, range, name)
|
9
9
|
return value if range.cover?(value)
|
10
|
-
check_fail ArgumentError,
|
10
|
+
check_fail ArgumentError,
|
11
|
+
"#{name} must be in #{range}, but %p is given" % value
|
11
12
|
end
|
12
13
|
|
13
14
|
private def check_fail(exc_class, message)
|
data/lib/colors/husl.rb
CHANGED
@@ -1,45 +1,7 @@
|
|
1
|
-
require "numo/narray"
|
2
|
-
|
3
1
|
module Colors
|
4
2
|
# Human-friendly alternative to HSL color space.
|
5
3
|
# The definition of HUSL is provided in <http://www.hsluv.org>.
|
6
4
|
class HUSL < HSL
|
7
|
-
DEG2RAD = 0.01745329251994329577r # 2 * pi / 360
|
8
|
-
|
9
|
-
def self.from_rgb(r, g, b)
|
10
|
-
c = XYZ.from_rgb(r, g, b)
|
11
|
-
l, u, v = c.luv_components(WHITE_POINT_D65)
|
12
|
-
l, c, h = convert_luv_to_lch(l, u, v)
|
13
|
-
h, s, l = convert_lch_to_husl(l, c, h)
|
14
|
-
new(h, s.to_r.clamp(0r, 1r), l.to_r.clamp(0r, 1r))
|
15
|
-
end
|
16
|
-
|
17
|
-
private_class_method def self.convert_luv_to_lch(l, u, v)
|
18
|
-
c = Math.sqrt(u*u + v*v).to_r
|
19
|
-
|
20
|
-
if c < 1e-8
|
21
|
-
h = 0r
|
22
|
-
else
|
23
|
-
h = Math.atan2(v, u).to_r * 180/Math::PI.to_r
|
24
|
-
h += 360r if h < 0
|
25
|
-
end
|
26
|
-
|
27
|
-
[l, c, h]
|
28
|
-
end
|
29
|
-
|
30
|
-
private_class_method def self.convert_lch_to_husl(l, c, h)
|
31
|
-
if l > 99.9999999 || l < 1e-8
|
32
|
-
s = 0r
|
33
|
-
else
|
34
|
-
mx = max_chroma(l, h)
|
35
|
-
s = c / mx * 100r
|
36
|
-
end
|
37
|
-
|
38
|
-
h = 0r if c < 1e-8
|
39
|
-
|
40
|
-
[h, s/100r, l/100r]
|
41
|
-
end
|
42
|
-
|
43
5
|
def ==(other)
|
44
6
|
case other
|
45
7
|
when HUSL
|
@@ -61,10 +23,13 @@ module Colors
|
|
61
23
|
RGB.new(*rgb_components)
|
62
24
|
end
|
63
25
|
|
26
|
+
def to_xyz
|
27
|
+
x, y, z = Convert.lch_to_xyz(*lch_components)
|
28
|
+
XYZ.new(x, y, z)
|
29
|
+
end
|
30
|
+
|
64
31
|
def rgb_components
|
65
|
-
|
66
|
-
x, y, z = convert_luv_to_xyz(l, u, v)
|
67
|
-
XYZ.new(x, y, z).rgb_components
|
32
|
+
to_xyz.rgb_components
|
68
33
|
end
|
69
34
|
|
70
35
|
def lch_components
|
@@ -74,7 +39,7 @@ module Colors
|
|
74
39
|
if l > 99.9999999 || l < 1e-8
|
75
40
|
c = 0r
|
76
41
|
else
|
77
|
-
mx =
|
42
|
+
mx = Convert.max_chroma(l, h)
|
78
43
|
c = mx / 100r * s
|
79
44
|
end
|
80
45
|
|
@@ -82,63 +47,5 @@ module Colors
|
|
82
47
|
|
83
48
|
[l, c, h]
|
84
49
|
end
|
85
|
-
|
86
|
-
private def convert_lch_to_luv(l, c, h)
|
87
|
-
h_rad = h * DEG2RAD
|
88
|
-
u = Math.cos(h_rad).to_r * c
|
89
|
-
v = Math.sin(h_rad).to_r * c
|
90
|
-
[l, u, v]
|
91
|
-
end
|
92
|
-
|
93
|
-
private def convert_luv_to_xyz(l, u, v)
|
94
|
-
return [0r, 0r, 0r] if l <= 1e-8
|
95
|
-
|
96
|
-
wp_u, wp_v = WHITE_POINT_D65.uv_values
|
97
|
-
var_u = u / (13 * l) + wp_u
|
98
|
-
var_v = v / (13 * l) + wp_v
|
99
|
-
y = if l < 8
|
100
|
-
l / XYZ::KAPPA
|
101
|
-
else
|
102
|
-
((l + 16r) / 116r)**3
|
103
|
-
end
|
104
|
-
x = -(9 * y * var_u) / ((var_u - 4) * var_v - var_u * var_v)
|
105
|
-
z = (9 * y - (15 * var_v * y) - (var_v * x)) / (3 * var_v)
|
106
|
-
[x, y, z]
|
107
|
-
end
|
108
|
-
|
109
|
-
def self.max_chroma(l, h)
|
110
|
-
h_rad = h * DEG2RAD
|
111
|
-
sin_h = Math.sin(h_rad).to_r
|
112
|
-
cos_h = Math.cos(h_rad).to_r
|
113
|
-
|
114
|
-
result = Float::INFINITY
|
115
|
-
get_bounds(l).each do |line|
|
116
|
-
len = line[1] / (sin_h - line[0] * cos_h)
|
117
|
-
result = len if 0 <= len && len < result
|
118
|
-
end
|
119
|
-
result
|
120
|
-
end
|
121
|
-
|
122
|
-
def self.get_bounds(l)
|
123
|
-
sub1 = (l + 16)**3 / 1560896r
|
124
|
-
sub2 = sub1 > XYZ::EPSILON ? sub1 : l/XYZ::KAPPA
|
125
|
-
|
126
|
-
bounds = Array.new(6) { [0r, 0r] }
|
127
|
-
0.upto(2) do |ch|
|
128
|
-
m1 = XYZ2RGB[ch, 0].to_r
|
129
|
-
m2 = XYZ2RGB[ch, 1].to_r
|
130
|
-
m3 = XYZ2RGB[ch, 2].to_r
|
131
|
-
|
132
|
-
[0, 1].each do |t|
|
133
|
-
top1 = (284517r * m1 - 94839r * m3) * sub2
|
134
|
-
top2 = (838422r * m3 + 769860r * m2 + 731718r * m1) * l * sub2 - 769860r * t * l
|
135
|
-
bottom = (632260r * m3 - 126452r * m2) * sub2 + 126452r * t
|
136
|
-
|
137
|
-
bounds[ch*2 + t][0] = top1 / bottom
|
138
|
-
bounds[ch*2 + t][1] = top2 / bottom
|
139
|
-
end
|
140
|
-
end
|
141
|
-
bounds
|
142
|
-
end
|
143
50
|
end
|
144
51
|
end
|