feat: Add Intaleq Native Android Kotlin & iOS Swift SDKs, Incline slope routing, Topographic contours and modular tactical app
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
enum AngleUnit {
|
||||
degrees, // 0° - 360°
|
||||
mils, // 0 - 6400 NATO Mils (₥)
|
||||
dual, // Both: 045° (0800 ₥)
|
||||
}
|
||||
|
||||
class AngleFormatter {
|
||||
static const double degToMilsNato = 17.7777777778; // 6400 mils / 360 deg
|
||||
|
||||
static double toMils(double deg) {
|
||||
return (deg * degToMilsNato) % 6400;
|
||||
}
|
||||
|
||||
static double fromMils(double mils) {
|
||||
return (mils / degToMilsNato) % 360;
|
||||
}
|
||||
|
||||
static String format(double deg, AngleUnit unit, {bool includeLabel = true}) {
|
||||
final cleanDeg = (deg % 360 + 360) % 360;
|
||||
final milsVal = (cleanDeg * degToMilsNato).round() % 6400;
|
||||
final degStr = '${cleanDeg.toStringAsFixed(1)}°';
|
||||
final milsStr = '${milsVal.toString().padLeft(4, '0')} ₥';
|
||||
|
||||
switch (unit) {
|
||||
case AngleUnit.degrees:
|
||||
return includeLabel ? 'السمت: $degStr' : degStr;
|
||||
case AngleUnit.mils:
|
||||
return includeLabel ? 'السمت: $milsStr' : milsStr;
|
||||
case AngleUnit.dual:
|
||||
return includeLabel ? '$degStr ($milsStr)' : '$degStr ($milsStr)';
|
||||
}
|
||||
}
|
||||
|
||||
static String unitLabel(AngleUnit unit) {
|
||||
switch (unit) {
|
||||
case AngleUnit.degrees:
|
||||
return 'الدرجات (Degrees °)';
|
||||
case AngleUnit.mils:
|
||||
return 'الميل العسكري (NATO Mils ₥)';
|
||||
case AngleUnit.dual:
|
||||
return 'عرض مزدوج (درجات + ميل)';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum LandmarkType {
|
||||
minaret,
|
||||
tower,
|
||||
waterTank,
|
||||
fort,
|
||||
mountain,
|
||||
militaryBase,
|
||||
grainSilo,
|
||||
}
|
||||
|
||||
class TacticalLandmark {
|
||||
final String id;
|
||||
final String name;
|
||||
final String region;
|
||||
final LandmarkType type;
|
||||
final double lat;
|
||||
final double lng;
|
||||
final int elevationM;
|
||||
final String description;
|
||||
|
||||
const TacticalLandmark({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.region,
|
||||
required this.type,
|
||||
required this.lat,
|
||||
required this.lng,
|
||||
required this.elevationM,
|
||||
required this.description,
|
||||
});
|
||||
|
||||
IconData get typeIcon {
|
||||
switch (type) {
|
||||
case LandmarkType.minaret:
|
||||
return Icons.mosque;
|
||||
case LandmarkType.tower:
|
||||
return Icons.cell_tower;
|
||||
case LandmarkType.waterTank:
|
||||
return Icons.water_drop;
|
||||
case LandmarkType.fort:
|
||||
return Icons.castle;
|
||||
case LandmarkType.mountain:
|
||||
return Icons.terrain;
|
||||
case LandmarkType.militaryBase:
|
||||
return Icons.shield;
|
||||
case LandmarkType.grainSilo:
|
||||
return Icons.inventory_2;
|
||||
}
|
||||
}
|
||||
|
||||
String get typeLabelArabic {
|
||||
switch (type) {
|
||||
case LandmarkType.minaret:
|
||||
return 'مئذنة / مسجد';
|
||||
case LandmarkType.tower:
|
||||
return 'برج اتصالات / إرسال';
|
||||
case LandmarkType.waterTank:
|
||||
return 'خزان مياه عالي';
|
||||
case LandmarkType.fort:
|
||||
return 'قلعة / موقع أثري';
|
||||
case LandmarkType.mountain:
|
||||
return 'قمة جبل / نقطة مثلثة';
|
||||
case LandmarkType.militaryBase:
|
||||
return 'قاعدة / مطار عسكري';
|
||||
case LandmarkType.grainSilo:
|
||||
return 'صوامع حبوب / منشأة عالية';
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'id': id,
|
||||
'name': name,
|
||||
'region': region,
|
||||
'type': type.name,
|
||||
'lat': lat,
|
||||
'lng': lng,
|
||||
'elevationM': elevationM,
|
||||
'description': description,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class ResectionObservation {
|
||||
final TacticalLandmark landmark;
|
||||
final double observedAzimuthDeg;
|
||||
final double trueAzimuthDeg;
|
||||
final DateTime timestamp;
|
||||
|
||||
ResectionObservation({
|
||||
required this.landmark,
|
||||
required this.observedAzimuthDeg,
|
||||
required this.trueAzimuthDeg,
|
||||
DateTime? timestamp,
|
||||
}) : timestamp = timestamp ?? DateTime.now();
|
||||
}
|
||||
|
||||
class ResectionResult {
|
||||
final double lat;
|
||||
final double lng;
|
||||
final double estimatedAccuracyMeters;
|
||||
final List<ResectionObservation> observations;
|
||||
final Map<String, double> distanceToLandmarksKm;
|
||||
|
||||
const ResectionResult({
|
||||
required this.lat,
|
||||
required this.lng,
|
||||
required this.estimatedAccuracyMeters,
|
||||
required this.observations,
|
||||
required this.distanceToLandmarksKm,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intaleq_maps/intaleq_maps.dart';
|
||||
|
||||
enum ManeuverType {
|
||||
straight,
|
||||
slightRight,
|
||||
right,
|
||||
sharpRight,
|
||||
slightLeft,
|
||||
left,
|
||||
sharpLeft,
|
||||
keepRight,
|
||||
keepLeft,
|
||||
uTurn,
|
||||
roundabout,
|
||||
arrive,
|
||||
unknown,
|
||||
}
|
||||
|
||||
class NavigationStep {
|
||||
final String instructionAr;
|
||||
final String streetName;
|
||||
final ManeuverType maneuver;
|
||||
final double distanceMeters;
|
||||
final LatLng location;
|
||||
|
||||
const NavigationStep({
|
||||
required this.instructionAr,
|
||||
required this.streetName,
|
||||
required this.maneuver,
|
||||
required this.distanceMeters,
|
||||
required this.location,
|
||||
});
|
||||
|
||||
IconData get icon {
|
||||
switch (maneuver) {
|
||||
case ManeuverType.arrive:
|
||||
return Icons.flag_circle_rounded;
|
||||
case ManeuverType.roundabout:
|
||||
return Icons.roundabout_right_rounded;
|
||||
case ManeuverType.right:
|
||||
case ManeuverType.keepRight:
|
||||
return Icons.turn_right_rounded;
|
||||
case ManeuverType.slightRight:
|
||||
return Icons.turn_slight_right_rounded;
|
||||
case ManeuverType.left:
|
||||
case ManeuverType.keepLeft:
|
||||
return Icons.turn_left_rounded;
|
||||
case ManeuverType.slightLeft:
|
||||
return Icons.turn_slight_left_rounded;
|
||||
case ManeuverType.sharpRight:
|
||||
return Icons.turn_sharp_right_rounded;
|
||||
case ManeuverType.sharpLeft:
|
||||
return Icons.turn_sharp_left_rounded;
|
||||
case ManeuverType.uTurn:
|
||||
return Icons.u_turn_right_rounded;
|
||||
case ManeuverType.straight:
|
||||
default:
|
||||
return Icons.straight_rounded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ActiveNavigationState {
|
||||
final bool isNavigating;
|
||||
final List<LatLng> routePoints;
|
||||
final List<NavigationStep> steps;
|
||||
final int currentStepIndex;
|
||||
final double remainingDistanceKm;
|
||||
final double remainingDurationMinutes;
|
||||
final double currentSpeedKmH;
|
||||
final double currentHeadingDeg;
|
||||
final LatLng? currentPosition;
|
||||
final bool isSimulating;
|
||||
|
||||
const ActiveNavigationState({
|
||||
this.isNavigating = false,
|
||||
this.routePoints = const [],
|
||||
this.steps = const [],
|
||||
this.currentStepIndex = 0,
|
||||
this.remainingDistanceKm = 0.0,
|
||||
this.remainingDurationMinutes = 0.0,
|
||||
this.currentSpeedKmH = 0.0,
|
||||
this.currentHeadingDeg = 0.0,
|
||||
this.currentPosition,
|
||||
this.isSimulating = false,
|
||||
});
|
||||
|
||||
NavigationStep? get currentStep =>
|
||||
(steps.isNotEmpty && currentStepIndex < steps.length) ? steps[currentStepIndex] : null;
|
||||
|
||||
NavigationStep? get nextStep =>
|
||||
(steps.isNotEmpty && currentStepIndex + 1 < steps.length) ? steps[currentStepIndex + 1] : null;
|
||||
}
|
||||
Reference in New Issue
Block a user