import 'dart:math' as math; import 'package:intaleq_maps/intaleq_maps.dart'; import '../models/military_operations_models.dart'; import 'military_grid_utils.dart'; /// Sovereign On-Device Minefield Threat & Breaching Corridor Engine class MinefieldEngine { MinefieldEngine._(); static const double earthRadiusM = 6371000.0; /// Build Minefield Boundary Box, Density Calculation, and Safe Breaching Corridor static MinefieldZoneResult calculateMinefieldZone({ required LatLng startPoint, required LatLng endPoint, required MinefieldType type, double widthMeters = 200.0, }) { // 1. Calculate Length & Azimuth final lengthMeters = MilitaryGridUtils.haversineDistance( startPoint.latitude, startPoint.longitude, endPoint.latitude, endPoint.longitude, ); final azimuthDeg = MilitaryGridUtils.calculateBearing( startPoint.latitude, startPoint.longitude, endPoint.latitude, endPoint.longitude, ); final azRad = (azimuthDeg * math.pi) / 180.0; final perpRad = azRad + (math.pi / 2.0); final halfWidth = widthMeters / 2.0; // Helper: offset lat/lng by distance and bearing LatLng offsetCoord(LatLng origin, double distM, double bearingRad) { final dLat = (distM / earthRadiusM) * (180.0 / math.pi) * math.cos(bearingRad); final dLng = (distM / (earthRadiusM * math.cos(origin.latitude * math.pi / 180.0))) * (180.0 / math.pi) * math.sin(bearingRad); return LatLng(origin.latitude + dLat, origin.longitude + dLng); } // 2. Build 4 Corners of Minefield Polygon final p1 = offsetCoord(startPoint, halfWidth, perpRad); final p2 = offsetCoord(endPoint, halfWidth, perpRad); final p3 = offsetCoord(endPoint, halfWidth, perpRad + math.pi); final p4 = offsetCoord(startPoint, halfWidth, perpRad + math.pi); final boundary = [p1, p2, p3, p4, p1]; // 3. Generate Safe Breaching Lane (الممر الآمن عبر الثغرة) // 16-meter wide swept corridor right through the middle const double breachWidthM = 16.0; final halfBreach = breachWidthM / 2.0; final midStart = LatLng( (p1.latitude + p4.latitude) / 2.0, (p1.longitude + p4.longitude) / 2.0, ); final midEnd = LatLng( (p2.latitude + p3.latitude) / 2.0, (p2.longitude + p3.longitude) / 2.0, ); final b1 = offsetCoord(midStart, halfBreach, perpRad); final b2 = offsetCoord(midEnd, halfBreach, perpRad); final b3 = offsetCoord(midEnd, halfBreach, perpRad + math.pi); final b4 = offsetCoord(midStart, halfBreach, perpRad + math.pi); final breachPolygon = [b1, b2, b3, b4, b1]; final breachCenterline = [midStart, midEnd]; // 4. Estimate Mines Count based on standard doctrine density double densityPerM2; switch (type) { case MinefieldType.antiTank: densityPerM2 = 0.005; // ~1 per 200 m2 break; case MinefieldType.antiPersonnel: densityPerM2 = 0.025; // ~1 per 40 m2 break; case MinefieldType.mixedBarrier: densityPerM2 = 0.035; break; } final areaM2 = lengthMeters * widthMeters; final estimatedMines = (areaM2 * densityPerM2).roundToDouble(); return MinefieldZoneResult( startPoint: startPoint, endPoint: endPoint, type: type, widthMeters: widthMeters, lengthMeters: (lengthMeters * 10).round() / 10.0, estimatedMinesCount: estimatedMines, boundaryPolygon: boundary, breachLaneCenterline: breachCenterline, breachLanePolygon: breachPolygon, ); } }