lib/fusuma/plugin/detectors/rotate_detector.rb in fusuma-2.0.0.pre vs lib/fusuma/plugin/detectors/rotate_detector.rb in fusuma-2.0.0.pre2

- old
+ new

@@ -1,111 +1,152 @@ # frozen_string_literal: true -require_relative './detector.rb' +require_relative './detector' module Fusuma module Plugin module Detectors class RotateDetector < Detector + SOURCES = ['gesture'].freeze BUFFER_TYPE = 'gesture' GESTURE_RECORD_TYPE = 'pinch' FINGERS = [2, 3, 4].freeze BASE_THERESHOLD = 0.5 - BASE_INTERVAL = 0.1 # @param buffers [Array<Buffer>] - # @return [Event] if event is detected + # @return [Events::Event] if event is detected # @return [NilClass] if event is NOT detected def detect(buffers) - buffer = buffers.find { |b| b.type == BUFFER_TYPE } - .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE } + gesture_buffer = buffers.find { |b| b.type == BUFFER_TYPE } + .select_from_last_begin + .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE } - return if buffer.empty? + updating_events = gesture_buffer.updating_events + return if updating_events.empty? - angle = buffer.avg_attrs(:rotate) + updating_time = 100 * (updating_events.last.time - updating_events.first.time) + oneshot_angle = gesture_buffer.sum_attrs(:rotate) / updating_time - finger = buffer.finger - direction = Direction.new(angle: angle).to_s - quantity = Quantity.new(angle: angle).to_f + return if updating_events.empty? - index = create_index(gesture: type, - finger: finger, - direction: direction) + finger = gesture_buffer.finger - return unless enough?(index: index, quantity: quantity) + status = case gesture_buffer.events.last.record.status + when 'end' + 'end' + when 'update' + if updating_events.length == 1 + 'begin' + else + 'update' + end + else + gesture_buffer.events.last.record.status + end - create_event(record: Events::Records::IndexRecord.new(index: index)) + delta = if status == 'end' + gesture_buffer.events[-2].record.delta + else + gesture_buffer.events.last.record.delta + end + + repeat_direction = Direction.new(angle: delta.rotate).to_s + repeat_quantity = Quantity.new(angle: delta.rotate).to_f + + repeat_index = create_repeat_index(gesture: type, finger: finger, + direction: repeat_direction, + status: status) + + if status == 'update' + return unless moved?(repeat_quantity) + + oneshot_direction = Direction.new(angle: oneshot_angle).to_s + oneshot_quantity = Quantity.new(angle: oneshot_angle).to_f + oneshot_index = create_oneshot_index(gesture: type, finger: finger, + direction: oneshot_direction) + if enough_oneshot_threshold?(index: oneshot_index, quantity: oneshot_quantity) + return [ + create_event(record: Events::Records::IndexRecord.new( + index: oneshot_index, trigger: :oneshot, args: delta.to_h + )), + create_event(record: Events::Records::IndexRecord.new( + index: repeat_index, trigger: :repeat, args: delta.to_h + )) + ] + end + end + create_event(record: Events::Records::IndexRecord.new( + index: repeat_index, trigger: :repeat, args: delta.to_h + )) end # @param [String] gesture # @param [Integer] finger # @param [String] direction + # @param [String] status # @return [Config::Index] - def create_index(gesture:, finger:, direction:) + def create_repeat_index(gesture:, finger:, direction:, status:) Config::Index.new( [ Config::Index::Key.new(gesture), + Config::Index::Key.new(finger.to_i), + Config::Index::Key.new(direction), + Config::Index::Key.new(status) + ] + ) + end + + # @param [String] gesture + # @param [Integer] finger + # @param [String] direction + # @return [Config::Index] + def create_oneshot_index(gesture:, finger:, direction:) + Config::Index.new( + [ + Config::Index::Key.new(gesture), Config::Index::Key.new(finger.to_i, skippable: true), Config::Index::Key.new(direction) ] ) end private - def enough?(index:, quantity:) - enough_interval?(index: index) && enough_angle?(index: index, quantity: quantity) + def moved?(repeat_quantity) + repeat_quantity > 0.2 end - def enough_angle?(index:, quantity:) + def enough_oneshot_threshold?(index:, quantity:) quantity > threshold(index: index) end - def enough_interval?(index:) - return true if first_time? - return true if (Time.now - last_time) > interval_time(index: index) - - false - end - def threshold(index:) @threshold ||= {} @threshold[index.cache_key] ||= begin - keys_specific = Config::Index.new [*index.keys, 'threshold'] - keys_global = Config::Index.new ['threshold', type] - config_value = Config.search(keys_specific) || - Config.search(keys_global) || 1 - BASE_THERESHOLD * config_value - end + keys_specific = Config::Index.new [*index.keys, 'threshold'] + keys_global = Config::Index.new ['threshold', type] + config_value = Config.search(keys_specific) || + Config.search(keys_global) || 1 + BASE_THERESHOLD * config_value + end end - def interval_time(index:) - @interval_time ||= {} - @interval_time[index.cache_key] ||= begin - keys_specific = Config::Index.new [*index.keys, 'interval'] - keys_global = Config::Index.new ['interval', type] - config_value = Config.search(keys_specific) || - Config.search(keys_global) || 1 - BASE_INTERVAL * config_value - end - end - # direction of gesture class Direction CLOCKWISE = 'clockwise' COUNTERCLOCKWISE = 'counterclockwise' def initialize(angle:) - @angle = angle + @angle = angle.to_f end def to_s calc end def calc - if @angle > 0 + if @angle.positive? CLOCKWISE else COUNTERCLOCKWISE end end