- RouteGeometry (lib/domain/mission/route_geometry.dart): physically grounded flight path - straight segments + tangential arcs at each course change, sized from the drone's minimum turn radius (doc 3.7/4.6), replacing a naive spline that would suggest unrealistic turn radii. Marks a vertex "bad" (turn angle >= 160°, tangent length exceeding 90% of either adjacent leg, or exceeding the waypoint's catch radius) and a leg "bad" when the required climb/descent rate exceeds the drone's max climb/descent rate. Pure Dart, no Flutter dependency, so it stays usable if the mission domain is ever split into its own package (4.22). Wind-based turn-radius correction from the prototype isn't ported yet - the wind system (doc 3.8) doesn't exist in the Flutter app. - MissionMap now draws each RouteSegment as its own Polyline, colored red when bad instead of a single plain white line; waypoint markers turn red too when their vertex is bad. - ValueWheel: vertical drag-to-adjust tape control (HTML prototype's #altWheel/#spdWheel), custom-painted tick marks, blue center indicator, gradient fade at top/bottom. Wired into PlanScreen on both screen edges with Alt/Speed readouts. - curAlt/curSpeed now live in PlanScreen state instead of fixed constants: dropping a new waypoint uses whatever the wheels are currently set to; entering editing mode on an existing waypoint loads its values into the wheels; adjusting a wheel while editing writes live into that waypoint (provider gained setAltitude/setSpeed to match the existing moveWaypoint/toggleAction pattern). Added dedicated unit tests for the geometry (empty list, straight line, feasible 90° turn producing a line-arc-line segment sequence, an infeasible near-180° turn, and an infeasible descent rate) rather than relying on eyeballing it on the emulator - this is exactly the kind of ported-math correctness that's hard to verify visually but easy to get subtly wrong. All 11 tests (previous 6 + these 5) and flutter analyze pass. Also manually verified the wheels on the Pixel_10a emulator: drag changes the value and the on-screen readout in real time. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
71 lines
2.2 KiB
Dart
71 lines
2.2 KiB
Dart
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../domain/waypoint/flat_waypoint_list.dart';
|
|
|
|
/// Haelt die Wegpunktliste der aktuell in Bearbeitung befindlichen Mission
|
|
/// (Architektur-Doku 3.2/3.6). Reaktiver Einzelwert im Sinne von 4.16 -
|
|
/// daher Riverpod statt Bloc; die App-Mode State Machine bleibt in
|
|
/// AppModeCubit.
|
|
class CurrentMissionNotifier extends Notifier<List<Waypoint>> {
|
|
@override
|
|
List<Waypoint> build() => [];
|
|
|
|
void addWaypoint(Waypoint waypoint) {
|
|
state = [...state, waypoint];
|
|
}
|
|
|
|
/// Aktualisiert die Position eines Wegpunkts (Drag-to-Reposition im
|
|
/// Editier-Modus: Kartenverschieben bewegt den Zielpunkt live mit).
|
|
void moveWaypoint(int index, double lat, double lon) {
|
|
state = [
|
|
for (var i = 0; i < state.length; i++)
|
|
if (i == index) state[i].copyWith(lat: lat, lon: lon) else state[i],
|
|
];
|
|
}
|
|
|
|
/// Aktualisiert die Zielhoehe eines Wegpunkts (Alt-Drehrad im
|
|
/// Editier-Modus schreibt live in den Zielpunkt).
|
|
void setAltitude(int index, double altitudeM) {
|
|
state = [
|
|
for (var i = 0; i < state.length; i++)
|
|
if (i == index) state[i].copyWith(altitudeM: altitudeM) else state[i],
|
|
];
|
|
}
|
|
|
|
/// Aktualisiert die Zielgeschwindigkeit eines Wegpunkts (Speed-Drehrad im
|
|
/// Editier-Modus schreibt live in den Zielpunkt).
|
|
void setSpeed(int index, double speedMs) {
|
|
state = [
|
|
for (var i = 0; i < state.length; i++)
|
|
if (i == index) state[i].copyWith(speedMs: speedMs) else state[i],
|
|
];
|
|
}
|
|
|
|
/// Schaltet die Execute-Aktion eines Wegpunkts um (Halo-Radialmenue:
|
|
/// erneutes Antippen derselben Aktion setzt sie zurueck auf "none").
|
|
void toggleAction(int index, WaypointAction action) {
|
|
state = [
|
|
for (var i = 0; i < state.length; i++)
|
|
if (i == index)
|
|
state[i].copyWith(
|
|
action:
|
|
state[i].action == action ? WaypointAction.none : action,
|
|
)
|
|
else
|
|
state[i],
|
|
];
|
|
}
|
|
|
|
void removeAt(int index) {
|
|
state = [
|
|
for (var i = 0; i < state.length; i++)
|
|
if (i != index) state[i],
|
|
];
|
|
}
|
|
}
|
|
|
|
final currentMissionProvider =
|
|
NotifierProvider<CurrentMissionNotifier, List<Waypoint>>(
|
|
CurrentMissionNotifier.new,
|
|
);
|