From 1e207f297c9b0e7340159c456be1217058feb567 Mon Sep 17 00:00:00 2001 From: Eugene Burmakin Date: Sun, 4 Aug 2024 14:03:52 +0200 Subject: [PATCH] Experiment with visits detection --- .app_version | 2 +- Gemfile | 2 + Gemfile.lock | 6 +++ app/services/visits/detect.rb | 77 +++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 app/services/visits/detect.rb diff --git a/.app_version b/.app_version index e3e18070..7e310bae 100644 --- a/.app_version +++ b/.app_version @@ -1 +1 @@ -0.9.8 +0.9.9 diff --git a/Gemfile b/Gemfile index d72ba5b6..4075626b 100644 --- a/Gemfile +++ b/Gemfile @@ -9,6 +9,8 @@ gem 'chartkick' gem 'data_migrate' gem 'devise' gem 'geocoder' +gem 'geokit' +gem 'geokit-rails' gem 'importmap-rails' gem 'kaminari' gem 'lograge' diff --git a/Gemfile.lock b/Gemfile.lock index 4e479a87..314315ce 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -135,6 +135,10 @@ GEM geocoder (1.8.3) base64 (>= 0.1.0) csv (>= 3.0.0) + geokit (1.14.0) + geokit-rails (2.5.0) + geokit (~> 1.5) + rails (>= 3.0) globalid (1.2.1) activesupport (>= 6.1) hashdiff (1.1.0) @@ -423,6 +427,8 @@ DEPENDENCIES ffaker foreman geocoder + geokit + geokit-rails importmap-rails kaminari lograge diff --git a/app/services/visits/detect.rb b/app/services/visits/detect.rb new file mode 100644 index 00000000..f50d149e --- /dev/null +++ b/app/services/visits/detect.rb @@ -0,0 +1,77 @@ +require 'geokit' + +class Visits::Detect + def initialize + a = 5.days.ago.beginning_of_month + b = 5.days.ago.end_of_month + @points = Point.order(timestamp: :asc).where(timestamp: a..b) + end + + def call + # Group points by day + points_by_day = @points.group_by { |point| point_date(point) } + + # Iterate through each day's points + points_by_day.each do |day, day_points| + # Sort points by timestamp + day_points.sort_by! { |point| point.timestamp } + + # Call the method for each day's points + grouped_points = group_points_by_radius(day_points) + + # Print the grouped points for the day + puts "Day: #{day}" + grouped_points.each_with_index do |group, index| + puts "Group #{index + 1}:" + group.each do |point| + puts point + end + end + end + end + + private + + # Method to convert timestamp to date + def point_date(point) + Time.zone.at(point.timestamp).to_date + end + + # Method to check if two points are within a certain radius (in meters) + def within_radius?(point1, point2, radius) + loc1 = Geokit::LatLng.new(point1.latitude, point1.longitude) + loc2 = Geokit::LatLng.new(point2.latitude, point2.longitude) + loc1.distance_to(loc2, units: :kms) * 1000 <= radius + end + + # Method to group points by increasing radius + def group_points_by_radius(day_points, initial_radius = 30, max_radius = 100, step = 10) + grouped = [] + remaining_points = day_points.dup + + while remaining_points.any? + point = remaining_points.shift + group = [point] + radius = initial_radius + + while radius <= max_radius + remaining_points.each do |next_point| + group << next_point if within_radius?(point, next_point, radius) + end + + if group.size > 1 + remaining_points -= group + grouped << group + break + else + radius += step + end + end + end + + grouped + end +end + +# Execute the detection +# Visits::Detect.new.call