feat: object detection service

This commit is contained in:
qguillaume
2026-06-05 21:18:48 +02:00
parent d487c98e3d
commit f65c5e6a3f
4 changed files with 196 additions and 22 deletions

View File

@@ -60,18 +60,18 @@ class ParallelismService {
StreamSubscription<AccelerometerEvent>? _subscription;
final StreamController<ParallelismData> _controller =
StreamController<ParallelismData>.broadcast();
StreamController<ParallelismData>.broadcast();
/// État interne mémorisé entre deux frames (cœur de l'hystérésis).
ParallelismStatus _currentStatus = ParallelismStatus.unknown;
ParallelismService({
this.alignThreshold = 15.0,
this.misalignThreshold = 22.0,
this.alignThreshold = 25.0,
this.misalignThreshold = 32.0,
}) : assert(
misalignThreshold > alignThreshold,
'misalignThreshold doit être supérieur à alignThreshold',
);
misalignThreshold > alignThreshold,
'misalignThreshold doit être supérieur à alignThreshold',
);
Stream<ParallelismData> get stream => _controller.stream;
@@ -122,14 +122,24 @@ class ParallelismService {
final double ny = gy / magnitude;
final double nz = gz / magnitude;
// Pitch : inclinaison avant/arrière (téléphone qui pointe vers le haut/bas)
// ── Mesure de l'écart par rapport à la VERTICALE (cible sur un mur) ──
// Quand le téléphone est vertical face au mur, la gravité est portée par
// l'axe -Y (ny ≈ -1) et l'axe Z est proche de 0 (nz ≈ 0).
//
// Pitch = bascule avant/arrière (le téléphone "se couche") → vient de nz.
// Roll = penché à gauche/droite → vient de nx.
final double pitchDeg = math.asin(nz.clamp(-1.0, 1.0)) * (180.0 / math.pi);
final double rollDeg = math.asin(nx.clamp(-1.0, 1.0)) * (180.0 / math.pi);
// Roll : inclinaison latérale (téléphone penché à gauche/droite)
final double rollDeg = math.atan2(nx, -ny) * (180.0 / math.pi);
// Écart angulaire TOTAL par rapport à la verticale parfaite, calculé en 3D.
// C'est l'angle entre l'axe -Y du téléphone et le vecteur gravité réel.
// -> Vaut 0° quand l'écran est parfaitement parallèle au mur,
// indépendamment d'une rotation autour de l'axe de visée.
final double tiltAngle =
math.acos((-ny).clamp(-1.0, 1.0)) * (180.0 / math.pi);
// Angle combiné = le pire des deux axes
final double worstAngle = math.max(pitchDeg.abs(), rollDeg.abs());
// On utilise l'écart 3D comme critère principal (plus permissif et stable).
final double worstAngle = tiltAngle;
// ── Hystérésis ──────────────────────────────────────────────────────────
// Premier appel : on décide selon alignThreshold uniquement
@@ -159,4 +169,4 @@ class ParallelismService {
rollDegrees: rollDeg,
));
}
}
}