From b4226216eb84246e2b738494a4041d40ed49920f Mon Sep 17 00:00:00 2001 From: qguillaume Date: Thu, 11 Jun 2026 19:40:30 +0200 Subject: [PATCH] feat: retrait cercle et encadre + decalage centrage de la cible pris en compte --- .gitignore | 1 + lib/features/capture/capture_screen.dart | 88 +----------------------- lib/features/crop/crop_screen.dart | 14 ++-- 3 files changed, 8 insertions(+), 95 deletions(-) diff --git a/.gitignore b/.gitignore index 6ab19e5c..2313fd48 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ .svn/ .swiftpm/ migrate_working_dir/ +.claude/ # IntelliJ related *.iml diff --git a/lib/features/capture/capture_screen.dart b/lib/features/capture/capture_screen.dart index 5b6a86cc..0a6103d3 100644 --- a/lib/features/capture/capture_screen.dart +++ b/lib/features/capture/capture_screen.dart @@ -469,30 +469,11 @@ class _CaptureScreenState extends State ), ), - // 1.bis Cercle dessiné autour de la cible circulaire détectée - if (_targetResult != null && _targetResult!.success) - Center( - child: AspectRatio( - aspectRatio: 3 / 4, - child: CustomPaint( - painter: _TargetCirclePainter( - target: _targetResult!, - color: _targetReady ? frameColor : Colors.white, - highlighted: _targetReady, - ), - ), - ), - ), - - // 2. Cadre de visée avec coins et mire centrale + // 2. Coins du cadre et mire centrale (sans le cadre rectangulaire) Center( - child: Container( + child: SizedBox( width: MediaQuery.of(context).size.width * 0.85, height: MediaQuery.of(context).size.width * 0.85, - decoration: BoxDecoration( - border: Border.all(color: frameColor, width: 2.0), - borderRadius: BorderRadius.circular(16), - ), child: Stack( children: [ _buildCameraCorner(TopLeft: true, color: frameColor), @@ -934,69 +915,4 @@ class _CaptureScreenState extends State ), ); } -} - -// ───────────────────────────────────────────────────────────────────────── -// Painter qui dessine un cercle autour de la cible circulaire détectée. -// Le centre et le rayon viennent d'OpenCV (coordonnées normalisées 0..1). -// Blanc tant que la cible n'est pas bien cadrée, couleur d'état sinon. -// ───────────────────────────────────────────────────────────────────────── -class _TargetCirclePainter extends CustomPainter { - final TargetDetectionResult target; - final Color color; - final bool highlighted; - - _TargetCirclePainter({ - required this.target, - required this.color, - required this.highlighted, - }); - - @override - void paint(Canvas canvas, Size size) { - // Centre en pixels dans la zone de dessin - final double cx = target.centerX * size.width; - final double cy = target.centerY * size.height; - // radius est normalisé par min(largeur, hauteur) côté OpenCV - final double r = target.radius * math.min(size.width, size.height); - - final Paint stroke = Paint() - ..style = PaintingStyle.stroke - ..strokeWidth = highlighted ? 3.5 : 2.0 - ..color = color; - - // Cercle principal autour de la cible - canvas.drawCircle(Offset(cx, cy), r, stroke); - - // Petite croix au centre détecté - final Paint cross = Paint() - ..strokeWidth = 2.0 - ..color = color; - const double k = 10; - canvas.drawLine(Offset(cx - k, cy), Offset(cx + k, cy), cross); - canvas.drawLine(Offset(cx, cy - k), Offset(cx, cy + k), cross); - - // Étiquette "CIBLE" quand elle est bien cadrée - if (highlighted) { - final tp = TextPainter( - text: TextSpan( - text: ' CIBLE ', - style: TextStyle( - color: Colors.black, - fontSize: 12, - fontWeight: FontWeight.bold, - backgroundColor: color, - ), - ), - textDirection: TextDirection.ltr, - )..layout(); - tp.paint(canvas, Offset(cx - tp.width / 2, (cy - r - 20).clamp(0.0, size.height))); - } - } - - @override - bool shouldRepaint(_TargetCirclePainter old) => - old.target != target || - old.color != color || - old.highlighted != highlighted; } \ No newline at end of file diff --git a/lib/features/crop/crop_screen.dart b/lib/features/crop/crop_screen.dart index 2ac05e5c..5e59ca6d 100644 --- a/lib/features/crop/crop_screen.dart +++ b/lib/features/crop/crop_screen.dart @@ -389,18 +389,14 @@ class _CropScreenState extends State { Future _onCropConfirm() async { setState(() => _isLoading = true); try { - // CORRECTIF ZOOM : On sauvegarde et réinitialise le zoom avant de calculer - // la zone de découpe pour ne pas transmettre le zoom aux écrans suivants + // La zone de découpe doit refléter le DÉPLACEMENT (pan) et la ROTATION, + // mais PAS le ZOOM. On neutralise donc temporairement _scale à 1.0 pour + // le calcul, tout en conservant _offset. La rotation est appliquée à part + // par cropToSquare(rotationDegrees: _rotation). final savedScale = _scale; - final savedOffset = _offset; _scale = 1.0; - _offset = Offset.zero; - final cropRect = _calculateCropRect(); - - // On restaure pour l'affichage (au cas où on revient en arrière) - _scale = savedScale; - _offset = savedOffset; + _scale = savedScale; // on restaure pour l'affichage (retour arrière) // AJOUT DE LA DECOUPE ET DU REDRESSEMENT GÉOMÉTRIQUE PHYSIQUE final croppedImagePath = await _cropService.cropToSquare(