feat: retrait cercle et encadre + decalage centrage de la cible pris en compte
This commit is contained in:
@@ -469,30 +469,11 @@ class _CaptureScreenState extends State<CaptureScreen>
|
||||
),
|
||||
),
|
||||
|
||||
// 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<CaptureScreen>
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────
|
||||
// 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;
|
||||
}
|
||||
@@ -389,18 +389,14 @@ class _CropScreenState extends State<CropScreen> {
|
||||
Future<void> _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(
|
||||
|
||||
Reference in New Issue
Block a user