import 'package:get/get.dart'; import '../models/landmark.dart'; import '../services/resection_calculator.dart'; /// ============================================================================ /// [ResectionController] - وحدة التحكم بالتقاطع البصري العكسي (GPS-Denied Fix) /// ============================================================================ /// English: /// GetX Controller managing camera-based optical resection observations, /// magnetic azimuth readings, and inverse triangulation coordinate resolution. /// /// العربية: /// متحكم GetX لإدارة عملية التقاطع البصري العكسي عبر الكاميرا والبوصلة المغناطيسية، /// واستخراج إحداثيات الموقع بدقة عند انقطاع الـ GPS أو التشويش الإلكتروني. /// ============================================================================ class ResectionController extends GetxController { // ── Observables / الحالات التفاعلية ────────────────────────────────────── final RxList observations = [].obs; final Rx resectionResult = Rx(null); final RxDouble currentHeadingDeg = 0.0.obs; final Rx selectedMapLandmark = Rx(null); /// Set Landmark picked from interactive Map / تعيين المعلم المختار مباشرة من الخريطة void setMapLandmark(double lat, double lng, {String? customName, int? elevationM}) { selectedMapLandmark.value = TacticalLandmark( id: 'picked_${DateTime.now().millisecondsSinceEpoch}', name: customName ?? 'معلم تكتيكي مرصود (${lat.toStringAsFixed(4)}, ${lng.toStringAsFixed(4)})', region: 'قاطع العمليات الميداني', type: LandmarkType.mountain, lat: lat, lng: lng, elevationM: elevationM ?? 850, description: 'تم تحديده بصرياً عبر إشارة المصلب التفاعلية على الخريطة', ); } /// Add Observation / إضافة رصد اتجاهي لمعلم جغرافي void addObservation(ResectionObservation obs) { observations.removeWhere((o) => o.landmark.id == obs.landmark.id); observations.add(obs); } /// Remove Observation / إزالة رصد معلم معين void removeObservation(String landmarkId) { observations.removeWhere((o) => o.landmark.id == landmarkId); } /// Compute Position from Observations / استخراج الإحداثيات بالتقاطع العكسي ResectionResult? computePosition() { if (observations.length < 2) return null; final res = ResectionCalculator.calculatePosition(observations); resectionResult.value = res; return res; } /// Compute Position from Single Landmark + Baseline step-off /// استخراج الموقع بالرصد على معلم واحد وخط أساس متحرك (10م، 11م، 20م، 50م) ResectionResult? computeSingleLandmarkPosition({ required TacticalLandmark landmark, required double azimuth1Deg, required double azimuth2Deg, required double baselineMeters, }) { final res = ResectionCalculator.calculateSingleLandmarkPolar( landmark: landmark, azimuth1Deg: azimuth1Deg, azimuth2Deg: azimuth2Deg, baselineMeters: baselineMeters, ); resectionResult.value = res; return res; } /// Reset all observations / تصفير وإعادة ضبط الرصد void reset() { observations.clear(); resectionResult.value = null; } }