53 lines
2.0 KiB
Dart
53 lines
2.0 KiB
Dart
import 'dart:math' as math;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Attendance math + filter rules (shared by UI and background service).
|
|
//
|
|
// Simple version:
|
|
// - Wake every 5 min, take ONE gps reading, sleep again (battery safe).
|
|
// - Throw away weak readings (error > 50 m).
|
|
// - Throw away tiny jumps (< 20 m) so sitting still never invents fake km.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
/// How often the background service takes one GPS reading.
|
|
const Duration kFixInterval = Duration(minutes: 5);
|
|
|
|
/// Max seconds to wait for a single GPS fix before giving up.
|
|
const Duration kFixTimeout = Duration(seconds: 30);
|
|
|
|
/// Discard any fix whose own accuracy error is worse than this (meters).
|
|
const double kMaxAcceptableAccuracyMeters = 50.0;
|
|
|
|
/// Ignore movement smaller than this (meters) - kills stationary drift.
|
|
const double kMinMoveMeters = 20.0;
|
|
|
|
/// Straight-line distance between two lat/lng points, in meters.
|
|
double haversineMeters(double lat1, double lon1, double lat2, double lon2) {
|
|
const double earthRadius = 6371000.0; // meters
|
|
final double dLat = _toRadians(lat2 - lat1);
|
|
final double dLon = _toRadians(lon2 - lon1);
|
|
final double a = math.sin(dLat / 2) * math.sin(dLat / 2) +
|
|
math.cos(_toRadians(lat1)) *
|
|
math.cos(_toRadians(lat2)) *
|
|
math.sin(dLon / 2) *
|
|
math.sin(dLon / 2);
|
|
final double c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
|
|
return earthRadius * c;
|
|
}
|
|
|
|
double _toRadians(double degrees) => degrees * math.pi / 180.0;
|
|
|
|
/// Decides whether a new fix is worth storing. Returns true only when the
|
|
/// reading is strong enough AND the person actually moved.
|
|
bool shouldStorePoint({
|
|
required double accuracy,
|
|
required double distanceFromLastMeters,
|
|
required bool isFirstPoint,
|
|
}) {
|
|
if (accuracy > kMaxAcceptableAccuracyMeters) return false; // weak signal
|
|
if (!isFirstPoint && distanceFromLastMeters < kMinMoveMeters) {
|
|
return false; // standing still (drift)
|
|
}
|
|
return true;
|
|
}
|