fix(analysis): appliquer la rotation du crop sur l'image en modes calibration et plotting

This commit is contained in:
qguillaume
2026-05-27 12:11:00 +02:00
parent 04c1204116
commit 95e62abe47
2 changed files with 47 additions and 26 deletions

View File

@@ -50,6 +50,9 @@ class AnalysisProvider extends ChangeNotifier {
String? _imagePath;
TargetType? _targetType;
// AJOUT PROTECTION DU PLOTTING : Stockage permanent de la rotation du Crop
double _cropRotation = 0.0;
// Target detection results
double _targetCenterX = 0.5;
double _targetCenterY = 0.5;
@@ -82,6 +85,7 @@ class AnalysisProvider extends ChangeNotifier {
String? get errorMessage => _errorMessage;
String? get imagePath => _imagePath;
TargetType? get targetType => _targetType;
double get cropRotation => _cropRotation; // Getter pour le Plotting
double get targetCenterX => _targetCenterX;
double get targetCenterY => _targetCenterY;
double get targetRadius => _targetRadius;
@@ -112,6 +116,12 @@ class AnalysisProvider extends ChangeNotifier {
? _correctedImagePath
: _imagePath;
/// Modifie et mémorise la rotation de l'image pour le Plotting
void setCropRotation(double rotation) {
_cropRotation = rotation;
notifyListeners();
}
/// Analyze an image
///
/// [autoAnalyze] determines if we should run automatic detection immediately.
@@ -778,6 +788,7 @@ class AnalysisProvider extends ChangeNotifier {
_errorMessage = null;
_imagePath = null;
_targetType = null;
_cropRotation = 0.0; // Reset de la rotation
_targetCenterX = 0.5;
_targetCenterY = 0.5;
_targetRadius = 0.4;

View File

@@ -23,11 +23,8 @@ import '../crop/crop_screen.dart';
import '../capture/capture_screen.dart';
import 'widgets/target_overlay.dart';
import 'widgets/target_calibration.dart';
import 'widgets/target_overlay.dart';
import 'widgets/score_card.dart';
import 'widgets/grouping_stats.dart';
import '../capture/capture_screen.dart'; // Si ton écran principal s'appelle comme ça
import '../crop/crop_screen.dart';
class AnalysisScreen extends StatelessWidget {
final String imagePath;
@@ -57,12 +54,20 @@ class AnalysisScreen extends StatelessWidget {
: null;
return ChangeNotifierProvider(
create: (context) => AnalysisProvider(
create: (context) {
final p = AnalysisProvider(
detectionService: context.read<TargetDetectionService>(),
scoreCalculatorService: context.read<ScoreCalculatorService>(),
groupingAnalyzerService: context.read<GroupingAnalyzerService>(),
sessionRepository: context.read<SessionRepository>(),
)..analyzeImage(imagePath, targetType, autoAnalyze: false, manualCenter: manualCenterOffset),
);
// Sauvegarde de l'angle de rotation d'origine directement dans l'état global
if (cropRotation != null) {
p.setCropRotation(cropRotation!);
}
p.analyzeImage(imagePath, targetType, autoAnalyze: false, manualCenter: manualCenterOffset);
return p;
},
child: _AnalysisScreenContent(
cropScale: cropScale,
cropOffset: cropOffset,
@@ -207,7 +212,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
),
),
// SECTION CORRIGÉE : Utilise maintenant widget.cropRotation sans aucune erreur !
// SECTION CORRIGÉE : Utilise maintenant la réactivité du provider globale
AspectRatio(
aspectRatio: provider.imageAspectRatio,
child: _isCalibrating
@@ -217,20 +222,16 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
ClipRect(
child: Builder(
builder: (context) {
final double rotationAngle = widget.cropRotation ?? 0.0;
return Transform(
transform: Matrix4.identity()
..translate(widget.cropOffset?.dx ?? 0.0, widget.cropOffset?.dy ?? 0.0)
..scale(1.0, 1.0), // Zoom ignoré au plotting pour rester en vue globale
..setTranslationRaw(widget.cropOffset?.dx ?? 0.0, widget.cropOffset?.dy ?? 0.0, 0.0)
..scale(1.0, 1.0) // Zoom ignoré au plotting pour rester en vue globale
..rotateZ((provider.cropRotation) * (math.pi / 180)), // FIX : Utilisation du provider dynamique
alignment: Alignment.center,
child: Transform.rotate(
angle: rotationAngle * (math.pi / 180),
child: Image.file(
File(provider.imagePath!),
fit: BoxFit.contain,
),
),
);
}
),
@@ -486,10 +487,18 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
},
child: Stack(
children: [
Image.file(
// FIX CRITIQUE PLOTTING : L'image de fond doit appliquer exactement le même angle de rotation qu'en calibration !
Transform(
transform: Matrix4.identity()
..setTranslationRaw(widget.cropOffset?.dx ?? 0.0, widget.cropOffset?.dy ?? 0.0, 0.0)
..scale(1.0, 1.0)
..rotateZ((provider.cropRotation) * (math.pi / 180)),
alignment: Alignment.center,
child: Image.file(
File(provider.imagePath!),
key: _imageKey,
fit: BoxFit.fill,
fit: BoxFit.contain, // Remplace BoxFit.fill pour s'aligner sur la Calibration
),
),
TargetOverlay(
targetCenterX: provider.targetCenterX,
@@ -568,6 +577,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
),
);
}
void _showSaveSessionDialog(BuildContext context, AnalysisProvider provider) {
showDialog(
context: context,
@@ -645,7 +655,7 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
weaponName: sessionProvider.currentWeapon,
weaponId: sessionProvider.currentWeaponId,
distance: sessionProvider.distance,
date: sessionProvider.sessionDate, // <-- CORRECTION : Prise en compte de la date ici aussi !
date: sessionProvider.sessionDate,
);
if (context.mounted) {
@@ -667,4 +677,4 @@ class _AnalysisScreenContentState extends State<_AnalysisScreenContent> {
),
);
}
}
}