feat(tactical): add interactive location picker, minefield quantities analysis, and organizational feasibility study
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -465,3 +465,114 @@ export async function calculateRadialViewshed(
|
||||
visiblePercentage
|
||||
};
|
||||
}
|
||||
|
||||
export interface MinefieldAnalysisResult {
|
||||
startLat: number;
|
||||
startLng: number;
|
||||
endLat: number;
|
||||
endLng: number;
|
||||
frontageMeters: number;
|
||||
azimuthDegrees: number;
|
||||
startElevation: number;
|
||||
endElevation: number;
|
||||
avgSlopeDegrees: number;
|
||||
suitabilityScore: number; // 0-100%
|
||||
suitabilityVerdict: string;
|
||||
suitabilityVerdictAr: string;
|
||||
isChokePoint: boolean;
|
||||
quantities: {
|
||||
antiTankMines: number;
|
||||
antiPersonnelMines: number;
|
||||
fuseSets: number;
|
||||
warningSigns: number;
|
||||
rowsCount: number;
|
||||
depthMeters: number;
|
||||
estimatedDeploymentHours: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tactical Minefield Barrier & Sapper Engineering Analysis
|
||||
* دراسة جدوى وكميات حقل الألغام الدفاعي وفحص التضاريس
|
||||
*/
|
||||
export async function calculateMinefieldAnalysis(
|
||||
startLat: number,
|
||||
startLng: number,
|
||||
endLat: number,
|
||||
endLng: number,
|
||||
densityLevel: 'standard' | 'dense' | 'light' = 'standard'
|
||||
): Promise<MinefieldAnalysisResult> {
|
||||
const frontageMeters = calculateDistance(startLat, startLng, endLat, endLng);
|
||||
const azimuthDegrees = calculateAzimuth(startLat, startLng, endLat, endLng);
|
||||
|
||||
const startElev = await sampleElevationAt(startLat, startLng);
|
||||
const endElev = await sampleElevationAt(endLat, endLng);
|
||||
|
||||
// Sample intermediate points to determine valley / ridge / choke point profile
|
||||
const samples = 10;
|
||||
const elevs: number[] = [];
|
||||
for (let i = 0; i <= samples; i++) {
|
||||
const frac = i / samples;
|
||||
const lat = startLat + (endLat - startLat) * frac;
|
||||
const lng = startLng + (endLng - startLng) * frac;
|
||||
const el = await sampleElevationAt(lat, lng);
|
||||
elevs.push(el);
|
||||
}
|
||||
|
||||
const elevDiff = Math.abs(endElev - startElev);
|
||||
const avgSlopeRad = frontageMeters > 0 ? Math.atan(elevDiff / frontageMeters) : 0;
|
||||
const avgSlopeDegrees = Math.round((avgSlopeRad * (180 / Math.PI)) * 10) / 10;
|
||||
|
||||
// Check if center is lower than edges (a defile / valley choke point)
|
||||
const midElev = elevs[Math.floor(samples / 2)];
|
||||
const isChokePoint = midElev < Math.min(startElev, endElev) - 10 || avgSlopeDegrees <= 10;
|
||||
|
||||
const densityFactor = densityLevel === 'dense' ? 1.5 : densityLevel === 'light' ? 0.6 : 1.0;
|
||||
const atMinesPerMeter = 1.0 * densityFactor;
|
||||
const apMinesPerMeter = 2.0 * densityFactor;
|
||||
|
||||
const antiTankMines = Math.round(frontageMeters * atMinesPerMeter);
|
||||
const antiPersonnelMines = Math.round(frontageMeters * apMinesPerMeter);
|
||||
const warningSigns = Math.max(4, Math.round(frontageMeters / 30));
|
||||
const deploymentHours = Math.round(((frontageMeters / 150) * 2 * densityFactor) * 10) / 10;
|
||||
|
||||
let suitabilityScore = 85;
|
||||
let suitabilityVerdict = 'Highly Effective Defensive Barrier';
|
||||
let suitabilityVerdictAr = 'موضع دفاعي نموذجي يسد محور اقتراب الدروع بفعالية';
|
||||
|
||||
if (avgSlopeDegrees > 20) {
|
||||
suitabilityScore = 55;
|
||||
suitabilityVerdict = 'Steep Terrain: Armor movement already restricted by natural slope';
|
||||
suitabilityVerdictAr = 'انحدار جبلي شديد: التضاريس تشكل مانعاً طبيعياً لحركة الدروع';
|
||||
} else if (isChokePoint) {
|
||||
suitabilityScore = 96;
|
||||
suitabilityVerdict = 'Optimal Choke Point Defile Barrier';
|
||||
suitabilityVerdictAr = 'ممر ومضيق إجباري مثالي (Choke Point) يمنع التفاف آليات العدو';
|
||||
}
|
||||
|
||||
return {
|
||||
startLat,
|
||||
startLng,
|
||||
endLat,
|
||||
endLng,
|
||||
frontageMeters: Math.round(frontageMeters),
|
||||
azimuthDegrees: Math.round(azimuthDegrees * 10) / 10,
|
||||
startElevation: Math.round(startElev),
|
||||
endElevation: Math.round(endElev),
|
||||
avgSlopeDegrees,
|
||||
suitabilityScore,
|
||||
suitabilityVerdict,
|
||||
suitabilityVerdictAr,
|
||||
isChokePoint,
|
||||
quantities: {
|
||||
antiTankMines,
|
||||
antiPersonnelMines,
|
||||
fuseSets: Math.round((antiTankMines + antiPersonnelMines) * 1.1),
|
||||
warningSigns,
|
||||
rowsCount: densityLevel === 'dense' ? 4 : 3,
|
||||
depthMeters: densityLevel === 'dense' ? 75 : 50,
|
||||
estimatedDeploymentHours: Math.max(1, deploymentHours)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user