91 lines
3.0 KiB
Dart
91 lines
3.0 KiB
Dart
/// أنواع المقاطع المكتشفة تلقائياً
|
|
enum SegmentType {
|
|
warmup, // إحماء - أول 5-10% من المسافة بسرعة منخفضة
|
|
main, // المرحلة الرئيسية
|
|
cooldown, // تبريد - آخر 5-10% بسرعة متناقصة
|
|
stop, // نقطة توقف - سرعة < 0.3 m/s لأكثر من 10 ثوان
|
|
sprint, // تسارع - سرعة > 120% من المتوسط
|
|
uphill, // صعود - ارتفاع > 3% grade
|
|
downhill, // نزول - انخفاض > 3% grade
|
|
}
|
|
|
|
/// نموذج مقطع من المسار
|
|
/// يمثل جزء من التمرين تم تقسيمه بناءً على تغيرات السرعة أو الارتفاع
|
|
class WorkoutSegment {
|
|
final int segmentIndex;
|
|
final SegmentType type;
|
|
final double distanceMeters;
|
|
final int durationSeconds;
|
|
final double avgSpeedMps;
|
|
final double maxSpeedMps;
|
|
final double elevationChange; // positive = uphill, negative = downhill
|
|
final int startCoordIndex; // index in coordinates list
|
|
final int endCoordIndex;
|
|
|
|
WorkoutSegment({
|
|
required this.segmentIndex,
|
|
required this.type,
|
|
required this.distanceMeters,
|
|
required this.durationSeconds,
|
|
required this.avgSpeedMps,
|
|
this.maxSpeedMps = 0,
|
|
this.elevationChange = 0,
|
|
required this.startCoordIndex,
|
|
required this.endCoordIndex,
|
|
});
|
|
|
|
/// Pace in min/km
|
|
double get paceMinKm {
|
|
if (avgSpeedMps <= 0) return 0;
|
|
double kmh = avgSpeedMps * 3.6;
|
|
return kmh > 0 ? 60.0 / kmh : 0;
|
|
}
|
|
|
|
/// Gradient percentage (for elevation segments)
|
|
double get gradientPercent {
|
|
if (distanceMeters <= 0) return 0;
|
|
return (elevationChange / distanceMeters) * 100;
|
|
}
|
|
|
|
Map<String, dynamic> toMap() {
|
|
return {
|
|
'segment_index': segmentIndex,
|
|
'segment_type': type.name,
|
|
'distance_meters': distanceMeters,
|
|
'duration_seconds': durationSeconds,
|
|
'avg_speed_mps': avgSpeedMps,
|
|
'max_speed_mps': maxSpeedMps,
|
|
'elevation_change': elevationChange,
|
|
'start_coord_index': startCoordIndex,
|
|
'end_coord_index': endCoordIndex,
|
|
};
|
|
}
|
|
|
|
factory WorkoutSegment.fromMap(Map<String, dynamic> map) {
|
|
return WorkoutSegment(
|
|
segmentIndex: map['segment_index'] as int,
|
|
type: SegmentType.values.firstWhere(
|
|
(e) => e.name == map['segment_type'],
|
|
orElse: () => SegmentType.main,
|
|
),
|
|
distanceMeters: (map['distance_meters'] as num).toDouble(),
|
|
durationSeconds: map['duration_seconds'] as int,
|
|
avgSpeedMps: (map['avg_speed_mps'] as num).toDouble(),
|
|
maxSpeedMps: (map['max_speed_mps'] as num?)?.toDouble() ?? 0,
|
|
elevationChange: (map['elevation_change'] as num?)?.toDouble() ?? 0,
|
|
startCoordIndex: map['start_coord_index'] as int,
|
|
endCoordIndex: map['end_coord_index'] as int,
|
|
);
|
|
}
|
|
|
|
/// Convert to API-compatible map
|
|
Map<String, dynamic> toApiMap() {
|
|
return {
|
|
'segment_order': segmentIndex,
|
|
'duration_seconds': durationSeconds,
|
|
'distance_meters': distanceMeters.toInt(),
|
|
'index_in_polyline': startCoordIndex,
|
|
};
|
|
}
|
|
}
|