mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
Store track distance in user's preferred unit
This commit is contained in:
parent
0d657b9d6e
commit
f33dcdfe21
10 changed files with 56 additions and 51 deletions
|
|
@ -26,7 +26,6 @@ class MapController < ApplicationController
|
|||
end
|
||||
|
||||
def extract_track_ids
|
||||
# Extract track IDs from coordinates (index 8: [lat, lng, battery, altitude, timestamp, velocity, id, country, track_id])
|
||||
@coordinates.map { |coord| coord[8]&.to_i }.compact.uniq.reject(&:zero?)
|
||||
end
|
||||
|
||||
|
|
@ -44,15 +43,14 @@ class MapController < ApplicationController
|
|||
)
|
||||
end
|
||||
|
||||
# Convert distance to meters for consistent storage
|
||||
distance_in_meters = case current_user.safe_settings.distance_unit.to_s
|
||||
when 'miles', 'mi'
|
||||
when 'mi'
|
||||
distance * 1609.344 # miles to meters
|
||||
else
|
||||
distance * 1000 # km to meters
|
||||
end
|
||||
|
||||
distance_in_meters.round # Return as integer meters
|
||||
distance_in_meters.round
|
||||
end
|
||||
|
||||
def parsed_start_at
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export function createTrackPopupContent(track, distanceUnit) {
|
|||
<strong>🕐 Start:</strong> ${startTime}<br>
|
||||
<strong>🏁 End:</strong> ${endTime}<br>
|
||||
<strong>⏱️ Duration:</strong> ${durationFormatted}<br>
|
||||
<strong>📏 Distance:</strong> ${formatDistance(track.distance / 1000, distanceUnit)}<br>
|
||||
<strong>📏 Distance:</strong> ${formatDistance(track.distance, distanceUnit)}<br>
|
||||
<strong>⚡ Avg Speed:</strong> ${formatSpeed(track.avg_speed, distanceUnit)}<br>
|
||||
<strong>⛰️ Elevation:</strong> +${track.elevation_gain || 0}m / -${track.elevation_loss || 0}m<br>
|
||||
<strong>📊 Max Alt:</strong> ${track.elevation_max || 0}m<br>
|
||||
|
|
@ -356,8 +356,8 @@ export function toggleTracksVisibility(tracksLayer, map, isVisible) {
|
|||
// Helper function to filter tracks by criteria
|
||||
export function filterTracks(tracks, criteria) {
|
||||
return tracks.filter(track => {
|
||||
if (criteria.minDistance && track.distance < criteria.minDistance * 1000) return false;
|
||||
if (criteria.maxDistance && track.distance > criteria.maxDistance * 1000) return false;
|
||||
if (criteria.minDistance && track.distance < criteria.minDistance) return false;
|
||||
if (criteria.maxDistance && track.distance > criteria.maxDistance) return false;
|
||||
if (criteria.minDuration && track.duration < criteria.minDuration * 60) return false;
|
||||
if (criteria.maxDuration && track.duration > criteria.maxDuration * 60) return false;
|
||||
if (criteria.startDate && new Date(track.start_at) < new Date(criteria.startDate)) return false;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class IncrementalTrackGeneratorJob < ApplicationJob
|
||||
class Tracks::IncrementalGeneratorJob < ApplicationJob
|
||||
queue_as :default
|
||||
sidekiq_options retry: 3
|
||||
|
||||
|
|
@ -53,28 +53,14 @@ module Calculateable
|
|||
end
|
||||
|
||||
def convert_distance_for_storage(calculated_distance)
|
||||
if track_model?
|
||||
convert_distance_to_meters(calculated_distance)
|
||||
else
|
||||
# For Trip model - store rounded distance in user's preferred unit
|
||||
calculated_distance.round
|
||||
end
|
||||
# Store distance in user's preferred unit with 2 decimal places precision
|
||||
calculated_distance.round(2)
|
||||
end
|
||||
|
||||
def track_model?
|
||||
self.class.name == 'Track'
|
||||
end
|
||||
|
||||
def convert_distance_to_meters(calculated_distance)
|
||||
# For Track model - convert to meters for storage (Track expects distance in meters)
|
||||
case user_distance_unit.to_s
|
||||
when 'mi'
|
||||
(calculated_distance * 1609.344).round # miles to meters
|
||||
else
|
||||
(calculated_distance * 1000).round # km to meters
|
||||
end
|
||||
end
|
||||
|
||||
def save_if_changed!
|
||||
save! if changed?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,19 +44,12 @@ module Tracks::TrackBuilder
|
|||
Tracks::BuildPath.new(points.map(&:lonlat)).call
|
||||
end
|
||||
|
||||
# Calculate track distance in meters for storage
|
||||
# Calculate track distance in user's preferred unit for storage
|
||||
# @param points [Array<Point>] array of Point objects
|
||||
# @return [Integer] distance in meters
|
||||
# @return [Float] distance in user's preferred unit with 2 decimal places precision
|
||||
def calculate_track_distance(points)
|
||||
distance_in_user_unit = Point.total_distance(points, user.safe_settings.distance_unit || 'km')
|
||||
|
||||
# Convert to meters for storage (Track model expects distance in meters)
|
||||
case user.safe_settings.distance_unit
|
||||
when 'miles', 'mi'
|
||||
(distance_in_user_unit * 1609.344).round # miles to meters
|
||||
else
|
||||
(distance_in_user_unit * 1000).round # km to meters
|
||||
end
|
||||
distance_in_user_unit.round(2)
|
||||
end
|
||||
|
||||
# Calculate track duration in seconds
|
||||
|
|
@ -67,11 +60,19 @@ module Tracks::TrackBuilder
|
|||
end
|
||||
|
||||
# Calculate average speed in km/h
|
||||
# @param distance_meters [Numeric] distance in meters
|
||||
# @param distance_in_user_unit [Numeric] distance in user's preferred unit
|
||||
# @param duration_seconds [Numeric] duration in seconds
|
||||
# @return [Float] average speed in km/h
|
||||
def calculate_average_speed(distance_meters, duration_seconds)
|
||||
return 0.0 if duration_seconds <= 0 || distance_meters <= 0
|
||||
def calculate_average_speed(distance_in_user_unit, duration_seconds)
|
||||
return 0.0 if duration_seconds <= 0 || distance_in_user_unit <= 0
|
||||
|
||||
# Convert distance to meters for speed calculation
|
||||
distance_meters = case user.safe_settings.distance_unit
|
||||
when 'miles', 'mi'
|
||||
distance_in_user_unit * 1609.344 # miles to meters
|
||||
else
|
||||
distance_in_user_unit * 1000 # km to meters
|
||||
end
|
||||
|
||||
# Speed in meters per second, then convert to km/h for storage
|
||||
speed_mps = distance_meters.to_f / duration_seconds
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ class CreateTracks < ActiveRecord::Migration[8.0]
|
|||
t.datetime :end_at, null: false
|
||||
t.references :user, null: false, foreign_key: true
|
||||
t.line_string :original_path, null: false
|
||||
t.integer :distance
|
||||
t.decimal :distance, precision: 8, scale: 2
|
||||
t.float :avg_speed
|
||||
t.integer :duration
|
||||
t.integer :elevation_gain
|
||||
|
|
|
|||
|
|
@ -120,5 +120,25 @@ RSpec.describe Point, type: :model do
|
|||
expect(point.lat).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#recalculate_track' do
|
||||
let(:point) { create(:point, track: track) }
|
||||
let(:track) { create(:track) }
|
||||
|
||||
it 'recalculates the track' do
|
||||
expect(track).to receive(:recalculate_path_and_distance!)
|
||||
|
||||
point.update(lonlat: 'POINT(-79.85581250721961 15.854775993302411)')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#trigger_incremental_track_generation' do
|
||||
let(:point) { create(:point, track: track) }
|
||||
let(:track) { create(:track) }
|
||||
|
||||
it 'enqueues Tracks::IncrementalGeneratorJob' do
|
||||
expect { point.trigger_incremental_track_generation }.to have_enqueued_job(Tracks::IncrementalGeneratorJob)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -143,16 +143,16 @@ RSpec.describe Track, type: :model do
|
|||
track.calculate_distance
|
||||
|
||||
expect(track.distance).to be > 0
|
||||
expect(track.distance).to be_a(Integer)
|
||||
expect(track.distance).to be_a(Numeric)
|
||||
end
|
||||
|
||||
it 'stores distance in meters for Track model' do
|
||||
it 'stores distance in user preferred unit for Track model' do
|
||||
allow(user).to receive(:safe_settings).and_return(double(distance_unit: 'km'))
|
||||
allow(Point).to receive(:total_distance).and_return(1.5) # 1.5 km
|
||||
|
||||
track.calculate_distance
|
||||
|
||||
expect(track.distance).to eq(1500) # Should be in meters as integer
|
||||
expect(track.distance).to eq(1.5) # Should be 1.5 km with 2 decimal places precision
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -274,9 +274,9 @@ RSpec.describe Tracks::CreateFromPoints do
|
|||
allow(Point).to receive(:total_distance).and_return(1.5) # 1.5 km
|
||||
end
|
||||
|
||||
it 'converts km to meters by default' do
|
||||
it 'stores distance in km by default' do
|
||||
distance = service.send(:calculate_track_distance, points)
|
||||
expect(distance).to eq(1500) # 1.5 km = 1500 meters
|
||||
expect(distance).to eq(1.5) # 1.5 km with 2 decimal places precision
|
||||
end
|
||||
|
||||
context 'with miles unit' do
|
||||
|
|
@ -284,9 +284,9 @@ RSpec.describe Tracks::CreateFromPoints do
|
|||
user.update!(settings: user.settings.merge({'maps' => {'distance_unit' => 'miles'}}))
|
||||
end
|
||||
|
||||
it 'converts miles to meters' do
|
||||
it 'stores distance in miles' do
|
||||
distance = service.send(:calculate_track_distance, points)
|
||||
expect(distance).to eq(2414) # 1.5 miles ≈ 2414 meters (rounded)
|
||||
expect(distance).to eq(1.5) # 1.5 miles with 2 decimal places precision
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -138,9 +138,9 @@ RSpec.describe Tracks::TrackBuilder do
|
|||
allow(Point).to receive(:total_distance).and_return(1.5) # 1.5 km
|
||||
end
|
||||
|
||||
it 'converts km to meters' do
|
||||
it 'stores distance in km' do
|
||||
result = builder.calculate_track_distance(points)
|
||||
expect(result).to eq(1500) # 1.5 km = 1500 meters
|
||||
expect(result).to eq(1.5) # 1.5 km with 2 decimal places precision
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -150,9 +150,9 @@ RSpec.describe Tracks::TrackBuilder do
|
|||
allow(Point).to receive(:total_distance).and_return(1.0) # 1 mile
|
||||
end
|
||||
|
||||
it 'converts miles to meters' do
|
||||
it 'stores distance in miles' do
|
||||
result = builder.calculate_track_distance(points)
|
||||
expect(result).to eq(1609) # 1 mile ≈ 1609 meters
|
||||
expect(result).to eq(1) # 1 mile
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -162,9 +162,9 @@ RSpec.describe Tracks::TrackBuilder do
|
|||
allow(Point).to receive(:total_distance).and_return(2.0)
|
||||
end
|
||||
|
||||
it 'defaults to km and converts to meters' do
|
||||
it 'defaults to km and stores distance in km' do
|
||||
result = builder.calculate_track_distance(points)
|
||||
expect(result).to eq(2000)
|
||||
expect(result).to eq(2.0) # 2.0 km with 2 decimal places precision
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue