aves_mio0.31/lib/model/activity/activity_track.dart.ok
2026-07-18 13:39:22 +02:00

189 lines
4.5 KiB
Text

// lib/model/activity/activity_track.dart
import 'package:latlong2/latlong.dart';
class ActivityTrack {
final String name;
final String format;
final Set<List<LatLng>> tracks;
/// Numero punti validi letti dal file prima di eventuale semplificazione grafica.
final int pointCount;
final double? distanceMeters;
final double? elevationGainMeters;
final Duration? duration;
final DateTime? startTime;
final String? sport;
final String? diagnostics;
const ActivityTrack({
required this.name,
required this.format,
required this.tracks,
required this.pointCount,
this.distanceMeters,
this.elevationGainMeters,
this.duration,
this.startTime,
this.sport,
this.diagnostics,
});
bool get isEmpty => tracks.isEmpty || tracks.every((segment) => segment.isEmpty);
Iterable<LatLng> get points sync* {
for (final segment in tracks) {
yield* segment;
}
}
List<LatLng> get validPoints {
return points
.where(
(point) =>
point.latitude.isFinite &&
point.longitude.isFinite &&
point.latitude.abs() <= 90 &&
point.longitude.abs() <= 180,
)
.toList(growable: false);
}
int get displayPointCount => validPoints.length;
LatLng? get center {
final allPoints = validPoints;
if (allPoints.isEmpty) return null;
final latitude = allPoints.fold<double>(
0,
(sum, point) => sum + point.latitude,
) /
allPoints.length;
final longitude = allPoints.fold<double>(
0,
(sum, point) => sum + point.longitude,
) /
allPoints.length;
return LatLng(latitude, longitude);
}
double? get minLatitude {
final allPoints = validPoints;
if (allPoints.isEmpty) return null;
return allPoints
.map((point) => point.latitude)
.reduce((a, b) => a < b ? a : b);
}
double? get maxLatitude {
final allPoints = validPoints;
if (allPoints.isEmpty) return null;
return allPoints
.map((point) => point.latitude)
.reduce((a, b) => a > b ? a : b);
}
double? get minLongitude {
final allPoints = validPoints;
if (allPoints.isEmpty) return null;
return allPoints
.map((point) => point.longitude)
.reduce((a, b) => a < b ? a : b);
}
double? get maxLongitude {
final allPoints = validPoints;
if (allPoints.isEmpty) return null;
return allPoints
.map((point) => point.longitude)
.reduce((a, b) => a > b ? a : b);
}
bool get hasBounds =>
minLatitude != null &&
maxLatitude != null &&
minLongitude != null &&
maxLongitude != null;
/// Angolo sud-ovest del rettangolo che contiene tutta la traccia.
LatLng? get southWest {
final south = minLatitude;
final west = minLongitude;
if (south == null || west == null) return null;
return LatLng(south, west);
}
/// Angolo nord-est del rettangolo che contiene tutta la traccia.
LatLng? get northEast {
final north = maxLatitude;
final east = maxLongitude;
if (north == null || east == null) return null;
return LatLng(north, east);
}
/// Centro geometrico del bounding box.
///
/// A differenza di [center], non dipende dalla densita dei punti. Per la mappa
/// spesso e' piu stabile per tracce con pause o punti molto concentrati.
LatLng? get boundsCenter {
final south = minLatitude;
final north = maxLatitude;
final west = minLongitude;
final east = maxLongitude;
if (south == null || north == null || west == null || east == null) {
return null;
}
return LatLng(
(south + north) / 2,
(west + east) / 2,
);
}
String get distanceLabel {
final value = distanceMeters;
if (value == null) return '- km';
return '${(value / 1000).toStringAsFixed(2)} km';
}
String get elevationGainLabel {
final value = elevationGainMeters;
if (value == null) return 'D+ -';
return 'D+ ${value.round()} m';
}
String get durationLabel {
final value = duration;
if (value == null) return '-';
final hours = value.inHours;
final minutes = value.inMinutes.remainder(60);
final seconds = value.inSeconds.remainder(60);
if (hours > 0) {
return '${hours}h ${minutes}m';
}
if (minutes > 0) {
return '${minutes}m ${seconds}s';
}
return '${seconds}s';
}
String get sportLabel {
final value = sport;
if (value == null || value.trim().isEmpty) return 'Attività';
return value;
}
}