From 6bd0bc0ce5799db2ebd4fdf8cf6f6f89043c7459 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Tue, 18 Aug 2026 10:42:04 +0300 Subject: [PATCH] =?UTF-8?q?feat(tactical):=20add=20comprehensive=20Terrain?= =?UTF-8?q?=20Study=20(=D8=AF=D8=B1=D8=A7=D8=B3=D8=A9=20=D8=A7=D9=84=D8=A3?= =?UTF-8?q?=D8=B1=D8=B6)=20with=20natural/manmade=20obstacles=20and=20OAKO?= =?UTF-8?q?C=20intelligence=20report?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/pages/TacticalDefenseView.tsx | 435 ++++++++++++++++++++- apps/web/src/utils/elevationService.ts | 273 +++++++++++++ 2 files changed, 695 insertions(+), 13 deletions(-) diff --git a/apps/web/src/pages/TacticalDefenseView.tsx b/apps/web/src/pages/TacticalDefenseView.tsx index 728e1db..1274877 100644 --- a/apps/web/src/pages/TacticalDefenseView.tsx +++ b/apps/web/src/pages/TacticalDefenseView.tsx @@ -23,20 +23,28 @@ import { MapPin, Target, LocateFixed, - Move + Move, + Building, + TreePine, + Printer, + FileText, + Compass, + Check } from 'lucide-react'; import { calculateLineOfSight, calculateRadialViewshed, calculateMinefieldAnalysis, + calculateTerrainStudy, LineOfSightResult, Viewshed360Result, MinefieldAnalysisResult, + TerrainStudyResult, calculateDistance, calculateAzimuth } from '../utils/elevationService'; -type TacticalMode = 'los' | 'viewshed' | 'artillery' | 'minefield' | 'hlz' | 'symbols' | 'study'; +type TacticalMode = 'terrain' | 'los' | 'viewshed' | 'artillery' | 'minefield' | 'hlz' | 'symbols' | 'study'; interface TacticalSymbolItem { id: string; @@ -67,11 +75,18 @@ export const TacticalDefenseView: React.FC = () => { const mapContainer = useRef(null); const map = useRef(null); - const [mode, setMode] = useState('los'); + const [mode, setMode] = useState('terrain'); const [cursorPos, setCursorPos] = useState({ lat: 31.95, lng: 35.93, elev: 850 }); const [activePlacement, setActivePlacement] = useState(null); - // Line of Sight State + // 1. Terrain Tactical Study State (دراسة الأرض) + const [terrainCenter, setTerrainCenter] = useState<[number, number] | null>([31.9539, 35.9106]); + const [terrainRadius, setTerrainRadius] = useState(4000); + const [terrainResult, setTerrainResult] = useState(null); + const [terrainLoading, setTerrainLoading] = useState(false); + const [copiedReport, setCopiedReport] = useState(false); + + // 2. Line of Sight State const [losPointA, setLosPointA] = useState<[number, number] | null>([31.9539, 35.9106]); const [losPointB, setLosPointB] = useState<[number, number] | null>([32.0125, 35.8540]); const [losObsHeight, setLosObsHeight] = useState(2); @@ -79,14 +94,14 @@ export const TacticalDefenseView: React.FC = () => { const [losResult, setLosResult] = useState(null); const [losLoading, setLosLoading] = useState(false); - // Viewshed State + // 3. Viewshed State const [viewshedCenter, setViewshedCenter] = useState<[number, number] | null>([31.9800, 35.8800]); const [viewshedRadius, setViewshedRadius] = useState(5000); const [viewshedHeight, setViewshedHeight] = useState(10); const [viewshedResult, setViewshedResult] = useState(null); const [viewshedLoading, setViewshedLoading] = useState(false); - // Artillery Fire Mission State + // 4. Artillery Fire Mission State const [gunPos, setGunPos] = useState<[number, number] | null>([31.9300, 35.9100]); const [targetPos, setTargetPos] = useState<[number, number] | null>([32.0400, 35.8200]); const [caliber, setCaliber] = useState('155mm Howitzer (M109)'); @@ -94,19 +109,19 @@ export const TacticalDefenseView: React.FC = () => { const [artilleryResult, setArtilleryResult] = useState(null); const [artilleryLoading, setArtilleryLoading] = useState(false); - // Minefield Analysis State + // 5. Minefield Analysis State const [mineStart, setMineStart] = useState<[number, number] | null>([31.9700, 35.8600]); const [mineEnd, setMineEnd] = useState<[number, number] | null>([31.9950, 35.8750]); const [mineDensity, setMineDensity] = useState<'standard' | 'dense' | 'light'>('standard'); const [mineResult, setMineResult] = useState(null); const [mineLoading, setMineLoading] = useState(false); - // HLZ State + // 6. HLZ State const [hlzCenter, setHlzCenter] = useState<[number, number] | null>([31.9600, 35.9000]); const [hlzResult, setHlzResult] = useState(null); const [hlzLoading, setHlzLoading] = useState(false); - // Tactical Symbols State + // 7. Tactical Symbols State const [symbols, setSymbols] = useState(DEFAULT_SYMBOLS); const [selectedSymbolType, setSelectedSymbolType] = useState('friendly'); const [newSymbolName, setNewSymbolName] = useState(''); @@ -120,6 +135,9 @@ export const TacticalDefenseView: React.FC = () => { const activePlacementRef = useRef(activePlacement); activePlacementRef.current = activePlacement; + const terrainCenterRef = useRef(terrainCenter); + terrainCenterRef.current = terrainCenter; + const losPointARef = useRef(losPointA); losPointARef.current = losPointA; @@ -203,6 +221,8 @@ export const TacticalDefenseView: React.FC = () => { // Sync Draggable Markers to Map useEffect(() => { if (!map.current) return; + // Terrain Study Center + updateMarker('terrain-c', terrainCenter, '⛰️ مركز دراسة الأرض', '#6366f1', (pos) => setTerrainCenter(pos)); // LOS updateMarker('los-a', losPointA, '📍 راصد A', '#0284c7', (pos) => setLosPointA(pos)); updateMarker('los-b', losPointB, '🎯 هدف B', '#d97706', (pos) => setLosPointB(pos)); @@ -216,7 +236,7 @@ export const TacticalDefenseView: React.FC = () => { updateMarker('mine-e', mineEnd, '⛔ نهاية حقل الألغام', '#991b1b', (pos) => setMineEnd(pos)); // HLZ updateMarker('hlz-c', hlzCenter, '🚁 مركز HLZ', '#059669', (pos) => setHlzCenter(pos)); - }, [losPointA, losPointB, viewshedCenter, gunPos, targetPos, mineStart, mineEnd, hlzCenter]); + }, [terrainCenter, losPointA, losPointB, viewshedCenter, gunPos, targetPos, mineStart, mineEnd, hlzCenter]); // Map Initialization useEffect(() => { @@ -256,6 +276,11 @@ export const TacticalDefenseView: React.FC = () => { const currentMode = modeRef.current; // 1. Explicit Active Placement from Buttons + if (placement === 'terrain-center') { + setTerrainCenter([clickedLat, clickedLng]); + setActivePlacement(null); + return; + } if (placement === 'los-a') { setLosPointA([clickedLat, clickedLng]); setActivePlacement(null); @@ -298,7 +323,9 @@ export const TacticalDefenseView: React.FC = () => { } // 2. Default Context-Aware Click by Active Mode - if (currentMode === 'los') { + if (currentMode === 'terrain') { + setTerrainCenter([clickedLat, clickedLng]); + } else if (currentMode === 'los') { if (!losPointARef.current) { setLosPointA([clickedLat, clickedLng]); } else if (!losPointBRef.current) { @@ -352,6 +379,33 @@ export const TacticalDefenseView: React.FC = () => { }); initialMap.on('load', () => { + // 0. Terrain Study Circle Layer + initialMap.addSource('tactical-terrain-src', { + type: 'geojson', + data: { type: 'FeatureCollection', features: [] } + }); + + initialMap.addLayer({ + id: 'tactical-terrain-fill', + type: 'fill', + source: 'tactical-terrain-src', + paint: { + 'fill-color': '#6366f1', + 'fill-opacity': 0.15 + } + }); + + initialMap.addLayer({ + id: 'tactical-terrain-line', + type: 'line', + source: 'tactical-terrain-src', + paint: { + 'line-color': '#818cf8', + 'line-width': 2.5, + 'line-dasharray': [3, 2] + } + }); + // 1. Line of Sight Layer initialMap.addSource('tactical-los-src', { type: 'geojson', @@ -493,6 +547,50 @@ export const TacticalDefenseView: React.FC = () => { }; }, []); + // Run Terrain Tactical Study + const runTerrainStudy = () => { + if (!terrainCenter) return; + setTerrainLoading(true); + calculateTerrainStudy(terrainCenter[0], terrainCenter[1], terrainRadius) + .then((res) => { + setTerrainResult(res); + setTerrainLoading(false); + + // Draw sector boundary polygon on map + if (map.current && map.current.getSource('tactical-terrain-src')) { + const points = 48; + const coords: [number, number][] = []; + const R_earth = 6371000; + for (let i = 0; i <= points; i++) { + const angle = (i / points) * 2 * Math.PI; + const dLat = (terrainRadius / R_earth) * (180 / Math.PI) * Math.cos(angle); + const dLng = (terrainRadius / (R_earth * Math.cos((terrainCenter[0] * Math.PI) / 180))) * (180 / Math.PI) * Math.sin(angle); + coords.push([terrainCenter[1] + dLng, terrainCenter[0] + dLat]); + } + + (map.current.getSource('tactical-terrain-src') as maplibregl.GeoJSONSource).setData({ + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + properties: {}, + geometry: { + type: 'Polygon', + coordinates: [coords] + } + } + ] + }); + } + }) + .catch(() => setTerrainLoading(false)); + }; + + // Auto-run initial terrain study on mount + useEffect(() => { + runTerrainStudy(); + }, [terrainCenter, terrainRadius]); + // Update Line of Sight Calculations & Map Layer useEffect(() => { if (!losPointA || !losPointB) { @@ -700,10 +798,10 @@ export const TacticalDefenseView: React.FC = () => { essential: true }); - // Dynamically re-anchor operational points into this region so the user is not stuck with old coordinates const lat = sector.lat; const lng = sector.lng; + setTerrainCenter([Number(lat.toFixed(5)), Number(lng.toFixed(5))]); setLosPointA([Number((lat - 0.015).toFixed(5)), Number((lng - 0.015).toFixed(5))]); setLosPointB([Number((lat + 0.025).toFixed(5)), Number((lng + 0.025).toFixed(5))]); setViewshedCenter([Number(lat.toFixed(5)), Number(lng.toFixed(5))]); @@ -714,6 +812,38 @@ export const TacticalDefenseView: React.FC = () => { setHlzCenter([Number(lat.toFixed(5)), Number(lng.toFixed(5))]); }; + // Copy Intelligence Dossier to Clipboard + const handleCopyReport = () => { + if (!terrainResult) return; + const text = ` +=== تقرير الاستخبارات الجغرافية ودراسة الأرض التكتيكية === +القطاع: ${terrainResult.sectorName} +الإحداثيات: ${terrainResult.centerLat}, ${terrainResult.centerLng} +نصف القطر: ${terrainResult.radiusMeters / 1000} كم | المساحة: ${terrainResult.areaKm2} كم² +طبيعة الأرض: ${terrainResult.terrainClassificationAr} +حالة الحركة والمناورة: ${terrainResult.mobilityStatusAr} +المناسيب: أعلى قمة ${terrainResult.maxElevation}م | أخفض نقطة ${terrainResult.minElevation}م | الفارق التضاريسي ${terrainResult.reliefMeters}م +الانحدار: متوسط ${terrainResult.avgSlopeDegrees}° | أقصى انحدار ${terrainResult.maxSlopeDegrees}° + +[الموانع الطبيعية]: +${terrainResult.naturalObstacles.map(o => `- ${o.name}: ${o.description}`).join('\n')} + +[الموانع الصناعية والبنية التحتية]: +${terrainResult.manMadeObstacles.map(m => `- ${m.name}: ${m.description} (${m.tacticalNote})`).join('\n')} + +[المناطق المأهولة والعمران]: +- الكثافة: ${terrainResult.urbanAndDemographics.densityAr} +- التجمعات: ${terrainResult.urbanAndDemographics.settlements.join('، ')} +- بيئة قتال المباني: ${terrainResult.urbanAndDemographics.moutComplexity} + +[التوصيات التكتيكية]: +${terrainResult.tacticalRecommendations.map((r, i) => `${i + 1}. ${r}`).join('\n')} +`; + navigator.clipboard.writeText(text); + setCopiedReport(true); + setTimeout(() => setCopiedReport(false), 2500); + }; + return (
{ {/* Tactical Modes Selector */}
{[ + { id: 'terrain', label: 'دراسة الأرض', icon: }, { id: 'los', label: 'تبادل الرؤية (LOS)', icon: }, { id: 'viewshed', label: 'كشف 360°', icon: }, { id: 'artillery', label: 'موقع المدفعية', icon: }, @@ -853,7 +984,7 @@ export const TacticalDefenseView: React.FC = () => { {/* Left Side Tactical Control Deck */}
+ {/* ========================================================================= */} + {/* MODE 0: TERRAIN TACTICAL STUDY (دراسة الأرض والموانع والعمران) */} + {/* ========================================================================= */} + {mode === 'terrain' && ( +
+
+
+

+ دراسة الأرض والاستخبارات الجغرافية +

+

+ تحليل طبيعة الأرض، الموانع الطبيعية والصناعية، والمناطق المأهولة +

+
+ {terrainResult && ( + + )} +
+ + {/* Terrain Center Coordinate Card */} +
+
+ 📍 مركز قطاع دراسة الأرض: + +
+
+
+ + setTerrainCenter([Number(e.target.value), terrainCenter ? terrainCenter[1] : 35.9])} + style={{ width: '100%', background: '#0f172a', border: '1px solid rgba(255,255,255,0.2)', color: '#fff', padding: '5px 8px', borderRadius: 6, fontSize: '0.78rem' }} + /> +
+
+ + setTerrainCenter([terrainCenter ? terrainCenter[0] : 31.9, Number(e.target.value)])} + style={{ width: '100%', background: '#0f172a', border: '1px solid rgba(255,255,255,0.2)', color: '#fff', padding: '5px 8px', borderRadius: 6, fontSize: '0.78rem' }} + /> +
+
+
+ + {/* Radius Slider */} +
+ + setTerrainRadius(Number(e.target.value))} + style={{ width: '100%' }} + /> +
+ + + + {/* Terrain Intelligence Dossier Output */} + {terrainResult && ( +
+ + {/* Top Mobility & Classification Badge */} +
+
{terrainResult.sectorName}
+
+ {terrainResult.terrainClassificationAr} +
+
+ ⚡ {terrainResult.mobilityStatusAr} +
+
+ + {/* Elevation & Slope Metrics Grid */} +
+
+
أعلى قمة
+
{terrainResult.maxElevation}م
+
+
+
أخفض نقطة
+
{terrainResult.minElevation}م
+
+
+
الفارق التضاريسي
+
{terrainResult.reliefMeters}م
+
+
+ + {/* Slope Distribution Bar */} +
+
+ توزيع درجات الانحدار (Slope Analysis): + متوسط: {terrainResult.avgSlopeDegrees}° +
+
+
+
+
+
+
+ ■ منبسط (<5°): {terrainResult.slopeDistribution.flatPercentage}% + ■ متوسط (5-15°): {terrainResult.slopeDistribution.moderatePercentage}% + ■ وعر (>15°): {terrainResult.slopeDistribution.steepPercentage}% +
+
+ + {/* SECTION 1: NATURAL OBSTACLES */} +
+
+ 1. الموانع الطبيعية (Natural Obstacles): +
+
+ {terrainResult.naturalObstacles.map((obs, idx) => ( +
+
• {obs.name} ({obs.type})
+
{obs.description}
+
الأثر التكتيكي: {obs.impact}
+
+ ))} +
+
+ + {/* SECTION 2: MAN-MADE OBSTACLES & INFRASTRUCTURE */} +
+
+ 2. الموانع الصناعية والبنية التحتية (Man-Made Features): +
+
+ {terrainResult.manMadeObstacles.map((obs, idx) => ( +
+
• {obs.name}
+
{obs.description}
+
ملاحظة تكتيكية: {obs.tacticalNote}
+
+ ))} +
+
+ + {/* SECTION 3: URBAN AREAS & DEMOGRAPHICS */} +
+
+ 3. المناطق المأهولة بالسكان والعمران: +
+
+
الكثافة السكانية: {terrainResult.urbanAndDemographics.densityAr}
+
التجمعات والقرى الرئيسية: {terrainResult.urbanAndDemographics.settlements.join('، ')}
+
قتال المناطق المبنية (MOUT): {terrainResult.urbanAndDemographics.moutComplexity}
+
مخاطر الأضرار الجانبية: {terrainResult.urbanAndDemographics.collateralDamageRisk}
+
+
+ + {/* SECTION 4: SOIL & CONCEALMENT */} +
+
+ 4. التربة وإمكانات الإخفاء والتمويه: +
+
+
نوع التربة: {terrainResult.landCoverAndCover.soilType}
+
صلاحية السير للآليات: {terrainResult.landCoverAndCover.trafficability}
+
الإخفاء من الرصد الأرضي: {terrainResult.landCoverAndCover.concealmentRating}
+
الانكشاف للرصد الجوي: {terrainResult.landCoverAndCover.airObservationExposure}
+
+
+ + {/* SECTION 5: COMMANDER'S TACTICAL RECOMMENDATIONS (OAKOC) */} +
+
+ 5. التقييم التكتيكي للقائد والتوصيات الميدانية: +
+
+ {terrainResult.tacticalRecommendations.map((rec, i) => ( +
+ {i + 1}. + {rec} +
+ ))} +
+
+ +
+ )} +
+ )} + + {/* ========================================================================= */} {/* MODE 1: LINE OF SIGHT */} + {/* ========================================================================= */} {mode === 'los' && (
@@ -1080,7 +1477,9 @@ export const TacticalDefenseView: React.FC = () => {
)} + {/* ========================================================================= */} {/* MODE 2: 360 VIEWSHED */} + {/* ========================================================================= */} {mode === 'viewshed' && (
@@ -1198,7 +1597,9 @@ export const TacticalDefenseView: React.FC = () => {
)} + {/* ========================================================================= */} {/* MODE 3: ARTILLERY FIRE MISSION */} + {/* ========================================================================= */} {mode === 'artillery' && (
@@ -1366,7 +1767,9 @@ export const TacticalDefenseView: React.FC = () => {
)} + {/* ========================================================================= */} {/* MODE 4: MINEFIELD ANALYSIS */} + {/* ========================================================================= */} {mode === 'minefield' && (
@@ -1543,7 +1946,9 @@ export const TacticalDefenseView: React.FC = () => {
)} + {/* ========================================================================= */} {/* MODE 5: HLZ ASSESSMENT */} + {/* ========================================================================= */} {mode === 'hlz' && (
@@ -1637,7 +2042,9 @@ export const TacticalDefenseView: React.FC = () => {
)} + {/* ========================================================================= */} {/* MODE 6: TACTICAL SYMBOLS & DEPLOYMENT */} + {/* ========================================================================= */} {mode === 'symbols' && (
@@ -1787,7 +2194,9 @@ export const TacticalDefenseView: React.FC = () => {
)} + {/* ========================================================================= */} {/* MODE 7: TACTICAL FEASIBILITY STUDY & ORGANIZATION REPORT */} + {/* ========================================================================= */} {mode === 'study' && (
diff --git a/apps/web/src/utils/elevationService.ts b/apps/web/src/utils/elevationService.ts index 40332cf..d47a244 100644 --- a/apps/web/src/utils/elevationService.ts +++ b/apps/web/src/utils/elevationService.ts @@ -576,3 +576,276 @@ export async function calculateMinefieldAnalysis( }; } +export interface TerrainStudyResult { + centerLat: number; + centerLng: number; + radiusMeters: number; + areaKm2: number; + sectorName: string; + centerElevation: number; + minElevation: number; + maxElevation: number; + reliefMeters: number; + avgSlopeDegrees: number; + maxSlopeDegrees: number; + slopeDistribution: { + flatPercentage: number; // < 5 deg (Go) + moderatePercentage: number; // 5-15 deg (Slow-Go) + steepPercentage: number; // > 15 deg (No-Go / Obstacle) + }; + terrainClassification: string; + terrainClassificationAr: string; + mobilityStatus: 'GO' | 'SLOW-GO' | 'NO-GO'; + mobilityStatusAr: string; + naturalObstacles: Array<{ + name: string; + type: string; + description: string; + impact: string; + }>; + manMadeObstacles: Array<{ + name: string; + type: string; + description: string; + tacticalNote: string; + }>; + urbanAndDemographics: { + density: 'HIGH' | 'MEDIUM' | 'LOW' | 'SPARSE'; + densityAr: string; + settlements: string[]; + moutComplexity: string; + collateralDamageRisk: string; + }; + landCoverAndCover: { + soilType: string; + trafficability: string; + concealmentRating: string; + airObservationExposure: string; + }; + oakocAssessment: { + obstacles: string; + avenuesOfApproach: string; + keyTerrain: string; + observationAndFieldsOfFire: string; + coverAndConcealment: string; + }; + tacticalRecommendations: string[]; +} + +/** + * Military Tactical Terrain Intelligence & Environmental Study (OAKOC Doctrine) + * دراسة الأرض الشاملة: التضاريس، الموانع الطبيعية والصناعية، والمناطق المأهولة + */ +export async function calculateTerrainStudy( + centerLat: number, + centerLng: number, + radiusMeters: number = 3000 +): Promise { + const centerElev = await sampleElevationAt(centerLat, centerLng); + const areaKm2 = Math.round(Math.PI * Math.pow(radiusMeters / 1000, 2) * 10) / 10; + + // Multi-point radial sampling across the sector + const samples = 24; + const elevations: number[] = [centerElev]; + const slopes: number[] = []; + + for (let i = 0; i < samples; i++) { + const angleRad = (i / samples) * 2 * Math.PI; + const dist = radiusMeters * (0.3 + (i % 3) * 0.35); + const R_earth = 6371000; + const dLat = (dist / R_earth) * (180 / Math.PI) * Math.cos(angleRad); + const dLng = (dist / (R_earth * Math.cos((centerLat * Math.PI) / 180))) * (180 / Math.PI) * Math.sin(angleRad); + + const sLat = centerLat + dLat; + const sLng = centerLng + dLng; + const el = await sampleElevationAt(sLat, sLng); + elevations.push(el); + + const slopeDeg = Math.atan(Math.abs(el - centerElev) / dist) * (180 / Math.PI); + slopes.push(slopeDeg); + } + + const minElev = Math.min(...elevations); + const maxElev = Math.max(...elevations); + const relief = maxElev - minElev; + + const avgSlope = Math.round((slopes.reduce((a, b) => a + b, 0) / slopes.length) * 10) / 10; + const maxSlope = Math.round(Math.max(...slopes) * 10) / 10; + + const flatCount = slopes.filter(s => s < 5).length; + const modCount = slopes.filter(s => s >= 5 && s <= 15).length; + const steepCount = slopes.filter(s => s > 15).length; + + const flatPct = Math.round((flatCount / slopes.length) * 100); + const modPct = Math.round((modCount / slopes.length) * 100); + const steepPct = Math.max(0, 100 - flatPct - modPct); + + // Sector Geolocation and Regional Characteristics + let sectorName = 'قطاع عمليات ميداني'; + let terrainClassificationAr = 'هضاب وتلال متوسطة الوعورة'; + let terrainClassification = 'Rolling Hills & Ridges'; + let urbanDensity: 'HIGH' | 'MEDIUM' | 'LOW' | 'SPARSE' = 'LOW'; + let urbanDensityAr = 'كثافة منخفضة / ريفية'; + let settlements: string[] = ['تجمعات سكنية متفرقة', 'مزارع ومنشآت ريفية']; + let soilType = 'تربة طينية صخرية جافة'; + let trafficability = 'جيدة للمركبات المدولبة والمجنزرة مع الحذر من الانزلاقات في المنحدرات'; + + if (centerLat > 32.3 && centerLng < 36.0) { + sectorName = 'قاطع الشمال / حوض اليرموك وإربد'; + terrainClassificationAr = 'مرتفعات جبلية تتخللها أودية سحيقة وخوانق مائية'; + terrainClassification = 'Highland Plateaus with Deep Gorges'; + urbanDensity = 'MEDIUM'; + urbanDensityAr = 'كثافة متوسطة (قرى وضواحي ممتدة)'; + settlements = ['بلدات وضواحي إربد', 'قرى حوض اليرموك', 'مزارع ومحميات وادي الشلالة']; + soilType = 'تربة زراعية خصبة وصخور كلسية'; + trafficability = 'صعبة على حواف الأودية - تتطلب محاور طرق رئيسية'; + } else if (centerLat >= 31.8 && centerLat <= 32.2 && centerLng >= 35.8 && centerLng <= 36.1) { + sectorName = 'قاطع الوسط / إقليم العاصمة عمان'; + terrainClassificationAr = 'هضاب وكتل جبلية حضرية مكتظة بالعمران'; + terrainClassification = 'Urbanized Highland Terrain'; + urbanDensity = 'HIGH'; + urbanDensityAr = 'كثافة عالية (بيئة قتال مباني MOUT)'; + settlements = ['أحياء ومجمعات العاصمة عمان', 'المناطق التجارية والتقاطعات المرورية', 'مناطق صناعية متقدمة']; + soilType = 'أرض معبدة وأرصفة إسمنتية مع تربة صخرية'; + trafficability = 'ممتازة على شبكة الطرق ولكنها مقيدة بالاختناقات المرورية والمباني'; + } else if (centerLng > 36.1) { + sectorName = 'قاطع البادية والشرق / المفرق والصفاوي'; + terrainClassificationAr = 'سهول صحراوية مفتوحة وأراضي حرات بازلتية'; + terrainClassification = 'Open Desert Steppe & Basalt Harrah'; + urbanDensity = 'SPARSE'; + urbanDensityAr = 'شبه خالية / تجمعات بدوية ومزارع متفرقة'; + settlements = ['تجمعات ريفية بدوية', 'مواقع عسكرية ونقاط حدودية', 'مزارع صحراوية']; + soilType = 'رمال وحصى بازلتية صلبة'; + trafficability = 'حركة حرة مفتوحة للدروع والآليات الصحراوية (Cross-Country GO)'; + } else if (centerLat < 31.8 && centerLng < 35.7) { + sectorName = 'قاطع الغور / المنخفض الصدعي والبحر الميت'; + terrainClassificationAr = 'أخفـض نقطة على سطح الأرض (جروف حادة ومنحدرات قاسية)'; + terrainClassification = 'Rift Valley Escarpment (-400m MSL)'; + urbanDensity = 'LOW'; + urbanDensityAr = 'كثافة منخفضة (مزارع الغور والمنتجعات)'; + settlements = ['مزارع الأغوار الجنوبية', 'مجمعات الفنادق ومصانع البوتاس', 'قرى غور الصافي']; + soilType = 'طمي نهري وسبخات ملحية وصخور رسوبية'; + trafficability = 'حذرة جداً بجانب السبخات - ممتازة على طريق البحر الميت الرئيسي'; + } else if (centerLat < 31.5 && centerLat > 30.0) { + sectorName = 'قاطع الجنوب الجبلي / مرتفعات الكرك والشوبك'; + terrainClassificationAr = 'سلاسل جبلية شاهقة وتلال متصلة ذات إشراف تكتيكي'; + terrainClassification = 'High Mountainous Plateaus (>1200m)'; + urbanDensity = 'LOW'; + urbanDensityAr = 'بلدات جبلية وقرى متفرقة'; + settlements = ['مدينة الكرك التاريخية', 'قرى المزار والشوبك', 'مزارع الجبال الجنوبية']; + soilType = 'صخور جيرية صلبة وحجارة متناثرة'; + trafficability = 'مقيدة بالممرات الجبلية والمنعطفات الحادة (Slow-Go)'; + } else if (centerLat <= 30.0) { + sectorName = 'قاطع الجنوب الصحراوي / وادي رم والعقبة'; + terrainClassificationAr = 'جبال رملية شاهقة (Monoliths) تتخللها ممرات ووديان رملية واسعة'; + terrainClassification = 'Sandstone Monoliths & Desert Valleys'; + urbanDensity = 'SPARSE'; + urbanDensityAr = 'شبه خالية (مخيمات سياحية وتجمعات بدوية)'; + settlements = ['قرية وادي رم', 'مخيمات الديسة السياحية', 'نقاط المراقبة الجنوبية']; + soilType = 'رمال ناعمة وصخور رملية ضخمة'; + trafficability = 'ممتازة للآليات ذات الدفع الرباعي والمجنزرات في بطون الأودية'; + } + + // Determine Overall Mobility Status + let mobilityStatus: 'GO' | 'SLOW-GO' | 'NO-GO' = 'GO'; + let mobilityStatusAr = 'حركة حرة ممتازة للآليات والدروع (Cross-Country GO)'; + if (steepPct > 40 || avgSlope > 14) { + mobilityStatus = 'NO-GO'; + mobilityStatusAr = 'مانع تضاريسي - حركة مقيدة وشديدة الصعوبة (NO-GO)'; + } else if (steepPct > 15 || modPct > 40 || avgSlope > 7) { + mobilityStatus = 'SLOW-GO'; + mobilityStatusAr = 'حركة بطيئة تتطلب مسارب وتجهيزاً هندسياً (SLOW-GO)'; + } + + return { + centerLat, + centerLng, + radiusMeters, + areaKm2, + sectorName, + centerElevation: Math.round(centerElev), + minElevation: Math.round(minElev), + maxElevation: Math.round(maxElev), + reliefMeters: Math.round(relief), + avgSlopeDegrees: avgSlope, + maxSlopeDegrees: maxSlope, + slopeDistribution: { + flatPercentage: flatPct, + moderatePercentage: modPct, + steepPercentage: steepPct + }, + terrainClassification, + terrainClassificationAr, + mobilityStatus, + mobilityStatusAr, + naturalObstacles: [ + { + name: 'المنحدرات والجروف التضاريسية الحادة', + type: 'انحدار طبوغرافي', + description: `تشكل المناطق ذات الانحدار الشديد (${steepPct}%) مانعاً طبيعياً يحد من تقدم الدروع ويجبرها على الالتفاف.`, + impact: 'إعاقة محاور الهجوم المعادي وتوجيهه نحو الخناق المجهزة بالنيران' + }, + { + name: 'الأودية والشعاب ومجاري السيول الطبيعية', + type: 'أودية ومصارف مائية', + description: 'بطون الأودية تمثل ممرات حركة محجوبة عن خط النظر ولكنها عرضة للكمائن والسيول الفجائية.', + impact: 'تصلح كمسارب تسلل للمشاة ولكنها خطرة للآليات الثقيلة' + }, + { + name: 'القمم والمرتفعات الحاكمة المجاورة', + type: 'أرض مسيطرة (Key Terrain)', + description: `أعلى قمة في القطاع بارتفاع ${maxElev}م توفر إشرافاً نارياً واستطلاعياً على عمق يصل إلى ${Math.round(radiusMeters / 500)} كم.`, + impact: 'وجوب احتلالها بنقاط مراقبة وأسلحة إسناد مضادة للدروع' + } + ], + manMadeObstacles: [ + { + name: 'شبكة الطرق والمحاور المعبدة', + type: 'محاور حركة سريعة', + description: 'الطرق الرئيسية المارة بالقطاع تتيح سرعة إعادة انتشار القوات والإمداد اللوجستي.', + tacticalNote: 'تعتبر أهدافاً حيوية يجب تأمينها بنقاط سيطرة وتفتيش وغلق سريع' + }, + { + name: 'خطوط نقل الطاقة وأبراج الاتصالات', + type: 'بنية تحتية صناعية', + description: 'أبراج الضغط العالي والاتصالات تشكل عوائق أمام الطيران المنخفض ومواقع محتملة لمحطات الإعاقة اللاسلكية.', + tacticalNote: 'تجنب هبوط المروحيات بالقرب من خطوط الضغط العالي' + }, + { + name: 'المباني والمنشآت الخرسانية الممتدة', + type: 'موانع مبنية', + description: 'المباني المتفرقة توفر سواتر خرسانية ممتازة ضد الشظايا ونيران الأسلحة الخفيفة.', + tacticalNote: 'تتطلب تطهيراً هندسياً لضمان خلوها من العبوات والأفخاخ' + } + ], + urbanAndDemographics: { + density: urbanDensity, + densityAr: urbanDensityAr, + settlements, + moutComplexity: urbanDensity === 'HIGH' ? 'معقدة جداً وتتطلب تدريب قتال مباني متخصص' : 'بسيطة إلى متوسطة وتقتصر على أطراف القرى', + collateralDamageRisk: urbanDensity === 'HIGH' ? 'عالية جداً وتتطلب ذخائر موجهة وقواعد اشتباك صارمة' : 'منخفضة مع مراعاة حماية الأعيان المدنية' + }, + landCoverAndCover: { + soilType, + trafficability, + concealmentRating: steepPct > 20 || urbanDensity === 'HIGH' ? 'ممتازة خلف التموجات والمباني' : 'متوسطة إلى مكشوفة في الأراضي المفتوحة', + airObservationExposure: urbanDensity === 'HIGH' ? 'مختلطة (مباني تحجب الرؤية الجوية)' : 'عالية للرصد الجوي والمسيرات نهاراً' + }, + oakocAssessment: { + obstacles: `القطاع يحتوي على ${steepPct}% أراضٍ شديدة الوعورة تشكل موانع طبيعية، مع وجود محاور طرق رئيسية تشكل ممرات حركة سريعة.`, + avenuesOfApproach: 'محاور الاقتراب الرئيسية تتبع بطون الهضاب وشبكة الطرق الفرعية، مما يسهل رصدها وتغطيتها بالمدفعية ومضادات الدروع.', + keyTerrain: `المرتفع ${maxElev}م يشكل الأرض الحاكمة (Decisive Terrain) والسيطرة عليه تمنح تفوقاً نارياً حاسماً.`, + observationAndFieldsOfFire: `حقول الرماية مكشوفة ومثالية في قطاعات (${flatPct}%) المنبسطة، ومقيدة في قطاعات الأودية والعمران.`, + coverAndConcealment: 'السواتر الطبيعية متوفرة على المنحدرات المعاكسة (Reverse Slopes) وفي الجيوب المنخفضة.' + }, + tacticalRecommendations: [ + `تمركز نقاط المراقبة والرادار على المرتفع الحاكم بارتفاع ${maxElev}م لتأمين الإنذار المبكر.`, + 'استغلال المنحدرات الشديدة كمانع طبيعي وزرع حقول الألغام الدفاعية في الممرات الإجبارية والخناق.', + 'تأمين محاور الطرق المعبدة وتجهيز خطط غلق هندسي فورية لقطع تقدم أرتال العدو السريعة.', + 'نشر وحدات المشاة الآلية في المنحدرات الخلفية لحمايتها من الرصد والنار المباشرة (Defilade).', + 'تخصيص مهابط المروحيات والإخلاء في المناطق المستوية ذات الانحدار الأقل من 5 درجات.' + ] + }; +} + +