diff --git a/lib/features/map/map_screen.dart b/lib/features/map/map_screen.dart index b143127..dd7916b 100644 --- a/lib/features/map/map_screen.dart +++ b/lib/features/map/map_screen.dart @@ -33,8 +33,6 @@ class _MapScreenState extends ConsumerState { bool _showHardBraking = true; bool _showCornering = true; - // These are intentionally derived from the already-persisted telemetry. - // They do not alter the frozen telemetry acquisition/fusion pipeline. static const double _hardAccelThresholdG = 0.35; static const double _hardBrakingThresholdG = -0.35; static const Duration _eventMergeWindow = Duration(milliseconds: 1500); @@ -133,8 +131,6 @@ class _MapScreenState extends ConsumerState { return markers; } - // Build map events directly from persisted longitudinal G when RideEvents are - // absent/incomplete. Existing RideEvents remain untouched and are still shown. List _buildTelemetryEventMarkers(List samples) { final gps = samples.where((s) => s.latitude != null && s.longitude != null && @@ -248,32 +244,97 @@ class _MapScreenState extends ConsumerState { ); List _buildPolylines() { - if (_routePoints.isEmpty || !_showRoute) return []; - if (!_showSpeedHeatmap) { - return [AppPolyline(id: 'history_route', points: _routePoints, color: const Color(0xFF00E5FF), width: 4.5)]; - } + if (_routePoints.isEmpty) return []; + final polylines = []; - final validSamples = _telemetrySamples.where((t) => t.latitude != null && t.longitude != null).toList(); - if (validSamples.isEmpty) return []; - final step = (validSamples.length / 1500).ceil().clamp(1, 10); - List currentSegment = []; - Color currentColor = _getSpeedColor(validSamples.first.speed ?? 0.0); - for (int i = 0; i < validSamples.length; i += step) { - final s = validSamples[i]; - final pt = AppLatLng(s.latitude!, s.longitude!); - final segColor = _getSpeedColor(s.speed ?? 0.0); - if (segColor != currentColor && currentSegment.isNotEmpty) { - currentSegment.add(pt); - polylines.add(AppPolyline(id: 'speed_seg_${polylines.length}', points: List.from(currentSegment), color: currentColor, width: 5.0)); - currentSegment = [pt]; - currentColor = segColor; - } else { - currentSegment.add(pt); + if (_showRoute) { + polylines.add(AppPolyline( + id: 'history_route', + points: _routePoints, + color: const Color(0xFF00E5FF), + width: 4.5, + )); + } + + final validSamples = _telemetrySamples + .where((t) => t.latitude != null && t.longitude != null) + .toList(); + if (validSamples.isEmpty) return polylines; + + if (_showSpeedHeatmap) { + final step = (validSamples.length / 1500).ceil().clamp(1, 10); + List currentSegment = []; + Color currentColor = _getSpeedColor(validSamples.first.speed ?? 0.0); + for (int i = 0; i < validSamples.length; i += step) { + final s = validSamples[i]; + final pt = AppLatLng(s.latitude!, s.longitude!); + final segColor = _getSpeedColor(s.speed ?? 0.0); + if (segColor != currentColor && currentSegment.isNotEmpty) { + currentSegment.add(pt); + polylines.add(AppPolyline(id: 'speed_seg_${polylines.length}', points: List.from(currentSegment), color: currentColor, width: 5.0)); + currentSegment = [pt]; + currentColor = segColor; + } else { + currentSegment.add(pt); + } + } + if (currentSegment.length > 1) { + polylines.add(AppPolyline(id: 'speed_seg_${polylines.length}', points: currentSegment, color: currentColor, width: 5.0)); } } - if (currentSegment.length > 1) { - polylines.add(AppPolyline(id: 'speed_seg_${polylines.length}', points: currentSegment, color: currentColor, width: 5.0)); + + if (_showHardAccel) { + polylines.addAll(_buildLongitudinalEventPolylines( + validSamples, + predicate: (g) => g >= _hardAccelThresholdG, + idPrefix: 'accel_layer', + color: const Color(0xFF76FF03), + )); } + if (_showHardBraking) { + polylines.addAll(_buildLongitudinalEventPolylines( + validSamples, + predicate: (g) => g <= _hardBrakingThresholdG, + idPrefix: 'braking_layer', + color: const Color(0xFFFF5252), + )); + } + + return polylines; + } + + List _buildLongitudinalEventPolylines( + List samples, { + required bool Function(double g) predicate, + required String idPrefix, + required Color color, + }) { + final polylines = []; + List segment = []; + var segmentIndex = 0; + + void flush() { + if (segment.length >= 2) { + polylines.add(AppPolyline( + id: '${idPrefix}_$segmentIndex', + points: List.from(segment), + color: color, + width: 7.0, + )); + segmentIndex++; + } + segment = []; + } + + for (final sample in samples) { + final g = sample.longitudinalG ?? sample.accelX; + if (g != null && g.isFinite && predicate(g)) { + segment.add(AppLatLng(sample.latitude!, sample.longitude!)); + } else { + flush(); + } + } + flush(); return polylines; }