dawarich/app/services/visits/prepare.rb

81 lines
2.5 KiB
Ruby
Raw Normal View History

2024-08-12 16:18:11 -04:00
# frozen_string_literal: true
class Visits::Prepare
attr_reader :points
def initialize(points)
@points = points
end
def call
points_by_day = points.group_by { |point| point_date(point) }
points_by_day.map do |day, day_points|
day_points.sort_by!(&:timestamp)
grouped_points = Visits::GroupPoints.new(day_points).group_points_by_radius
day_result = prepare_day_result(grouped_points)
# Iterate through the day_result, check if there are any points outside
# of visits that are between two consecutive visits. If there are none,
# merge the visits.
2024-09-05 15:01:59 -04:00
day_result.each_cons(2) do |visit1, visit2|
next if visit1[:points].last == visit2[:points].first
points_between_visits = day_points.select do |point|
point.timestamp > visit1[:points].last.timestamp &&
point.timestamp < visit2[:points].first.timestamp
end
if points_between_visits.any?
# If there are points between the visits, we need to check if they are close enough to the visits to be considered part of them.
points_between_visits.each do |point|
next unless visit1[:points].last.distance_to(point) < visit1[:radius] ||
visit2[:points].first.distance_to(point) < visit2[:radius] ||
(point.timestamp - visit1[:points].last.timestamp).to_i < 600
visit1[:points] << point
end
end
visit1[:points] += visit2[:points]
visit1[:duration] = (visit1[:points].last.timestamp - visit1[:points].first.timestamp).to_i / 60
visit1[:ended_at] = Time.zone.at(visit1[:points].last.timestamp)
day_result.delete(visit2)
end
2024-08-12 16:18:11 -04:00
next if day_result.blank?
{ date: day, visits: day_result }
end.compact
end
private
def point_date(point) = Time.zone.at(point.timestamp).to_date.to_s
def calculate_radius(center_point, group)
max_distance = group.map { |point| center_point.distance_to(point) }.max
(max_distance / 10.0).ceil * 10
2024-08-12 16:18:11 -04:00
end
def prepare_day_result(grouped_points)
grouped_points.map do |group|
center_point = group.first
{
latitude: center_point.lat,
longitude: center_point.lon,
2024-08-12 16:18:11 -04:00
radius: calculate_radius(center_point, group),
points: group,
2024-09-05 15:01:59 -04:00
duration: (group.last.timestamp - group.first.timestamp).to_i / 60,
started_at: Time.zone.at(group.first.timestamp).to_s,
ended_at: Time.zone.at(group.last.timestamp).to_s
2024-08-12 16:18:11 -04:00
}
end
end
end