import 'dart:math' as math; import 'package:intaleq_maps/intaleq_maps.dart'; /// Military Coordinates Utility (WGS84 <-> UTM Zone 36N & MGRS Grid) /// Specifically optimized for Jordan & Levantine military operations (Zone 36N / 37N) class MilitaryGridUtils { MilitaryGridUtils._(); static const double _a = 6378137.0; // WGS84 semi-major axis static const double _f = 1 / 298.257223563; // WGS84 flattening static const double _b = _a * (1.0 - _f); static const double _eSq = (_a * _a - _b * _b) / (_a * _a); static const double _ePrimeSq = (_a * _a - _b * _b) / (_b * _b); static const double _k0 = 0.9996; // UTM scale factor /// Convert WGS84 Lat/Lng to UTM Zone 36N Easting (شرقيات) and Northing (شماليات) static MilitaryCoordinates fromLatLng(LatLng latLng, {int zone = 36}) { final lat = latLng.latitude; final lng = latLng.longitude; final latRad = lat * (math.pi / 180.0); final lngRad = lng * (math.pi / 180.0); final centralMeridianDeg = (zone - 1) * 6 - 180 + 3; final centralMeridianRad = centralMeridianDeg * (math.pi / 180.0); final n = _a / math.sqrt(1.0 - _eSq * math.sin(latRad) * math.sin(latRad)); final t = math.tan(latRad) * math.tan(latRad); final c = _ePrimeSq * math.cos(latRad) * math.cos(latRad); final aCoeff = math.cos(latRad) * (lngRad - centralMeridianRad); final m = _a * ((1.0 - _eSq / 4.0 - 3.0 * _eSq * _eSq / 64.0 - 5.0 * _eSq * _eSq * _eSq / 256.0) * latRad - (3.0 * _eSq / 8.0 + 3.0 * _eSq * _eSq / 32.0 + 45.0 * _eSq * _eSq * _eSq / 1024.0) * math.sin(2.0 * latRad) + (15.0 * _eSq * _eSq / 256.0 + 45.0 * _eSq * _eSq * _eSq / 1024.0) * math.sin(4.0 * latRad) - (35.0 * _eSq * _eSq * _eSq / 3072.0) * math.sin(6.0 * latRad)); final easting = 500000.0 + _k0 * n * (aCoeff + (1.0 - t + c) * math.pow(aCoeff, 3) / 6.0 + (5.0 - 18.0 * t + t * t + 72.0 * c - 58.0 * _ePrimeSq) * math.pow(aCoeff, 5) / 120.0); final northing = _k0 * (m + n * math.tan(latRad) * (aCoeff * aCoeff / 2.0 + (5.0 - t + 9.0 * c + 4.0 * c * c) * math.pow(aCoeff, 4) / 24.0 + (61.0 - 58.0 * t + t * t + 600.0 * c - 330.0 * _ePrimeSq) * math.pow(aCoeff, 6) / 720.0)); return MilitaryCoordinates( lat: lat, lng: lng, easting: easting, northing: northing, zone: zone, ); } /// Convert UTM Zone 36N Easting (شرقيات) and Northing (شماليات) to WGS84 Lat/Lng static LatLng toLatLng({ required double easting, required double northing, int zone = 36, }) { final e1 = (1.0 - math.sqrt(1.0 - _eSq)) / (1.0 + math.sqrt(1.0 - _eSq)); final x = easting - 500000.0; final y = northing; final m = y / _k0; final mu = m / (_a * (1.0 - _eSq / 4.0 - 3.0 * _eSq * _eSq / 64.0 - 5.0 * _eSq * _eSq * _eSq / 256.0)); final phi1Rad = mu + (3.0 * e1 / 2.0 - 27.0 * math.pow(e1, 3) / 32.0) * math.sin(2.0 * mu) + (21.0 * e1 * e1 / 16.0 - 55.0 * math.pow(e1, 4) / 32.0) * math.sin(4.0 * mu) + (151.0 * math.pow(e1, 3) / 96.0) * math.sin(6.0 * mu) + (1097.0 * math.pow(e1, 4) / 512.0) * math.sin(8.0 * mu); final n1 = _a / math.sqrt(1.0 - _eSq * math.sin(phi1Rad) * math.sin(phi1Rad)); final t1 = math.tan(phi1Rad) * math.tan(phi1Rad); final c1 = _ePrimeSq * math.cos(phi1Rad) * math.cos(phi1Rad); final r1 = _a * (1.0 - _eSq) / math.pow(1.0 - _eSq * math.sin(phi1Rad) * math.sin(phi1Rad), 1.5); final d = x / (n1 * _k0); final latRad = phi1Rad - (n1 * math.tan(phi1Rad) / r1) * (d * d / 2.0 - (5.0 + 3.0 * t1 + 10.0 * c1 - 4.0 * c1 * c1 - 9.0 * _ePrimeSq) * math.pow(d, 4) / 24.0 + (61.0 + 90.0 * t1 + 298.0 * c1 + 45.0 * t1 * t1 - 252.0 * _ePrimeSq - 3.0 * c1 * c1) * math.pow(d, 6) / 720.0); final centralMeridianDeg = (zone - 1) * 6 - 180 + 3; final centralMeridianRad = centralMeridianDeg * (math.pi / 180.0); final lngRad = centralMeridianRad + (d - (1.0 + 2.0 * t1 + c1) * math.pow(d, 3) / 6.0 + (5.0 - 2.0 * c1 + 28.0 * t1 - 3.0 * c1 * c1 + 8.0 * _ePrimeSq + 24.0 * t1 * t1) * math.pow(d, 5) / 120.0) / math.cos(phi1Rad); return LatLng( latRad * (180.0 / math.pi), lngRad * (180.0 / math.pi), ); } } class MilitaryCoordinates { final double lat; final double lng; final double easting; final double northing; final int zone; MilitaryCoordinates({ required this.lat, required this.lng, required this.easting, required this.northing, this.zone = 36, }); /// Short 6-digit Easting / Northing string for tactical voice transmission (e.g. 845 412) String get shortGrid => '${(easting.round() % 100000 ~/ 100).toString().padLeft(3, '0')} ${(northing.round() % 100000 ~/ 100).toString().padLeft(3, '0')}'; /// Standard Arabic military format (شرقيات: 784520 م • شماليات: 3541280 م) String get arabicFullFormat => 'شرقيات: ${easting.round()} م • شماليات: ${northing.round()} م (${zone}N)'; String get eastingStr => '${easting.round()}'; String get northingStr => '${northing.round()}'; }