esp32_ethernet_milight_hub/test/remote/helpers/transition_helpers.rb
2021-01-15 22:49:01 +01:00

131 lines
No EOL
3.7 KiB
Ruby

require 'chroma'
module TransitionHelpers
module Defaults
PERIOD = 500
NUM_PERIODS = 20
DURATION = PERIOD * NUM_PERIODS
end
def highlight_value(a, highlight_ix)
str = a
.each_with_index
.map do |x, i|
i == highlight_ix ? ">>#{x}<<" : x
end
.join(', ')
"[#{str}]"
end
def color_transitions_are_equal(expected:, seen:)
%i(hue saturation).each do |label|
e = expected.map { |x| x[label] }
s = seen.map { |x| x[label] }
transitions_are_equal(expected: e, seen: s, label: label, allowed_variation: label == :saturation ? 5 : 20)
end
end
def transitions_are_equal(expected:, seen:, allowed_variation: 0, label: nil)
generate_msg = ->(a, b, i) do
s = "Transition step value"
if !label.nil?
s << " for #{label} "
end
s << "at index #{i} "
s << if allowed_variation == 0
"should be equal to expected value. Expected: #{a}, saw: #{b}."
else
"should be within #{allowed_variation} of expected value. Expected: #{a}, saw: #{b}."
end
s << " Steps:\n"
s << " Expected : #{highlight_value(expected, i)},\n"
s << " Seen : #{highlight_value(seen, i)}"
end
expect(expected.length).to eq(seen.length),
"Transition was a different length than expected.\n" <<
" Expected : #{expected}\n" <<
" Seen : #{seen}"
expected.zip(seen).each_with_index do |x, i|
a, b = x
diff = (a - b).abs
expect(diff).to be <= allowed_variation, generate_msg.call(a, b, i)
end
end
def rgb_to_hs(*color)
if color.length > 1
r, g, b = color
else
r, g, b = coerce_color(color.first)
end
hsv = Chroma::Converters::HsvConverter.convert_rgb(Chroma::ColorModes::Rgb.new(r, g, b))
{ hue: hsv.h.round, saturation: (100*hsv.s).round }
end
def coerce_color(c)
c.split(',').map(&:to_i) unless c.is_a?(Array)
end
def calculate_color_transition_steps(start_color:, end_color:, duration: nil, period: nil, num_periods: Defaults::NUM_PERIODS)
start_color = coerce_color(start_color)
end_color = coerce_color(end_color)
part_transitions = start_color.zip(end_color).map do |c|
s, e = c
calculate_transition_steps(start_value: s, end_value: e, duration: duration, period: period, num_periods: num_periods)
end
# If some colors don't transition, they'll stay at the same value while others move.
# Turn this: [[1,2,3], [0], [4,5,6]]
# Into this: [[1,2,3], [0,0,0], [4,5,6]]
longest = part_transitions.max_by { |x| x.length }.length
part_transitions.map! { |x| x + [x.last]*(longest-x.length) }
# Zip individual parts into 3-tuples
# Turn this: [[1,2,3], [0,0,0], [4,5,6]]
# Into this: [[1,0,4], [2,0,5], [3,0,6]]
transition_colors = part_transitions.first.zip(*part_transitions[1..part_transitions.length])
# Undergo the RGB -> HSV w/ value = 100
transition_colors.map do |x|
r, g, b = x
rgb_to_hs(r, g, b)
end
end
def calculate_transition_steps(start_value:, end_value:, duration: nil, period: nil, num_periods: Defaults::NUM_PERIODS)
if !duration.nil? || !period.nil?
period ||= Defaults::PERIOD
duration ||= Defaults::DURATION
num_periods = [1, (duration / period.to_f).ceil].max
end
diff = end_value - start_value
step_size = [1, (diff.abs / num_periods.to_f).ceil].max
step_size = -step_size if end_value < start_value
steps = []
val = start_value
while val != end_value
steps << val
if (end_value - val).abs < step_size.abs
val += (end_value - val)
else
val += step_size
end
end
steps << end_value
steps
end
end