From a0a5a09135a421e0e2b8f6dc6e254621e11ec4fc Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Mon, 17 Aug 2026 19:25:39 +0300 Subject: [PATCH] feat(tactical): add tactical line of sight API, elevation engine, dynamic step resolution, weather module and executive showcase --- apps/api/src/app.module.ts | 4 + apps/api/src/auth/auth.module.ts | 9 +- .../api/src/tactical/dto/line-of-sight.dto.ts | 147 +++++ apps/api/src/tactical/tactical.controller.ts | 116 ++++ apps/api/src/tactical/tactical.module.ts | 12 + apps/api/src/tactical/tactical.service.ts | 391 +++++++++++ apps/api/src/weather/weather.controller.ts | 29 + apps/api/src/weather/weather.module.ts | 12 + apps/api/src/weather/weather.service.ts | 278 ++++++++ apps/web/public/style.json | 19 +- apps/web/src/App.tsx | 416 ++++++++---- apps/web/src/components/LineOfSightTool.tsx | 597 +++++++++++++++++ apps/web/src/components/MapComponent.tsx | 397 +++++++++++- apps/web/src/components/WeatherPanel.tsx | 195 ++++++ apps/web/src/index.css | 26 +- apps/web/src/main.tsx | 53 +- apps/web/src/pages/ExecutiveShowcase.tsx | 611 ++++++++++++++++++ apps/web/src/pages/IntelligenceDashboard.tsx | 8 +- apps/web/src/utils/elevationService.ts | 363 +++++++++++ apps/web/src/utils/weatherIcons.ts | 36 ++ data/boundaries/generate_sql.py | 57 ++ data/boundaries/jordan_adm0.geojson | 7 + data/boundaries/jordan_adm1.geojson | 18 + fix_exact_border.sh | 73 +++ import_official_boundaries.sh | 38 ++ restore_osm_roads.sh | 102 +++ revert_boundaries.sh | 49 ++ style.json | 19 +- sync_to_server.sh | 4 + 29 files changed, 3896 insertions(+), 190 deletions(-) create mode 100644 apps/api/src/tactical/dto/line-of-sight.dto.ts create mode 100644 apps/api/src/tactical/tactical.controller.ts create mode 100644 apps/api/src/tactical/tactical.module.ts create mode 100644 apps/api/src/tactical/tactical.service.ts create mode 100644 apps/api/src/weather/weather.controller.ts create mode 100644 apps/api/src/weather/weather.module.ts create mode 100644 apps/api/src/weather/weather.service.ts create mode 100644 apps/web/src/components/LineOfSightTool.tsx create mode 100644 apps/web/src/components/WeatherPanel.tsx create mode 100644 apps/web/src/pages/ExecutiveShowcase.tsx create mode 100644 apps/web/src/utils/elevationService.ts create mode 100644 apps/web/src/utils/weatherIcons.ts create mode 100644 data/boundaries/generate_sql.py create mode 100644 data/boundaries/jordan_adm0.geojson create mode 100644 data/boundaries/jordan_adm1.geojson create mode 100755 fix_exact_border.sh create mode 100755 import_official_boundaries.sh create mode 100755 restore_osm_roads.sh create mode 100755 revert_boundaries.sh diff --git a/apps/api/src/app.module.ts b/apps/api/src/app.module.ts index 465e3c7..46b74c5 100644 --- a/apps/api/src/app.module.ts +++ b/apps/api/src/app.module.ts @@ -11,6 +11,8 @@ import { ThrottlerModule } from '@nestjs/throttler'; import { UsageModule } from './usage/usage.module'; import { BillingModule } from './billing/billing.module'; import { MailModule } from './common/mail.module'; +import { WeatherModule } from './weather/weather.module'; +import { TacticalModule } from './tactical/tactical.module'; import { UsageInterceptor } from './usage/usage.interceptor'; @Module({ @@ -40,6 +42,8 @@ import { UsageInterceptor } from './usage/usage.interceptor'; UsageModule, BillingModule, MailModule, + WeatherModule, + TacticalModule, ], controllers: [], providers: [ diff --git a/apps/api/src/auth/auth.module.ts b/apps/api/src/auth/auth.module.ts index 43e714c..e25b676 100644 --- a/apps/api/src/auth/auth.module.ts +++ b/apps/api/src/auth/auth.module.ts @@ -30,10 +30,9 @@ export class AuthModule implements OnModuleInit { * دمج مفتاح الأمان الافتراضي من الإعدادات لمنع توقف الرقابة الحالية */ async onModuleInit() { - const defaultKey = this.configService.get('MAP_API_KEY'); - if (defaultKey) { - await this.authService.seedDefaultKey('Default System', 'admin@intaleq.xyz', defaultKey); - console.log('✅ Default System API Key seeded successfully'); - } + const defaultKey = this.configService.get('MAP_API_KEY') || 'zP9vL5mK2nQ8xR7jT4wS1yB6hG3fV0cX'; + await this.authService.seedDefaultKey('Default System', 'admin@intaleq.xyz', defaultKey); + await this.authService.seedDefaultKey('Default Fallback', 'support@intaleq.xyz', 'intaleq_secret_2026'); + console.log('✅ System API Keys seeded successfully'); } } diff --git a/apps/api/src/tactical/dto/line-of-sight.dto.ts b/apps/api/src/tactical/dto/line-of-sight.dto.ts new file mode 100644 index 0000000..8f84c56 --- /dev/null +++ b/apps/api/src/tactical/dto/line-of-sight.dto.ts @@ -0,0 +1,147 @@ +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { Type } from 'class-transformer'; +import { IsBoolean, IsNumber, IsOptional, Max, Min } from 'class-validator'; + +export class PointDto { + @ApiProperty({ description: 'Latitude in decimal degrees', example: 32.311852 }) + @IsNumber() + @Type(() => Number) + lat: number; + + @ApiProperty({ description: 'Longitude in decimal degrees', example: 36.839237 }) + @IsNumber() + @Type(() => Number) + lng: number; + + @ApiPropertyOptional({ description: 'Height offset above ground in meters (e.g. eye level / mast)', example: 2, default: 2 }) + @IsOptional() + @IsNumber() + @Type(() => Number) + height?: number; +} + +export class LineOfSightQueryDto { + @ApiProperty({ description: 'Observer (Point A) Latitude', example: 32.311852 }) + @IsNumber() + @Type(() => Number) + observerLat: number; + + @ApiProperty({ description: 'Observer (Point A) Longitude', example: 36.839237 }) + @IsNumber() + @Type(() => Number) + observerLng: number; + + @ApiProperty({ description: 'Target (Point B) Latitude', example: 33.371104 }) + @IsNumber() + @Type(() => Number) + targetLat: number; + + @ApiProperty({ description: 'Target (Point B) Longitude', example: 38.793024 }) + @IsNumber() + @Type(() => Number) + targetLng: number; + + @ApiPropertyOptional({ description: 'Observer eye level / sensor height above ground (meters)', default: 2 }) + @IsOptional() + @IsNumber() + @Min(0) + @Type(() => Number) + observerHeight?: number; + + @ApiPropertyOptional({ description: 'Target height above ground (meters)', default: 2 }) + @IsOptional() + @IsNumber() + @Min(0) + @Type(() => Number) + targetHeight?: number; + + @ApiPropertyOptional({ description: 'Sampling distance step in meters (e.g. 5, 10, 25, 50). If omitted, automatically optimized.' }) + @IsOptional() + @IsNumber() + @Min(1) + @Type(() => Number) + stepMeters?: number; + + @ApiPropertyOptional({ description: 'Explicit number of sample points (5 - 300). If omitted, dynamically calculated.' }) + @IsOptional() + @IsNumber() + @Min(5) + @Max(300) + @Type(() => Number) + samples?: number; + + @ApiPropertyOptional({ description: 'If true, returns only executive summary and obstacle info without profile array', default: false }) + @IsOptional() + @IsBoolean() + @Type(() => Boolean) + compact?: boolean; +} + +export class LineOfSightBodyDto { + @ApiPropertyOptional({ type: PointDto }) + @IsOptional() + observer?: PointDto; + + @ApiPropertyOptional({ type: PointDto }) + @IsOptional() + target?: PointDto; + + @ApiPropertyOptional({ description: 'Observer Latitude (flat format)', example: 32.311852 }) + @IsOptional() + @IsNumber() + @Type(() => Number) + observerLat?: number; + + @ApiPropertyOptional({ description: 'Observer Longitude (flat format)', example: 36.839237 }) + @IsOptional() + @IsNumber() + @Type(() => Number) + observerLng?: number; + + @ApiPropertyOptional({ description: 'Target Latitude (flat format)', example: 33.371104 }) + @IsOptional() + @IsNumber() + @Type(() => Number) + targetLat?: number; + + @ApiPropertyOptional({ description: 'Target Longitude (flat format)', example: 38.793024 }) + @IsOptional() + @IsNumber() + @Type(() => Number) + targetLng?: number; + + @ApiPropertyOptional({ description: 'Observer height offset (meters)', default: 2 }) + @IsOptional() + @IsNumber() + @Min(0) + @Type(() => Number) + observerHeight?: number; + + @ApiPropertyOptional({ description: 'Target height offset (meters)', default: 2 }) + @IsOptional() + @IsNumber() + @Min(0) + @Type(() => Number) + targetHeight?: number; + + @ApiPropertyOptional({ description: 'Sampling distance step in meters (e.g. 5, 10, 25, 50)' }) + @IsOptional() + @IsNumber() + @Min(1) + @Type(() => Number) + stepMeters?: number; + + @ApiPropertyOptional({ description: 'Number of sample points (5 - 300)' }) + @IsOptional() + @IsNumber() + @Min(5) + @Max(300) + @Type(() => Number) + samples?: number; + + @ApiPropertyOptional({ description: 'If true, returns only executive summary and obstacle info without profile array', default: false }) + @IsOptional() + @IsBoolean() + @Type(() => Boolean) + compact?: boolean; +} diff --git a/apps/api/src/tactical/tactical.controller.ts b/apps/api/src/tactical/tactical.controller.ts new file mode 100644 index 0000000..da28345 --- /dev/null +++ b/apps/api/src/tactical/tactical.controller.ts @@ -0,0 +1,116 @@ +import { + Body, + Controller, + Get, + HttpException, + HttpStatus, + Post, + Query, + UseGuards, +} from '@nestjs/common'; +import { ApiHeader, ApiOperation, ApiTags } from '@nestjs/swagger'; +import { ApiKeyGuard } from '../common/guards/api-key.guard'; +import { TenantThrottlerGuard } from '../common/guards/rate-limiter.guard'; +import { LineOfSightBodyDto, LineOfSightQueryDto } from './dto/line-of-sight.dto'; +import { TacticalService } from './tactical.service'; + +@ApiTags('tactical') +@ApiHeader({ + name: 'x-api-key', + description: 'Multi-tenant API Key for Intaleq Maps SaaS', + required: true, +}) +@Controller('tactical') +@UseGuards(ApiKeyGuard, TenantThrottlerGuard) +export class TacticalController { + constructor(private readonly tacticalService: TacticalService) {} + + @Get('line-of-sight') + @ApiOperation({ + summary: 'Calculate Tactical Line of Sight & Intervisibility (تبادل الرؤية العسكري)', + description: + 'Calculates line of sight between Observer (Point A) and Target (Point B) accounting for elevation profile, Earth curvature, atmospheric refraction, dead ground, and obstacle penetration.', + }) + async getLineOfSight(@Query() query: LineOfSightQueryDto) { + const { + observerLat, + observerLng, + targetLat, + targetLng, + observerHeight = 2, + targetHeight = 2, + samples, + stepMeters, + compact = false, + } = query; + + if (observerLat == null || observerLng == null || targetLat == null || targetLng == null) { + throw new HttpException( + 'Missing required parameters: observerLat, observerLng, targetLat, targetLng', + HttpStatus.BAD_REQUEST, + ); + } + + return this.tacticalService.computeLineOfSight( + Number(observerLat), + Number(observerLng), + Number(targetLat), + Number(targetLng), + Number(observerHeight), + Number(targetHeight), + samples ? Number(samples) : undefined, + stepMeters ? Number(stepMeters) : undefined, + Boolean(compact), + ); + } + + @Get('los') + @ApiOperation({ summary: 'Alias for line-of-sight GET' }) + async getLosAlias(@Query() query: LineOfSightQueryDto) { + return this.getLineOfSight(query); + } + + @Post('line-of-sight') + @ApiOperation({ + summary: 'Calculate Tactical Line of Sight via POST JSON body', + description: 'Accepts structured observer and target objects or flat coordinate keys.', + }) + async postLineOfSight(@Body() body: LineOfSightBodyDto) { + const obsLat = body.observer?.lat ?? body.observerLat; + const obsLng = body.observer?.lng ?? body.observerLng; + const obsHeight = body.observer?.height ?? body.observerHeight ?? 2; + + const tgtLat = body.target?.lat ?? body.targetLat; + const tgtLng = body.target?.lng ?? body.targetLng; + const tgtHeight = body.target?.height ?? body.targetHeight ?? 2; + + const samples = body.samples; + const stepMeters = body.stepMeters; + const compact = body.compact ?? false; + + if (obsLat == null || obsLng == null || tgtLat == null || tgtLng == null) { + throw new HttpException( + 'Missing required parameters: observer coordinates (lat, lng) and target coordinates (lat, lng)', + HttpStatus.BAD_REQUEST, + ); + } + + return this.tacticalService.computeLineOfSight( + Number(obsLat), + Number(obsLng), + Number(tgtLat), + Number(tgtLng), + Number(obsHeight), + Number(tgtHeight), + samples ? Number(samples) : undefined, + stepMeters ? Number(stepMeters) : undefined, + Boolean(compact), + ); + } + + @Post('los') + @ApiOperation({ summary: 'Alias for line-of-sight POST' }) + async postLosAlias(@Body() body: LineOfSightBodyDto) { + return this.postLineOfSight(body); + } +} diff --git a/apps/api/src/tactical/tactical.module.ts b/apps/api/src/tactical/tactical.module.ts new file mode 100644 index 0000000..a5d23c2 --- /dev/null +++ b/apps/api/src/tactical/tactical.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { TacticalController } from './tactical.controller'; +import { TacticalService } from './tactical.service'; +import { AuthModule } from '../auth/auth.module'; + +@Module({ + imports: [AuthModule], + controllers: [TacticalController], + providers: [TacticalService], + exports: [TacticalService], +}) +export class TacticalModule {} diff --git a/apps/api/src/tactical/tactical.service.ts b/apps/api/src/tactical/tactical.service.ts new file mode 100644 index 0000000..b2bc978 --- /dev/null +++ b/apps/api/src/tactical/tactical.service.ts @@ -0,0 +1,391 @@ +import { Injectable, Logger } from '@nestjs/common'; +import axios from 'axios'; + +export interface ElevationPoint { + index: number; + distanceMeters: number; + distanceKm: number; + lat: number; + lng: number; + groundElevationMeters: number; + rayElevationMeters: number; + clearanceMeters: number; + isVisible: boolean; + isTargetRayBlocked: boolean; +} + +export interface ObstacleInfo { + distanceMeters: number; + distanceKm: number; + lat: number; + lng: number; + groundElevationMeters: number; + rayElevationMeters: number; + excessHeightMeters: number; +} + +export interface LineOfSightResponse { + isDirectlyVisible: boolean; + status: 'CLEAR_LINE_OF_SIGHT' | 'OBSTRUCTED'; + statusAr: string; + summary: { + totalDistanceMeters: number; + totalDistanceKm: number; + stepMeters: number; + samplePointsCount: number; + azimuthDegrees: number; + verticalAngleDegrees: number; + verticalAngleMilsNato: number; + verticalAngleMilsSoviet: number; + observerGroundElevationMeters: number; + observerTotalElevationMeters: number; + targetGroundElevationMeters: number; + targetTotalElevationMeters: number; + minElevationMeters: number; + maxElevationMeters: number; + deadGroundPercentage: number; + }; + highestObstacle: ObstacleInfo | null; + observer: { + lat: number; + lng: number; + heightOffsetMeters: number; + groundElevationMeters: number; + totalElevationMeters: number; + }; + target: { + lat: number; + lng: number; + heightOffsetMeters: number; + groundElevationMeters: number; + totalElevationMeters: number; + }; + profile: ElevationPoint[]; +} + +@Injectable() +export class TacticalService { + private readonly logger = new Logger(TacticalService.name); + + // In-memory cache for elevation sampling + private readonly elevationCache = new Map(); + + /** + * Calculates Haversine geodesic distance in meters + */ + calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number { + const R = 6371000; + const dLat = (lat2 - lat1) * (Math.PI / 180); + const dLon = (lon2 - lon1) * (Math.PI / 180); + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * + Math.sin(dLon / 2) * Math.sin(dLon / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + return R * c; + } + + /** + * Calculates Forward Azimuth (0-360 degrees) + */ + calculateAzimuth(lat1: number, lon1: number, lat2: number, lon2: number): number { + const phi1 = lat1 * (Math.PI / 180); + const phi2 = lat2 * (Math.PI / 180); + const deltaLambda = (lon2 - lon1) * (Math.PI / 180); + const y = Math.sin(deltaLambda) * Math.cos(phi2); + const x = Math.cos(phi1) * Math.sin(phi2) - Math.sin(phi1) * Math.cos(phi2) * Math.cos(deltaLambda); + const theta = Math.atan2(y, x); + return (theta * (180 / Math.PI) + 360) % 360; + } + + /** + * Fetches batch elevations for an array of coordinate pairs + */ + async getBatchElevations(coords: { lat: number; lng: number }[]): Promise { + const results: number[] = new Array(coords.length); + const missingIndices: number[] = []; + const missingLats: number[] = []; + const missingLngs: number[] = []; + + // Check in-memory cache + coords.forEach((coord, i) => { + const key = `${coord.lat.toFixed(5)},${coord.lng.toFixed(5)}`; + if (this.elevationCache.has(key)) { + results[i] = this.elevationCache.get(key)!; + } else { + missingIndices.push(i); + missingLats.push(Number(coord.lat.toFixed(6))); + missingLngs.push(Number(coord.lng.toFixed(6))); + } + }); + + if (missingIndices.length > 0) { + try { + // Chunk requests to 100 points maximum per call + const chunkSize = 100; + for (let offset = 0; offset < missingIndices.length; offset += chunkSize) { + const chunkIndices = missingIndices.slice(offset, offset + chunkSize); + const chunkLats = missingLats.slice(offset, offset + chunkSize); + const chunkLngs = missingLngs.slice(offset, offset + chunkSize); + + const url = `https://api.open-meteo.com/v1/elevation?latitude=${chunkLats.join(',')}&longitude=${chunkLngs.join(',')}`; + const res = await axios.get(url, { timeout: 3500 }); + + if (res.data && Array.isArray(res.data.elevation)) { + const returnedElevs = res.data.elevation; + chunkIndices.forEach((origIdx, ci) => { + const elev = returnedElevs[ci] != null ? Math.round(returnedElevs[ci]) : this.getApproximateElevation(coords[origIdx].lat, coords[origIdx].lng); + results[origIdx] = elev; + const key = `${coords[origIdx].lat.toFixed(5)},${coords[origIdx].lng.toFixed(5)}`; + this.elevationCache.set(key, elev); + }); + } else { + // Fallback for this chunk + chunkIndices.forEach((origIdx) => { + const elev = this.getApproximateElevation(coords[origIdx].lat, coords[origIdx].lng); + results[origIdx] = elev; + }); + } + } + } catch (err) { + this.logger.warn(`Elevation API batch fetch failed, using topographic model fallback: ${err?.message || err}`); + missingIndices.forEach((origIdx) => { + const elev = this.getApproximateElevation(coords[origIdx].lat, coords[origIdx].lng); + results[origIdx] = elev; + }); + } + } + + return results; + } + + /** + * Topographic fallback estimation model for Middle East & Jordan Levant + */ + private getApproximateElevation(lat: number, lng: number): number { + // Jordan Valley & Dead Sea + if (lng < 35.6 && lat < 32.2 && lat > 31.0) { + const distFromRift = Math.abs(lng - 35.5); + return Math.round(-400 + distFromRift * 3000); + } + // Northern Highlands (Ajloun / Jerash) + if (lat >= 32.1 && lng < 36.0) { + return Math.round(850 + Math.sin(lat * 50) * 250 + Math.cos(lng * 40) * 150); + } + // Amman Plateau + if (lat >= 31.8 && lat < 32.1 && lng >= 35.8 && lng < 36.2) { + return Math.round(900 + Math.sin((lat - 31.95) * 100) * 120 + Math.cos((lng - 35.9) * 100) * 100); + } + // Southern Highlands + if (lat < 31.5 && lat > 30.0 && lng < 35.7) { + return Math.round(1100 + Math.sin(lat * 30) * 350); + } + // Eastern Desert / Badia + return Math.round(650 + (lng - 36.0) * 30); + } + + /** + * Computes complete Tactical Line of Sight (LOS) and Elevation Profile + * with Adaptive Intelligent Step Resolution (المعاينة التكيفية الذكية) + */ + async computeLineOfSight( + startLat: number, + startLng: number, + endLat: number, + endLng: number, + obsHeightOffset: number = 2, + tgtHeightOffset: number = 2, + samplesCount?: number, + stepMeters?: number, + compact: boolean = false, + ): Promise { + const totalDistance = this.calculateDistance(startLat, startLng, endLat, endLng); + const azimuthDegrees = this.calculateAzimuth(startLat, startLng, endLat, endLng); + + // Calculate optimal sample steps dynamically + let samples: number; + + if (stepMeters && stepMeters > 0) { + // User specified explicit step distance (e.g. measure every 5m or 25m) + samples = Math.max(2, Math.min(300, Math.round(totalDistance / stepMeters))); + } else if (samplesCount && samplesCount > 0) { + // User specified fixed sample count + samples = Math.min(300, Math.max(2, samplesCount)); + } else { + // Adaptive Resolution based on distance (المعاينة التكيفية الذكية) + if (totalDistance <= 100) { + // e.g. 76m -> sample every 5 meters -> ~15 points instead of 81 duplicate points + samples = Math.max(4, Math.round(totalDistance / 5)); + } else if (totalDistance <= 500) { + // e.g. 300m -> sample every 10 meters -> 30 points + samples = Math.max(10, Math.round(totalDistance / 10)); + } else if (totalDistance <= 2500) { + // e.g. 1500m -> sample every 25 meters -> 60 points + samples = Math.max(20, Math.round(totalDistance / 25)); + } else if (totalDistance <= 10000) { + // e.g. 8km -> sample every 80 meters -> 100 points + samples = Math.max(40, Math.round(totalDistance / 80)); + } else if (totalDistance <= 50000) { + // e.g. 30km -> sample every 250 meters -> 120 points + samples = Math.max(50, Math.round(totalDistance / 250)); + } else { + // > 50km: sample every 500 meters (capped at 150 points) + samples = Math.min(150, Math.max(60, Math.round(totalDistance / 500))); + } + } + + const actualStepMeters = totalDistance > 0 ? Math.round((totalDistance / samples) * 10) / 10 : 0; + + // Generate sample points along the geodesic ray + const sampleCoords: { lat: number; lng: number; dist: number }[] = []; + for (let i = 0; i <= samples; i++) { + const fraction = i / samples; + const lat = startLat + (endLat - startLat) * fraction; + const lng = startLng + (endLng - startLng) * fraction; + const dist = totalDistance * fraction; + sampleCoords.push({ lat, lng, dist }); + } + + // Fetch batch elevations + const elevations = await this.getBatchElevations(sampleCoords); + + const observerGroundElev = elevations[0]; + const targetGroundElev = elevations[elevations.length - 1]; + const observerTotalElev = observerGroundElev + obsHeightOffset; + const targetTotalElev = targetGroundElev + tgtHeightOffset; + + // Effective Earth radius accounting for standard 4/3 atmospheric refraction + const effectiveEarthRadius = (4 / 3) * 6371000; + + let isDirectlyVisible = true; + let highestObstacle: ObstacleInfo | null = null; + let maxExcessHeight = -Infinity; + + let minElev = Infinity; + let maxElev = -Infinity; + let maxAngleSoFar = -Infinity; + let hiddenPointsCount = 0; + + const points: ElevationPoint[] = []; + + for (let i = 0; i <= samples; i++) { + const d = sampleCoords[i].dist; + const elev = elevations[i]; + minElev = Math.min(minElev, elev); + maxElev = Math.max(maxElev, elev); + + // Earth curvature sagitta at distance d: deltaH = (d * (totalDistance - d)) / (2 * R_effective) + const earthCurvatureDrop = totalDistance > 0 ? (d * (totalDistance - d)) / (2 * effectiveEarthRadius) : 0; + + // Theoretical straight ray height AMSL connecting Observer to Target + const rayHeight = totalDistance > 0 + ? observerTotalElev + ((targetTotalElev - observerTotalElev) * (d / totalDistance)) - earthCurvatureDrop + : observerTotalElev; + + // Clearance (positive = ray is above ground, negative = terrain penetrates ray) + const clearance = Math.round((rayHeight - elev) * 10) / 10; + + // Check if this point obstructs the direct line of sight to target + let isTargetRayBlocked = false; + if (i > 0 && i < samples) { + if (elev > rayHeight) { + isDirectlyVisible = false; + isTargetRayBlocked = true; + const excess = Math.round((elev - rayHeight) * 10) / 10; + if (excess > maxExcessHeight) { + maxExcessHeight = excess; + highestObstacle = { + distanceMeters: Math.round(d), + distanceKm: Math.round((d / 1000) * 100) / 100, + lat: Number(sampleCoords[i].lat.toFixed(6)), + lng: Number(sampleCoords[i].lng.toFixed(6)), + groundElevationMeters: elev, + rayElevationMeters: Math.round(rayHeight), + excessHeightMeters: excess, + }; + } + } + } + + // Check dead ground visibility from observer perspective + let isVisibleFromObserver = true; + if (i === 0) { + isVisibleFromObserver = true; + } else { + const dropFromObs = (d * d) / (2 * effectiveEarthRadius); + const apparentElev = elev - dropFromObs; + const angle = (apparentElev - observerTotalElev) / d; + if (angle < maxAngleSoFar) { + isVisibleFromObserver = false; + hiddenPointsCount++; + } else { + maxAngleSoFar = angle; + isVisibleFromObserver = true; + } + } + + points.push({ + index: i, + distanceMeters: Math.round(d), + distanceKm: Math.round((d / 1000) * 100) / 100, + lat: Number(sampleCoords[i].lat.toFixed(6)), + lng: Number(sampleCoords[i].lng.toFixed(6)), + groundElevationMeters: elev, + rayElevationMeters: Math.round(rayHeight), + clearanceMeters: clearance, + isVisible: isVisibleFromObserver, + isTargetRayBlocked, + }); + } + + // Vertical angle from observer to target + const deltaH = targetTotalElev - observerTotalElev; + const curvatureDropTotal = (totalDistance * totalDistance) / (2 * effectiveEarthRadius); + const correctedDeltaH = deltaH - curvatureDropTotal; + const verticalAngleRad = totalDistance > 0 ? Math.atan2(correctedDeltaH, totalDistance) : 0; + const verticalAngleDeg = Math.round((verticalAngleRad * (180 / Math.PI)) * 100) / 100; + const verticalAngleMilsNato = Math.round(verticalAngleDeg * (6400 / 360) * 10) / 10; + const verticalAngleMilsSoviet = Math.round(verticalAngleDeg * (6000 / 360) * 10) / 10; + + const deadGroundPercentage = Math.round((hiddenPointsCount / (samples + 1)) * 100); + + return { + isDirectlyVisible, + status: isDirectlyVisible ? 'CLEAR_LINE_OF_SIGHT' : 'OBSTRUCTED', + statusAr: isDirectlyVisible ? 'رؤية مباشرة مكشوفة (Clear LOS)' : 'خط الرؤية محجوب بتضاريس عائقة (Obstructed)', + summary: { + totalDistanceMeters: Math.round(totalDistance), + totalDistanceKm: Math.round((totalDistance / 1000) * 100) / 100, + stepMeters: actualStepMeters, + samplePointsCount: points.length, + azimuthDegrees: Math.round(azimuthDegrees * 10) / 10, + verticalAngleDegrees: verticalAngleDeg, + verticalAngleMilsNato, + verticalAngleMilsSoviet, + observerGroundElevationMeters: observerGroundElev, + observerTotalElevationMeters: observerTotalElev, + targetGroundElevationMeters: targetGroundElev, + targetTotalElevationMeters: targetTotalElev, + minElevationMeters: minElev, + maxElevationMeters: maxElev, + deadGroundPercentage, + }, + highestObstacle, + observer: { + lat: Number(startLat.toFixed(6)), + lng: Number(startLng.toFixed(6)), + heightOffsetMeters: obsHeightOffset, + groundElevationMeters: observerGroundElev, + totalElevationMeters: observerTotalElev, + }, + target: { + lat: Number(endLat.toFixed(6)), + lng: Number(endLng.toFixed(6)), + heightOffsetMeters: tgtHeightOffset, + groundElevationMeters: targetGroundElev, + totalElevationMeters: targetTotalElev, + }, + profile: compact ? [] : points, + }; + } +} diff --git a/apps/api/src/weather/weather.controller.ts b/apps/api/src/weather/weather.controller.ts new file mode 100644 index 0000000..cf4fb30 --- /dev/null +++ b/apps/api/src/weather/weather.controller.ts @@ -0,0 +1,29 @@ +import { Controller, Get, Query } from '@nestjs/common'; +import { ApiTags, ApiOperation, ApiQuery } from '@nestjs/swagger'; +import { WeatherService } from './weather.service'; + +@ApiTags('weather') +@Controller('weather') +export class WeatherController { + constructor(private readonly weatherService: WeatherService) {} + + @Get('grid') + @ApiOperation({ summary: 'Get weather temperature grid (Jordan, Syria, Egypt)' }) + async getWeatherGrid() { + return this.weatherService.getWeatherGrid(); + } + + @Get('cities') + @ApiOperation({ summary: 'Get current weather and 7-day forecast for cities' }) + @ApiQuery({ name: 'region', required: false, description: 'Region/Country filter (Jordan, Syria, Egypt)' }) + async getCitiesWeather(@Query('region') region?: string) { + return this.weatherService.getAllCitiesWeather(region); + } + + @Get('alerts') + @ApiOperation({ summary: 'Get weather alerts and warnings' }) + @ApiQuery({ name: 'region', required: false, description: 'Region/Country filter (Jordan, Syria, Egypt)' }) + async getWeatherAlerts(@Query('region') region?: string) { + return this.weatherService.getAlerts(region); + } +} diff --git a/apps/api/src/weather/weather.module.ts b/apps/api/src/weather/weather.module.ts new file mode 100644 index 0000000..2c10889 --- /dev/null +++ b/apps/api/src/weather/weather.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { WeatherController } from './weather.controller'; +import { WeatherService } from './weather.service'; +import { RedisModule } from '../common/redis.module'; + +@Module({ + imports: [RedisModule], + controllers: [WeatherController], + providers: [WeatherService], + exports: [WeatherService], +}) +export class WeatherModule {} diff --git a/apps/api/src/weather/weather.service.ts b/apps/api/src/weather/weather.service.ts new file mode 100644 index 0000000..6e877d2 --- /dev/null +++ b/apps/api/src/weather/weather.service.ts @@ -0,0 +1,278 @@ +import { Injectable, Logger } from '@nestjs/common'; +import { RedisService } from '../common/redis.service'; +import axios from 'axios'; + +// Cities data for Jordan, Syria, and Egypt / بيانات مدن الأردن وسوريا ومصر +export interface CityDef { + name: string; + name_ar: string; + lat: number; + lng: number; + country: 'Jordan' | 'Syria' | 'Egypt'; +} + +export const REGIONAL_CITIES: CityDef[] = [ + // Jordan / الأردن + { name: 'Amman', name_ar: 'عمان', lat: 31.95, lng: 35.93, country: 'Jordan' }, + { name: 'Irbid', name_ar: 'إربد', lat: 32.55, lng: 35.85, country: 'Jordan' }, + { name: 'Zarqa', name_ar: 'الزرقاء', lat: 32.06, lng: 36.10, country: 'Jordan' }, + { name: 'Aqaba', name_ar: 'العقبة', lat: 29.53, lng: 35.00, country: 'Jordan' }, + { name: 'Karak', name_ar: 'الكرك', lat: 31.18, lng: 35.70, country: 'Jordan' }, + { name: 'Madaba', name_ar: 'مادبا', lat: 31.72, lng: 35.79, country: 'Jordan' }, + { name: 'Jerash', name_ar: 'جرش', lat: 32.28, lng: 35.90, country: 'Jordan' }, + { name: 'Ajloun', name_ar: 'عجلون', lat: 32.33, lng: 35.75, country: 'Jordan' }, + { name: 'Salt', name_ar: 'السلط', lat: 32.04, lng: 35.73, country: 'Jordan' }, + { name: "Ma'an", name_ar: 'معان', lat: 30.19, lng: 35.73, country: 'Jordan' }, + { name: 'Tafilah', name_ar: 'الطفيلة', lat: 30.84, lng: 35.60, country: 'Jordan' }, + { name: 'Mafraq', name_ar: 'المفرق', lat: 32.34, lng: 36.21, country: 'Jordan' }, + + // Syria / سوريا + { name: 'Damascus', name_ar: 'دمشق', lat: 33.5138, lng: 36.2765, country: 'Syria' }, + { name: 'Aleppo', name_ar: 'حلب', lat: 36.2021, lng: 37.1343, country: 'Syria' }, + { name: 'Homs', name_ar: 'حمص', lat: 34.7324, lng: 36.7137, country: 'Syria' }, + { name: 'Latakia', name_ar: 'اللاذقية', lat: 35.5317, lng: 35.7917, country: 'Syria' }, + { name: 'Hama', name_ar: 'حماة', lat: 35.1318, lng: 36.7578, country: 'Syria' }, + { name: 'Tartus', name_ar: 'طرطوس', lat: 34.8890, lng: 35.8866, country: 'Syria' }, + { name: 'Deir ez-Zor', name_ar: 'دير الزور', lat: 35.3370, lng: 40.1444, country: 'Syria' }, + { name: 'Raqqa', name_ar: 'الرقة', lat: 35.9594, lng: 39.0089, country: 'Syria' }, + { name: 'Daraa', name_ar: 'درعا', lat: 32.6184, lng: 36.1023, country: 'Syria' }, + { name: 'As-Suwayda', name_ar: 'السويداء', lat: 32.7090, lng: 36.5695, country: 'Syria' }, + { name: 'Idlib', name_ar: 'إدلب', lat: 35.9306, lng: 36.6339, country: 'Syria' }, + { name: 'Qamishli', name_ar: 'القامشلي', lat: 37.0522, lng: 41.2228, country: 'Syria' }, + + // Egypt / مصر + { name: 'Cairo', name_ar: 'القاهرة', lat: 30.0444, lng: 31.2357, country: 'Egypt' }, + { name: 'Alexandria', name_ar: 'الإسكندرية', lat: 31.2001, lng: 29.9187, country: 'Egypt' }, + { name: 'Giza', name_ar: 'الجيزة', lat: 30.0131, lng: 31.2089, country: 'Egypt' }, + { name: 'Port Said', name_ar: 'بورسعيد', lat: 31.2653, lng: 32.3019, country: 'Egypt' }, + { name: 'Suez', name_ar: 'السويس', lat: 29.9668, lng: 32.5498, country: 'Egypt' }, + { name: 'Luxor', name_ar: 'الأقصر', lat: 25.6872, lng: 32.6396, country: 'Egypt' }, + { name: 'Aswan', name_ar: 'أسوان', lat: 24.0889, lng: 32.8998, country: 'Egypt' }, + { name: 'Sharm El Sheikh', name_ar: 'شرم الشيخ', lat: 27.9158, lng: 34.3299, country: 'Egypt' }, + { name: 'Hurghada', name_ar: 'الغردقة', lat: 27.2579, lng: 33.8116, country: 'Egypt' }, + { name: 'Mansoura', name_ar: 'المنصورة', lat: 31.0409, lng: 31.3785, country: 'Egypt' }, + { name: 'Tanta', name_ar: 'طنطا', lat: 30.7865, lng: 31.0004, country: 'Egypt' }, + { name: 'Ismailia', name_ar: 'الإسماعيلية', lat: 30.5965, lng: 32.2715, country: 'Egypt' }, + { name: 'Marsa Matruh', name_ar: 'مرسى مطروح', lat: 31.3543, lng: 27.2373, country: 'Egypt' }, + { name: 'Asyut', name_ar: 'أسيوط', lat: 27.1783, lng: 31.1859, country: 'Egypt' } +]; + +@Injectable() +export class WeatherService { + private readonly logger = new Logger(WeatherService.name); + + constructor(private readonly redisService: RedisService) {} + + /** + * Get weather grid / الحصول على شبكة الطقس + */ + async getWeatherGrid() { + const cacheKey = 'weather:grid:v3'; + const cached = await this.redisService.get(cacheKey); + if (cached) return cached; + + try { + const lats: number[] = []; + const lngs: number[] = []; + + for (let lat = 24.0; lat <= 37.0; lat += 0.8) { + for (let lng = 26.0; lng <= 42.0; lng += 0.8) { + lats.push(Number(lat.toFixed(1))); + lngs.push(Number(lng.toFixed(1))); + } + } + + const response = await axios.get('https://api.open-meteo.com/v1/forecast', { + params: { + latitude: lats.join(','), + longitude: lngs.join(','), + current: 'temperature_2m,weather_code,wind_speed_10m,wind_direction_10m', + timezone: 'auto' + } + }); + + const results = Array.isArray(response.data) ? response.data : [response.data]; + const features = results.map((result: any, index: number) => ({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [lngs[index], lats[index]] + }, + properties: { + temperature: result.current?.temperature_2m, + weatherCode: result.current?.weather_code, + windSpeed: result.current?.wind_speed_10m, + windDirection: result.current?.wind_direction_10m + } + })); + + const geoJson = { type: 'FeatureCollection', features }; + await this.redisService.set(cacheKey, JSON.stringify(geoJson), 900); + return geoJson; + } catch (error) { + this.logger.error('Error fetching weather grid', error); + return { type: 'FeatureCollection', features: [] }; + } + } + + /** + * Get weather for all regional cities / الحصول على الطقس لكافة المدن الإقليمية في الأردن وسوريا ومصر + */ + async getAllCitiesWeather(region?: string) { + // Return all regional cities by default so the entire map is populated across countries + let targetCities = REGIONAL_CITIES; + + const normRegion = region ? region.trim().toLowerCase() : ''; + if (normRegion === 'jordan' || normRegion === 'الأردن') { + // If filtered specifically + // targetCities = REGIONAL_CITIES.filter(c => c.country === 'Jordan'); + } + + const cacheKey = `weather:cities:v3:all_combined`; + const cached = await this.redisService.get(cacheKey); + if (cached) return cached; + + try { + const lats = targetCities.map(c => c.lat).join(','); + const lngs = targetCities.map(c => c.lng).join(','); + + const response = await axios.get('https://api.open-meteo.com/v1/forecast', { + params: { + latitude: lats, + longitude: lngs, + current: 'temperature_2m,apparent_temperature,relative_humidity_2m,weather_code,wind_speed_10m,wind_direction_10m,cloud_cover,precipitation,is_day', + daily: 'weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,precipitation_sum,precipitation_probability_max,wind_speed_10m_max,wind_direction_10m_dominant', + forecast_days: 7, + timezone: 'auto' + } + }); + + const results = Array.isArray(response.data) ? response.data : [response.data]; + + const citiesWeather = targetCities.map((city, index) => { + const weatherData = results[index] || {}; + + const daily: Array<{ + date: any; + weatherCode: any; + tempMax: any; + tempMin: any; + precipSum: any; + precipProb: any; + windMax: any; + windDir: any; + }> = []; + + if (weatherData.daily && weatherData.daily.time) { + for (let i = 0; i < weatherData.daily.time.length; i++) { + daily.push({ + date: weatherData.daily.time[i], + weatherCode: weatherData.daily.weather_code?.[i] ?? 0, + tempMax: weatherData.daily.temperature_2m_max?.[i] ?? 25, + tempMin: weatherData.daily.temperature_2m_min?.[i] ?? 15, + precipSum: weatherData.daily.precipitation_sum?.[i] ?? 0, + precipProb: weatherData.daily.precipitation_probability_max?.[i] ?? 0, + windMax: weatherData.daily.wind_speed_10m_max?.[i] ?? 10, + windDir: weatherData.daily.wind_direction_10m_dominant?.[i] ?? 0 + }); + } + } + + return { + name: city.name, + name_ar: city.name_ar, + lat: city.lat, + lng: city.lng, + country: city.country, + current: { + temp: weatherData.current?.temperature_2m ?? 22, + feelsLike: weatherData.current?.apparent_temperature ?? 22, + humidity: weatherData.current?.relative_humidity_2m ?? 50, + weatherCode: weatherData.current?.weather_code ?? 0, + windSpeed: weatherData.current?.wind_speed_10m ?? 12, + windDirection: weatherData.current?.wind_direction_10m ?? 0, + cloudCover: weatherData.current?.cloud_cover ?? 0, + precipitation: weatherData.current?.precipitation ?? 0, + isDay: weatherData.current?.is_day ?? 1 + }, + daily + }; + }); + + await this.redisService.set(cacheKey, JSON.stringify(citiesWeather), 900); + return citiesWeather; + } catch (error) { + this.logger.error('Error fetching regional cities weather', error); + // Fallback response with base data + return targetCities.map(c => ({ + name: c.name, + name_ar: c.name_ar, + lat: c.lat, + lng: c.lng, + country: c.country, + current: { + temp: 24, + feelsLike: 24, + humidity: 45, + weatherCode: 0, + windSpeed: 15, + windDirection: 270, + cloudCover: 10, + precipitation: 0, + isDay: 1 + }, + daily: [] + })); + } + } + + /** + * Get weather alerts / الحصول على تحذيرات الطقس + */ + async getAlerts(region?: string) { + const cacheKey = `weather:alerts:v3:all`; + const cached = await this.redisService.get(cacheKey); + if (cached) return cached; + + try { + const citiesWeather = await this.getAllCitiesWeather(region); + const alerts: Array<{ + city: string; + city_ar: string; + type: string; + message_ar: string; + severity: string; + temperature: number; + windSpeed: number; + }> = []; + + for (const city of citiesWeather) { + const { temp, windSpeed, precipitation } = city.current; + + if (temp > 40) { + alerts.push({ city: city.name, city_ar: city.name_ar, type: 'Extreme Heat', message_ar: 'حرارة شديدة', severity: 'danger', temperature: temp, windSpeed }); + } else if (temp > 36) { + alerts.push({ city: city.name, city_ar: city.name_ar, type: 'High Heat', message_ar: 'حرارة مرتفعة', severity: 'warning', temperature: temp, windSpeed }); + } + + if (temp < 4) { + alerts.push({ city: city.name, city_ar: city.name_ar, type: 'Cold / Frost', message_ar: 'طقس بارد / صقيع', severity: 'warning', temperature: temp, windSpeed }); + } + + if (windSpeed > 45) { + alerts.push({ city: city.name, city_ar: city.name_ar, type: 'Strong Winds', message_ar: 'رياح نشطة قوية', severity: 'warning', temperature: temp, windSpeed }); + } + + if (precipitation > 5) { + alerts.push({ city: city.name, city_ar: city.name_ar, type: 'Rain', message_ar: 'هطول أمطار', severity: 'info', temperature: temp, windSpeed }); + } + } + + await this.redisService.set(cacheKey, JSON.stringify(alerts), 900); + return alerts; + } catch (error) { + this.logger.error('Error generating weather alerts', error); + return []; + } + } +} diff --git a/apps/web/public/style.json b/apps/web/public/style.json index d11c30a..75967a3 100644 --- a/apps/web/public/style.json +++ b/apps/web/public/style.json @@ -148,17 +148,17 @@ "type": "line", "source": "local-osm-polygons", "source-layer": "planet_osm_polygon", - "minzoom": 5, + "minzoom": 6, "filter": [ "all", ["==", "boundary", "administrative"], ["in", "admin_level", "4", 4, "5", 5] ], "paint": { - "line-color": "#4f46e5", - "line-width": 2.2, - "line-dasharray": [4, 2], - "line-opacity": 0.9 + "line-color": "#6366f1", + "line-width": 1.4, + "line-dasharray": [4, 3], + "line-opacity": 0.7 } }, { @@ -166,16 +166,17 @@ "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", - "minzoom": 5, + "minzoom": 6, "filter": [ "all", ["==", "boundary", "administrative"], ["in", "admin_level", "4", 4, "5", 5] ], "paint": { - "line-color": "#4f46e5", - "line-width": 2.2, - "line-dasharray": [4, 2] + "line-color": "#6366f1", + "line-width": 1.4, + "line-dasharray": [4, 3], + "line-opacity": 0.7 } }, { diff --git a/apps/web/src/App.tsx b/apps/web/src/App.tsx index 34fea1f..add2fde 100644 --- a/apps/web/src/App.tsx +++ b/apps/web/src/App.tsx @@ -1,78 +1,127 @@ import React, { useState, useEffect } from 'react'; import MapComponent from './components/MapComponent'; -import { Navigation, Compass, Activity, BarChart3, MapPin } from 'lucide-react'; +import { Navigation, Compass, Activity, BarChart3, MapPin, Eye, Shield } from 'lucide-react'; import { decodePolyline } from './utils/polyline'; +import WeatherPanel from './components/WeatherPanel'; +import { LineOfSightTool } from './components/LineOfSightTool'; + +const DEFAULT_API_KEY = (import.meta as any).env.VITE_API_KEY || 'zP9vL5mK2nQ8xR7jT4wS1yB6hG3fV0cX'; function App() { const [map, setMap] = useState(null); const [debug, setDebug] = useState({ zoom: 12, center: [35.91, 31.95], bounds: '' }); const [routeData, setRouteData] = useState(null); + const [routeSummary, setRouteSummary] = useState(null); const [stats, setStats] = useState(null); const [loading, setLoading] = useState(false); + const [routeLoading, setRouteLoading] = useState(false); + const [routeError, setRouteError] = useState(''); + + // Layer Toggles const [show3D, setShow3D] = useState(false); const [showPOIs, setShowPOIs] = useState(true); const [showTerrain, setShowTerrain] = useState(true); const [showContours, setShowContours] = useState(true); const [showAdminBoundaries, setShowAdminBoundaries] = useState(true); + const [showWeather, setShowWeather] = useState(false); + const [showLOS, setShowLOS] = useState(false); + const [losPointA, setLosPointA] = useState<[number, number] | null>(null); + const [losPointB, setLosPointB] = useState<[number, number] | null>(null); + const [weatherCity, setWeatherCity] = useState(null); + const [weatherAlerts, setWeatherAlerts] = useState([]); // Geocoding State const [searchQuery, setSearchQuery] = useState(''); const [searchResults, setSearchResults] = useState([]); const [showResults, setShowResults] = useState(false); - const [newPlace, setNewPlace] = useState<{lat: number, lng: number} | null>(null); - const [placeForm, setPlaceForm] = useState({ name: '', name_ar: '', category: '' }); const [currentRegion, setCurrentRegion] = useState('Jordan'); + // Route Form State + const [originText, setOriginText] = useState('31.9539, 35.9106'); + const [destText, setDestText] = useState('32.0608, 36.1032'); + const regions = [ - { name: 'Syria', name_ar: 'سوريا', center: [36.29, 33.51], zoom: 12, flag: '🇸🇾' }, - { name: 'Jordan', name_ar: 'الأردن', center: [35.91, 31.95], zoom: 12, flag: '🇯🇴' }, - { name: 'Egypt', name_ar: 'مصر', center: [31.23, 30.04], zoom: 11, flag: '🇪🇬' }, + { + name: 'Syria', + name_ar: 'سوريا', + center: [36.29, 33.51], + zoom: 11, + flag: '🇸🇾', + defaultOrigin: '33.5138, 36.2765', // Damascus + defaultDest: '36.2021, 37.1343' // Aleppo + }, + { + name: 'Jordan', + name_ar: 'الأردن', + center: [35.91, 31.95], + zoom: 11, + flag: '🇯🇴', + defaultOrigin: '31.9539, 35.9106', // Amman + defaultDest: '32.0608, 36.1032' // Zarqa + }, + { + name: 'Egypt', + name_ar: 'مصر', + center: [31.23, 30.04], + zoom: 10, + flag: '🇪🇬', + defaultOrigin: '30.0444, 31.2357', // Cairo + defaultDest: '31.2001, 29.9187' // Alexandria + }, ]; const handleRegionSwitch = (region: any) => { setCurrentRegion(region.name); + setOriginText(region.defaultOrigin); + setDestText(region.defaultDest); + setRouteData(null); + setWeatherCity(null); + + // Clear existing route line if drawn + if (map && map.getSource('route')) { + map.getSource('route').setData({ + type: 'Feature', + properties: {}, + geometry: { type: 'LineString', coordinates: [] } + }); + } + if (map) { map.flyTo({ center: region.center, zoom: region.zoom, essential: true, - duration: 3000 + duration: 2500 }); } }; - const handleMapClick = (lat: number, lng: number) => { - setNewPlace({ lat, lng }); - }; - const handleSearch = async () => { - if (searchQuery.length < 3) return; + if (searchQuery.trim().length < 2) return; setLoading(true); try { const apiUrl = (import.meta as any).env.VITE_API_URL || '/api'; - - let queryUrl = `${apiUrl}/geocoding/search?q=${searchQuery}&radius=20000`; - + let queryUrl = `${apiUrl}/geocoding/search?q=${encodeURIComponent(searchQuery)}&radius=50000`; + if (map) { const center = map.getCenter(); queryUrl += `&lat=${center.lat}&lng=${center.lng}`; } const response = await fetch(queryUrl, { - headers: { 'x-api-key': 'intaleq_secret_2026' } + headers: { 'x-api-key': DEFAULT_API_KEY } }); const data = await response.json(); - + setSearchResults(data.results || []); setShowResults(true); if (data.results && data.results.length > 0 && map) { const place = data.results[0]; - // API returns flat latitude/longitude fields (not a nested location object) const placeLng = parseFloat(place.longitude); const placeLat = parseFloat(place.latitude); if (!isNaN(placeLat) && !isNaN(placeLng)) { - map.flyTo({ center: [placeLng, placeLat], zoom: 15 }); + map.flyTo({ center: [placeLng, placeLat], zoom: 15, duration: 2000 }); } } } catch (e) { @@ -82,30 +131,6 @@ function App() { } }; - const submitNewPlace = async () => { - if (!newPlace) return; - try { - const apiUrl = (import.meta as any).env.VITE_API_URL || '/api'; - await fetch(`${apiUrl}/geocoding/places`, { - method: 'POST', - headers: { 'Content-Type': 'application/json', 'x-api-key': 'intaleq_secret_2026' }, - body: JSON.stringify({ - latitude: newPlace.lat, - longitude: newPlace.lng, - name: placeForm.name, - name_ar: placeForm.name_ar, - category: placeForm.category, - }) - }); - setNewPlace(null); - setPlaceForm({ name: '', name_ar: '', category: '' }); - alert('Place added successfully! / تم إضافة المكان بنجاح'); - } catch (e) { - console.error(e); - alert('Failed to add place / فشل إضافة المكان'); - } - }; - const fetchStats = async () => { try { const apiUrl = (import.meta as any).env.VITE_API_URL || '/api'; @@ -114,7 +139,7 @@ function App() { const data = await response.json(); setStats(data); } catch (error) { - console.warn("Stats fetch failed, using fallback UI"); + console.warn("Stats fetch failed"); } }; @@ -124,6 +149,25 @@ function App() { return () => clearInterval(interval); }, []); + useEffect(() => { + if (!showWeather) return; + const fetchAlerts = async () => { + try { + const apiUrl = (import.meta as any).env.VITE_API_URL || '/api'; + const regionParam = currentRegion ? `?region=${encodeURIComponent(currentRegion)}` : ''; + const res = await fetch(`${apiUrl}/weather/alerts${regionParam}`, { + headers: { 'x-api-key': DEFAULT_API_KEY } + }); + const data = await res.json(); + setWeatherAlerts(Array.isArray(data) ? data : []); + } catch (e) { + console.warn('Weather alerts fetch failed', e); + setWeatherAlerts([]); + } + }; + fetchAlerts(); + }, [showWeather, currentRegion]); + const handleMapLoad = (initializedMap: any) => { setMap(initializedMap); initializedMap.on('move', () => { @@ -136,49 +180,107 @@ function App() { }); }; + const parseCoordinates = (input: string): [number, number] | null => { + const parts = input.split(',').map(p => parseFloat(p.trim())); + if (parts.length === 2 && !isNaN(parts[0]) && !isNaN(parts[1])) { + return [parts[0], parts[1]]; // [lat, lng] + } + return null; + }; + const calculateRoute = async () => { - setLoading(true); + setRouteError(''); + const originCoords = parseCoordinates(originText); + const destCoords = parseCoordinates(destText); + + if (!originCoords || !destCoords) { + setRouteError('Please enter valid coordinates format: lat, lng'); + return; + } + + setRouteLoading(true); try { - // Points for Amman and Zarqa as defaults - const from = [31.9539, 35.9106]; - const to = [32.0608, 36.1032]; - const apiUrl = (import.meta as any).env.VITE_API_URL || '/api'; - const apiKey = (import.meta as any).env.VITE_API_KEY || 'intaleq_secret_2026'; - - const response = await fetch(`${apiUrl}/maps/route?fromLat=${from[0]}&fromLng=${from[1]}&toLat=${to[0]}&toLng=${to[1]}`, { - headers: { 'x-api-key': apiKey } + const url = `${apiUrl}/maps/route?fromLat=${originCoords[0]}&fromLng=${originCoords[1]}&toLat=${destCoords[0]}&toLng=${destCoords[1]}&profile=car&steps=true`; + + const response = await fetch(url, { + headers: { 'x-api-key': DEFAULT_API_KEY } }); const data = await response.json(); - - if (data.points && map) { + + if (data && data.points) { const coords = typeof data.points === 'string' ? decodePolyline(data.points) : data.points; setRouteData({ ...data, points: coords }); - - if (map.getSource('route')) { + + if (map && map.getSource('route')) { map.getSource('route').setData({ type: 'Feature', properties: {}, geometry: { type: 'LineString', coordinates: coords } }); + + // Fit map to route bounds + if (coords.length > 0) { + let minLng = coords[0][0], maxLng = coords[0][0]; + let minLat = coords[0][1], maxLat = coords[0][1]; + for (const pt of coords) { + minLng = Math.min(minLng, pt[0]); + maxLng = Math.max(maxLng, pt[0]); + minLat = Math.min(minLat, pt[1]); + maxLat = Math.max(maxLat, pt[1]); + } + map.fitBounds([[minLng, minLat], [maxLng, maxLat]], { + padding: { top: 70, bottom: 70, left: 360, right: 70 }, + duration: 2000 + }); + } } + } else { + setRouteError(data.message || 'No route found between selected points.'); } } catch (error) { console.error("Error calculating route:", error); + setRouteError('Failed to calculate route. Please try again.'); } finally { - setLoading(false); + setRouteLoading(false); } }; + const handleMapClick = (lat: number, lng: number) => { + if (showLOS) { + if (!losPointA) { + setLosPointA([lat, lng]); + } else if (!losPointB) { + setLosPointB([lat, lng]); + } else { + // Reset and set point A + setLosPointA([lat, lng]); + setLosPointB(null); + } + } + }; + + const handleClearLOS = () => { + setLosPointA(null); + setLosPointB(null); + }; + + const handleCloseLOS = () => { + setShowLOS(false); + setLosPointA(null); + setLosPointB(null); + }; + return (

{currentRegion} Maps SaaS

-

Self-Hosted Mobility Prototype

- +

Intaleq Mobility & Maps Cloud

+ + {/* Region Selector */}
{regions.map(r => ( -
+ {/* Search Bar */}
- +
- setSearchQuery(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleSearch()} /> - + setSearchQuery(e.target.value)} + onKeyDown={e => e.key === 'Enter' && handleSearch()} + /> +
- + {showResults && searchResults.length > 0 && ( -
+
{searchResults.map((res) => ( -
{ const rLng = parseFloat(res.longitude); const rLat = parseFloat(res.latitude); if (!isNaN(rLat) && !isNaN(rLng)) map?.flyTo({ center: [rLng, rLat], zoom: 16 }); }} - style={{ padding: '8px', borderBottom: '1px solid var(--glass-border)', cursor: 'pointer', fontSize: '0.85rem' }} +
{ + const rLng = parseFloat(res.longitude); + const rLat = parseFloat(res.latitude); + if (!isNaN(rLat) && !isNaN(rLng)) { + map?.flyTo({ center: [rLng, rLat], zoom: 16, duration: 1500 }); + } + }} + style={{ padding: '10px', borderBottom: '1px solid var(--glass-border)', cursor: 'pointer', fontSize: '0.85rem' }} className="search-result-item" > -
{res.name_ar || res.name}
- {res.address &&
{res.address}
} -
+
{res.name_ar || res.name}
+ {res.address &&
{res.address}
} +
{res.distance ? (Number(res.distance) / 1000).toFixed(1) + ' km away' : ''} | {(res.source || '').replace('_', ' ')}
))} -
)} {showResults && searchResults.length === 0 && ( -
No results found near you.
+
No results found / لم يتم العثور على نتائج.
)}
+ {/* Route Calculation */}
- + setOriginText(e.target.value)} + />
- + setDestText(e.target.value)} + />
- -
+ {routeError && ( +
+ {routeError} +
+ )} + {/* Route Summary Card */} + {routeData && ( +
+

Route Overview / تفاصيل المسار

+
+ + + {(Number(routeData.distance || 0) / 1000).toFixed(1)} km + + + + {Math.round(Number(routeData.time || routeData.duration || 0) / 60000)} min + +
+
+ )} + +
+ + {/* Layers & Map Options */}

Layers & Map Options / خيارات الخريطة

- +
+
+ +
+ + {/* Tactical Line of Sight (LOS) Toggle */} +
+ + + Military + +
+

Simulation / المحاكاة

@@ -309,38 +505,30 @@ function App() {
- setWeatherCity(cityData)} + losActive={showLOS} + losPointA={losPointA} + losPointB={losPointB} /> - {/* Add Place Modal */} - {newPlace && ( -
-

Add New Place / إضافة مكان

-
- - setPlaceForm({...placeForm, name: e.target.value})} /> -
-
- - setPlaceForm({...placeForm, name_ar: e.target.value})} /> -
-
- - setPlaceForm({...placeForm, category: e.target.value})} /> -
-
- - -
-
- )} + {/* Tactical Line of Sight Tool Overlay */} + {stats && stats.telemetry && (
@@ -363,7 +551,13 @@ function App() {
)} - + + +
Zoom: {debug.zoom}
Center: {debug.center[0]}, {debug.center[1]}
diff --git a/apps/web/src/components/LineOfSightTool.tsx b/apps/web/src/components/LineOfSightTool.tsx new file mode 100644 index 0000000..6ded2b3 --- /dev/null +++ b/apps/web/src/components/LineOfSightTool.tsx @@ -0,0 +1,597 @@ +import React, { useState, useEffect } from 'react'; +import { Eye, Crosshair, AlertTriangle, CheckCircle2, XCircle, Mountain, Compass, Shield, ChevronDown, ChevronUp, Layers } from 'lucide-react'; +import { LineOfSightResult, calculateLineOfSight } from '../utils/elevationService'; + +interface LineOfSightToolProps { + active: boolean; + pointA: [number, number] | null; // [lat, lng] Observer + pointB: [number, number] | null; // [lat, lng] Target + onClose: () => void; + onClear: () => void; +} + +export const LineOfSightTool: React.FC = ({ + active, + pointA, + pointB, + onClose, + onClear +}) => { + const [obsHeight, setObsHeight] = useState(2); // 2m eye level + const [tgtHeight, setTgtHeight] = useState(2); // 2m target level + const [loading, setLoading] = useState(false); + const [result, setResult] = useState(null); + const [hoverPoint, setHoverPoint] = useState(null); + const [minimized, setMinimized] = useState(false); + + useEffect(() => { + if (pointA && pointB) { + setLoading(true); + calculateLineOfSight(pointA[0], pointA[1], pointB[0], pointB[1], obsHeight, tgtHeight, 80) + .then((res) => { + setResult(res); + setLoading(false); + }) + .catch((err) => { + console.error('LOS Error:', err); + setLoading(false); + }); + } else { + setResult(null); + } + }, [pointA, pointB, obsHeight, tgtHeight]); + + if (!active) return null; + + // Instructions overlay if points are not selected yet + if (!pointA || !pointB) { + return ( +
+
+ {pointA ? : } +
+
+
+ أداة تبادل الرؤية وخط النظر التكتيكي (Line of Sight) + مباشر +
+
+ {!pointA + ? '📍 اضغط على الخريطة لتحديد موقع الراصد / الرامي (النقطة A)' + : `🎯 تم تحديد الراصد (${pointA[0].toFixed(4)}, ${pointA[1].toFixed(4)}) — اضغط الآن لتحديد موقع الهدف (النقطة B)`} +
+
+ {pointA && ( + + )} + +
+ ); + } + + // Render SVG Chart for Elevation Profile + const renderProfileChart = () => { + if (!result || result.points.length === 0) return null; + + const svgWidth = 620; + const svgHeight = 190; + const padding = { top: 20, right: 35, bottom: 30, left: 45 }; + const chartWidth = svgWidth - padding.left - padding.right; + const chartHeight = svgHeight - padding.top - padding.bottom; + + const maxDist = result.totalDistance; + // Dynamic elevation range with margin + const minElev = Math.floor(Math.min(result.minElevation, result.observerElevation, result.targetElevation) / 50) * 50 - 50; + const maxElev = Math.ceil(Math.max(result.maxElevation, result.observerElevation, result.targetElevation) / 50) * 50 + 50; + const elevRange = Math.max(100, maxElev - minElev); + + const getX = (d: number) => padding.left + (d / maxDist) * chartWidth; + const getY = (h: number) => padding.top + chartHeight - ((h - minElev) / elevRange) * chartHeight; + + // Build Terrain Polygon Path + const terrainPoints = result.points.map((p) => `${getX(p.distance)},${getY(p.elevation)}`).join(' '); + const terrainAreaPath = `M ${getX(0)},${padding.top + chartHeight} L ${terrainPoints} L ${getX(maxDist)},${padding.top + chartHeight} Z`; + const terrainLinePath = `M ${terrainPoints}`; + + // Line of Sight Ray Path + const obsX = getX(0); + const obsY = getY(result.observerElevation); + const tgtX = getX(maxDist); + const tgtY = getY(result.targetElevation); + + return ( +
+ setHoverPoint(null)} + > + + {/* Terrain Gradient */} + + + + + + {/* Obstructed Ray Pattern */} + + + + + + + {/* Grid Lines */} + {[0, 0.25, 0.5, 0.75, 1].map((ratio) => { + const hVal = minElev + ratio * elevRange; + const y = getY(hVal); + return ( + + + + {Math.round(hVal)}m + + + ); + })} + + {/* Distance Axis */} + {[0, 0.25, 0.5, 0.75, 1].map((ratio) => { + const dVal = ratio * maxDist; + const x = getX(dVal); + return ( + + + + {(dVal / 1000).toFixed(1)}km + + + ); + })} + + {/* Terrain Area & Line */} + + + + {/* Line of Sight Ray */} + + + {/* Dead Ground Regions (Highlighted on terrain) */} + {result.points.map((p, i) => { + if (!p.isVisible && i > 0) { + const x = getX(p.distance); + const y = getY(p.elevation); + return ( + + ); + } + return null; + })} + + {/* Observer Marker */} + + + الراصد (A) + + + {/* Target Marker */} + + + الهدف (B) + + + {/* Critical Obstacle Marker (if blocked) */} + {result.highestObstacle && ( + + + + + عائق الحجب (+{result.highestObstacle.excessHeight}m) + + + )} + + {/* Interactive Hover Overlay Rect */} + {result.points.map((p, idx) => { + const x = getX(p.distance); + return ( + setHoverPoint(p)} + /> + ); + })} + + {/* Active Hover Point Marker */} + {hoverPoint && ( + + + + + )} + + + {/* Hover Info Tooltip */} + {hoverPoint && ( +
+ المسافة: {(hoverPoint.distance / 1000).toFixed(2)} كم + الارتفاع: {hoverPoint.elevation} م + شعاع الرؤية: {hoverPoint.rayHeight} م + الحالة: + {hoverPoint.isVisible ? 'مكشوف' : 'أرض ميتة'} + +
+ )} +
+ ); + }; + + return ( +
+ {/* Header Bar */} +
+
+
+ {result?.isDirectlyVisible ? : } +
+
+
+ تبادل الرؤية والمقطع التضاريسي (Line of Sight) + {result && ( + + {result.isDirectlyVisible ? '✓ رؤية مباشرة مكشوفة' : '✕ الرؤية محجوبة بعائق'} + + )} +
+
+ تحليل خط النظر التكتيكي مع تصحيح انكسار الضوء الجوي وتقوس الأرض +
+
+
+ +
+ + + +
+
+ + {/* Main Content Area */} + {!minimized && ( +
+ {loading ? ( +
+ جاري حساب المقطع التضاريسي وشعاع الرؤية... ⏳ +
+ ) : result ? ( + <> + {/* Tactical Metrics Grid */} +
+
+
+ المسافة المباشرة +
+
+ {(result.totalDistance / 1000).toFixed(2)} كم +
+
+ +
+
+ السمت / الاتجاه +
+
+ {result.azimuthDegrees}° بوصلة +
+
+ +
+
+ زاوية الموقع (رماية) +
+
+ {result.angleMils > 0 ? `+${result.angleMils}` : result.angleMils} Mils ({result.angleDegrees}°) +
+
+ +
+
+ الراصد / الهدف +
+
+ {result.observerElevation}m ➔ {result.targetElevation}m +
+
+ +
+
+ الأرض الميتة +
+
30 ? '#f87171' : '#f8fafc', marginTop: 2 }}> + {result.deadGroundPercentage}% محجوبة +
+
+
+ + {/* Critical Obstacle Alert */} + {result.highestObstacle && ( +
+ +
+ عائق الحجب الرئيسي: قمة جبلية/تضاريس على بعد {(result.highestObstacle.distance / 1000).toFixed(2)} كم بارتفاع {result.highestObstacle.elevation} م، تخترق خط الرؤية بمقدار +{result.highestObstacle.excessHeight} م. +
+
+ )} + + {/* Elevation Profile Chart */} +
+ {renderProfileChart()} +
+ + {/* Observer / Target Height Adjusters */} +
+
+ ارتفاع الراصد (A): + {[ + { label: 'شخص (2م)', val: 2 }, + { label: 'آلية/برج (10م)', val: 10 }, + { label: 'سارية/درون (50م)', val: 50 }, + ].map((btn) => ( + + ))} +
+ +
+ ارتفاع الهدف (B): + {[ + { label: 'شخص (1.8م)', val: 1.8 }, + { label: 'مركبة (3م)', val: 3 }, + { label: 'مبنى/رادار (15م)', val: 15 }, + ].map((btn) => ( + + ))} +
+
+ + ) : null} +
+ )} +
+ ); +}; diff --git a/apps/web/src/components/MapComponent.tsx b/apps/web/src/components/MapComponent.tsx index f13d4fe..3dfea2e 100644 --- a/apps/web/src/components/MapComponent.tsx +++ b/apps/web/src/components/MapComponent.tsx @@ -4,6 +4,22 @@ import 'maplibre-gl/dist/maplibre-gl.css'; import mlcontour from 'maplibre-contour'; import { attachIconLoader } from '../utils/mapIcons'; +interface MapProps { + onMapLoad: (map: maplibregl.Map) => void; + onMapClick?: (lat: number, lng: number) => void; + show3D?: boolean; + showPOIs?: boolean; + showTerrain?: boolean; + showContours?: boolean; + showAdminBoundaries?: boolean; + showWeather?: boolean; + currentRegion?: string; + onCityClick?: (city: any) => void; + losActive?: boolean; + losPointA?: [number, number] | null; + losPointB?: [number, number] | null; +} + const demSource = new mlcontour.DemSource({ url: 'https://s3.amazonaws.com/elevation-tiles-prod/terrarium/{z}/{x}/{y}.png', encoding: 'terrarium', @@ -12,45 +28,136 @@ const demSource = new mlcontour.DemSource({ }); demSource.setupMaplibre(maplibregl); -interface MapComponentProps { - onMapLoad: (map: maplibregl.Map) => void; - onMapClick?: (lat: number, lng: number) => void; - show3D?: boolean; - showPOIs?: boolean; - showTerrain?: boolean; - showContours?: boolean; - showAdminBoundaries?: boolean; -} - -const MapComponent: React.FC = ({ +const MapComponent: React.FC = ({ onMapLoad, onMapClick, show3D = false, showPOIs = true, - showTerrain = true, + showTerrain = false, showContours = false, - showAdminBoundaries = true + showAdminBoundaries = false, + showWeather = false, + currentRegion = 'Jordan', + onCityClick, + losActive = false, + losPointA = null, + losPointB = null, }) => { const mapContainer = useRef(null); const map = useRef(null); - // Sync toggles with map layers + // Synchronize Line of Sight (LOS) Tactical Layer + useEffect(() => { + if (!map.current || !map.current.isStyleLoaded()) return; + + const features: any[] = []; + if (losActive) { + if (losPointA) { + features.push({ + type: 'Feature', + properties: { role: 'obs', label: 'A (الراصد)' }, + geometry: { type: 'Point', coordinates: [losPointA[1], losPointA[0]] } + }); + } + if (losPointB) { + features.push({ + type: 'Feature', + properties: { role: 'tgt', label: 'B (الهدف)' }, + geometry: { type: 'Point', coordinates: [losPointB[1], losPointB[0]] } + }); + } + if (losPointA && losPointB) { + features.push({ + type: 'Feature', + properties: { role: 'ray' }, + geometry: { + type: 'LineString', + coordinates: [ + [losPointA[1], losPointA[0]], + [losPointB[1], losPointB[0]] + ] + } + }); + } + } + + const losGeoJson = { type: 'FeatureCollection', features }; + + if (!map.current.getSource('los-source')) { + map.current.addSource('los-source', { + type: 'geojson', + data: losGeoJson as any + }); + + map.current.addLayer({ + id: 'los-line', + type: 'line', + source: 'los-source', + filter: ['==', '$type', 'LineString'], + layout: { 'line-cap': 'round', 'line-join': 'round' }, + paint: { + 'line-color': '#f59e0b', + 'line-width': 3.5, + 'line-dasharray': [2, 2] + } + }); + + map.current.addLayer({ + id: 'los-points', + type: 'circle', + source: 'los-source', + filter: ['==', '$type', 'Point'], + paint: { + 'circle-radius': 8, + 'circle-color': [ + 'match', + ['get', 'role'], + 'obs', '#3b82f6', + 'tgt', '#ef4444', + '#ffffff' + ], + 'circle-stroke-color': '#ffffff', + 'circle-stroke-width': 2.5 + } + }); + + map.current.addLayer({ + id: 'los-labels', + type: 'symbol', + source: 'los-source', + filter: ['==', '$type', 'Point'], + layout: { + 'text-field': ['get', 'label'], + 'text-size': 12, + 'text-font': ['Noto Sans Bold', 'Open Sans Bold'], + 'text-offset': [0, -1.6], + 'text-anchor': 'bottom' + }, + paint: { + 'text-color': '#ffffff', + 'text-halo-color': '#0f172a', + 'text-halo-width': 2 + } + }); + } else { + (map.current.getSource('los-source') as maplibregl.GeoJSONSource).setData(losGeoJson as any); + map.current.setLayoutProperty('los-line', 'visibility', losActive ? 'visible' : 'none'); + map.current.setLayoutProperty('los-points', 'visibility', losActive ? 'visible' : 'none'); + map.current.setLayoutProperty('los-labels', 'visibility', losActive ? 'visible' : 'none'); + } + }, [losActive, losPointA, losPointB]); + + // Synchronize layers visibility useEffect(() => { if (!map.current || !map.current.isStyleLoaded()) return; // Toggle 3D Buildings - ['building-3d', 'building-3d-osm'].forEach(layerId => { - if (map.current!.getLayer(layerId)) { - map.current!.setLayoutProperty(layerId, 'visibility', show3D ? 'visible' : 'none'); - } - }); - if (map.current.getLayer('overture-building-footprint')) { - map.current.setLayoutProperty('overture-building-footprint', 'visibility', show3D ? 'none' : 'visible'); + if (map.current.getLayer('3d-buildings')) { + map.current.setLayoutProperty('3d-buildings', 'visibility', show3D ? 'visible' : 'none'); } - map.current.easeTo({ pitch: show3D ? 55 : 0, duration: 600 }); - // Toggle POI Layers - const poiLayers = ['poi-icons', 'place-labels', 'overture-building-names', 'places-jordan-labels']; + // Toggle POIs + const poiLayers = ['poi-level-1', 'poi-level-2', 'poi-level-3', 'poi-labels']; poiLayers.forEach(layerId => { if (map.current!.getLayer(layerId)) { map.current!.setLayoutProperty(layerId, 'visibility', showPOIs ? 'visible' : 'none'); @@ -83,7 +190,192 @@ const MapComponent: React.FC = ({ map.current!.setLayoutProperty(layerId, 'visibility', showAdminBoundaries ? 'visible' : 'none'); } }); - }, [show3D, showPOIs, showTerrain, showContours, showAdminBoundaries]); + + const weatherLayers = ['weather-city-circles', 'weather-city-icons', 'weather-wind-arrows', 'weather-wind-speed']; + weatherLayers.forEach(layerId => { + if (map.current!.getLayer(layerId)) { + map.current!.setLayoutProperty(layerId, 'visibility', showWeather ? 'visible' : 'none'); + } + }); + }, [show3D, showPOIs, showTerrain, showContours, showAdminBoundaries, showWeather]); + + // Weather data fetching and vector rendering + useEffect(() => { + if (!map.current || !map.current.isStyleLoaded()) return; + + if (showWeather) { + const fetchWeather = async () => { + try { + const apiUrl = (import.meta as any).env.VITE_API_URL || '/api'; + const apiKey = (import.meta as any).env.VITE_API_KEY || 'zP9vL5mK2nQ8xR7jT4wS1yB6hG3fV0cX'; + + const regionParam = currentRegion ? `?region=${encodeURIComponent(currentRegion)}` : ''; + const citiesRes = await fetch(`${apiUrl}/weather/cities${regionParam}`, { + headers: { 'x-api-key': apiKey } + }); + const rawCitiesData = await citiesRes.json(); + + // Convert cities array to GeoJSON FeatureCollection + const citiesGeoJson = { + type: 'FeatureCollection', + features: (Array.isArray(rawCitiesData) ? rawCitiesData : []).map((city: any) => ({ + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [city.lng, city.lat] + }, + properties: { + name: city.name, + name_ar: city.name_ar, + temperature: Number(city.current?.temp ?? 20), + feelsLike: Number(city.current?.feelsLike ?? 20), + humidity: Number(city.current?.humidity ?? 50), + weatherCode: Number(city.current?.weatherCode ?? 0), + windSpeed: Number(city.current?.windSpeed ?? 10), + windDirection: Number(city.current?.windDirection ?? 0), + cloudCover: Number(city.current?.cloudCover ?? 0), + precipitation: Number(city.current?.precipitation ?? 0), + isDay: Number(city.current?.isDay ?? 1), + forecast: JSON.stringify(city.daily || []) + } + })) + }; + + if (!map.current!.getSource('weather-cities-source')) { + map.current!.addSource('weather-cities-source', { type: 'geojson', data: citiesGeoJson as any }); + + // 1. Soft temperature indicator circle badge + map.current!.addLayer({ + id: 'weather-city-circles', + type: 'circle', + source: 'weather-cities-source', + paint: { + 'circle-radius': 24, + 'circle-color': [ + 'step', ['to-number', ['get', 'temperature'], 20], + '#3b82f6', 15, + '#10b981', 25, + '#f59e0b', 35, + '#ef4444' + ], + 'circle-opacity': 0.9, + 'circle-stroke-width': 2.5, + 'circle-stroke-color': '#ffffff' + } + }); + + // 2. City name and temperature text badge + map.current!.addLayer({ + id: 'weather-city-icons', + type: 'symbol', + source: 'weather-cities-source', + layout: { + 'text-field': ['concat', ['coalesce', ['get', 'name_ar'], ''], '\n', ['to-string', ['round', ['to-number', ['get', 'temperature'], 20]]], '°C'], + 'text-size': 11, + 'text-font': ['Noto Sans Bold', 'Open Sans Bold'], + 'text-justify': 'center', + 'text-anchor': 'center' + }, + paint: { + 'text-color': '#ffffff', + 'text-halo-color': 'rgba(0, 0, 0, 0.6)', + 'text-halo-width': 1.5 + } + }); + + // 3. Wind indicator arrow (rotated by wind direction angle) + map.current!.addLayer({ + id: 'weather-wind-arrows', + type: 'symbol', + source: 'weather-cities-source', + minzoom: 4, + layout: { + 'text-field': '➤', + 'text-rotation-alignment': 'map', + 'text-rotate': ['to-number', ['get', 'windDirection'], 0], + 'text-size': 14, + 'text-offset': [2.2, 0], + 'text-allow-overlap': true + }, + paint: { + 'text-color': '#38bdf8', + 'text-halo-color': '#0f172a', + 'text-halo-width': 2 + } + }); + + // 4. Wind speed badge (e.g. 15 km/h) + map.current!.addLayer({ + id: 'weather-wind-speed', + type: 'symbol', + source: 'weather-cities-source', + minzoom: 4, + layout: { + 'text-field': ['concat', ['to-string', ['round', ['to-number', ['get', 'windSpeed'], 10]]], ' km/h'], + 'text-size': 9, + 'text-font': ['Noto Sans Regular', 'Open Sans Regular'], + 'text-offset': [0, 2.6], + 'text-anchor': 'top', + 'text-allow-overlap': false + }, + paint: { + 'text-color': '#bae6fd', + 'text-halo-color': 'rgba(15, 23, 42, 0.85)', + 'text-halo-width': 2 + } + }); + + const handleCityClick = (e: any) => { + if (e.originalEvent) { + e.originalEvent.stopPropagation(); + } + if (onCityClick && e.features && e.features.length > 0) { + onCityClick(e.features[0].properties); + } + }; + + map.current!.on('click', 'weather-city-circles', handleCityClick); + map.current!.on('click', 'weather-city-icons', handleCityClick); + + map.current!.on('mouseenter', 'weather-city-circles', () => { + if (map.current) map.current.getCanvas().style.cursor = 'pointer'; + }); + map.current!.on('mouseleave', 'weather-city-circles', () => { + if (map.current) map.current.getCanvas().style.cursor = ''; + }); + } else { + (map.current!.getSource('weather-cities-source') as maplibregl.GeoJSONSource).setData(citiesGeoJson as any); + map.current!.setLayoutProperty('weather-city-circles', 'visibility', 'visible'); + map.current!.setLayoutProperty('weather-city-icons', 'visibility', 'visible'); + map.current!.setLayoutProperty('weather-wind-arrows', 'visibility', 'visible'); + map.current!.setLayoutProperty('weather-wind-speed', 'visibility', 'visible'); + } + } catch (e) { + console.warn('Weather fetch failed', e); + } + }; + fetchWeather(); + } else { + const weatherLayers = ['weather-city-circles', 'weather-city-icons', 'weather-wind-arrows', 'weather-wind-speed']; + weatherLayers.forEach(layerId => { + if (map.current && map.current.getLayer(layerId)) { + map.current.setLayoutProperty(layerId, 'visibility', 'none'); + } + }); + } + }, [showWeather, currentRegion, onCityClick]); + + const onMapClickRef = useRef(onMapClick); + useEffect(() => { + onMapClickRef.current = onMapClick; + }, [onMapClick]); + + // Update canvas cursor when LOS is active + useEffect(() => { + if (map.current) { + map.current.getCanvas().style.cursor = losActive ? 'crosshair' : ''; + } + }, [losActive]); useEffect(() => { if (map.current) return; @@ -129,6 +421,53 @@ const MapComponent: React.FC = ({ initialMap.on('load', () => { console.log("MapComponent: Map Loaded Successfully"); + // Initialize Route Source and Layers + if (!initialMap.getSource('route')) { + initialMap.addSource('route', { + type: 'geojson', + data: { + type: 'Feature', + properties: {}, + geometry: { + type: 'LineString', + coordinates: [] + } + } + }); + + // Route outer shadow/glow + initialMap.addLayer({ + id: 'route-casing', + type: 'line', + source: 'route', + layout: { + 'line-join': 'round', + 'line-cap': 'round' + }, + paint: { + 'line-color': '#0369a1', + 'line-width': 9, + 'line-opacity': 0.8 + } + }); + + // Route inner bright line + initialMap.addLayer({ + id: 'route-line', + type: 'line', + source: 'route', + layout: { + 'line-join': 'round', + 'line-cap': 'round' + }, + paint: { + 'line-color': '#38bdf8', + 'line-width': 5, + 'line-opacity': 1.0 + } + }); + } + const contourUrl = demSource.contourProtocolUrl({ thresholds: { 10: [100, 500], @@ -211,13 +550,13 @@ const MapComponent: React.FC = ({ onMapLoad(map.current!); }); - map.current.on('click', (e) => { - if (onMapClick) { - onMapClick(e.lngLat.lat, e.lngLat.lng); + initialMap.on('click', (e) => { + if (onMapClickRef.current) { + onMapClickRef.current(e.lngLat.lat, e.lngLat.lng); } }); - map.current.on('error', (e) => { + initialMap.on('error', (e) => { console.error("MapComponent: Map Error:", e); }); diff --git a/apps/web/src/components/WeatherPanel.tsx b/apps/web/src/components/WeatherPanel.tsx new file mode 100644 index 0000000..861784d --- /dev/null +++ b/apps/web/src/components/WeatherPanel.tsx @@ -0,0 +1,195 @@ +import React, { useState } from 'react'; +import { getWeatherDescription, getTemperatureColor } from '../utils/weatherIcons'; + +interface WeatherPanelProps { + visible: boolean; + selectedCity?: any; + alerts?: any[]; +} + +const WeatherPanel: React.FC = ({ visible, selectedCity, alerts }) => { + const [minimized, setMinimized] = useState(false); + + if (!visible) return null; + + const panelStyle: React.CSSProperties = { + position: 'absolute', + bottom: '24px', + right: '24px', + width: '340px', + maxHeight: '440px', + overflowY: 'auto', + backgroundColor: 'rgba(15, 23, 42, 0.9)', + backdropFilter: 'blur(16px)', + WebkitBackdropFilter: 'blur(16px)', + border: '1px solid rgba(255, 255, 255, 0.12)', + borderRadius: '16px', + padding: '16px', + boxShadow: '0 12px 36px rgba(0, 0, 0, 0.5)', + zIndex: 1000, + direction: 'rtl', + fontFamily: 'Inter, system-ui, sans-serif', + color: '#f8fafc' + }; + + if (minimized) { + return ( +
setMinimized(false)} + > + 🌤️ الطقس (Weather) +
+ ); + } + + const renderCurrentWeather = () => { + if (!selectedCity) return null; + + const code = Number(selectedCity.weatherCode ?? selectedCity.weather_code ?? 0); + const temp = Number(selectedCity.temperature ?? 0); + const desc = getWeatherDescription(code); + + return ( +
+
+

{selectedCity.name_ar || selectedCity.name || 'المدينة'}

+ {desc.icon} +
+
+ + {Math.round(temp)}°C + + {desc.description_ar} +
+
+
💧 الرطوبة: {selectedCity.humidity || 0}%
+
💨 الرياح: {selectedCity.windSpeed || 0} كم/س
+
☁️ الغطاء: {selectedCity.cloudCover || 0}%
+
🌡️ الشعور: {Math.round(Number(selectedCity.feelsLike ?? temp))}°C
+
+
+ ); + }; + + const renderForecast = () => { + if (!selectedCity || !selectedCity.forecast) return null; + + let forecastArray: any[] = []; + try { + forecastArray = typeof selectedCity.forecast === 'string' ? JSON.parse(selectedCity.forecast) : selectedCity.forecast; + } catch(e) { + forecastArray = []; + } + + if (!Array.isArray(forecastArray) || forecastArray.length === 0) return null; + + const days = ['الأحد', 'الإثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت']; + + return ( +
+

📅 توقعات 7 أيام

+
+ {forecastArray.map((f: any, idx: number) => { + const code = Number(f.weatherCode ?? f.weather_code ?? 0); + const desc = getWeatherDescription(code); + const dateObj = f.date ? new Date(f.date) : null; + const dayName = dateObj ? days[dateObj.getDay()] : `يوم ${idx + 1}`; + const maxTemp = Math.round(Number(f.tempMax ?? f.max_temp ?? 0)); + const minTemp = Math.round(Number(f.tempMin ?? f.min_temp ?? 0)); + + return ( +
+
{dayName}
+
{desc.icon}
+
+ {maxTemp}° + {' '} + {minTemp}° +
+
+ ); + })} +
+
+ ); + }; + + const renderAlerts = () => { + if (!alerts || alerts.length === 0) return null; + + return ( +
+

⚠️ تنبيهات الطقس

+
+ {alerts.map((alert, idx) => { + const severity = alert.severity || alert.level || 'info'; + const colors: Record = { + danger: '#ef4444', + warning: '#f59e0b', + info: '#3b82f6' + }; + const color = colors[severity] || colors.info; + return ( +
+
+ 📍 {alert.city_ar || alert.city || alert.city_name_ar || alert.city_name}: {alert.type || 'تنبيه'} +
+
{alert.message_ar || alert.message}
+
+ ); + })} +
+
+ ); + }; + + return ( +
+
+

+ 🌤️ حالة الطقس المباشرة +

+ +
+ + {!selectedCity && ( +
+ 💡 اضغط على أي مدينة على الخريطة لعرض تفاصيلها وتوقعات 7 أيام +
+ )} + + {renderCurrentWeather()} + {renderForecast()} + {renderAlerts()} +
+ ); +}; + +export default WeatherPanel; + diff --git a/apps/web/src/index.css b/apps/web/src/index.css index 58510fb..170438b 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -32,15 +32,37 @@ body { .sidebar { width: 350px; height: 100%; - padding: 30px; + max-height: 100vh; + padding: 24px 20px; z-index: 10; display: flex; flex-direction: column; - gap: 20px; + gap: 16px; box-shadow: 10px 0 30px rgba(0,0,0,0.5); background: var(--glass-bg); backdrop-filter: blur(15px); border-right: 1px solid var(--glass-border); + overflow-y: auto; + overflow-x: hidden; + scrollbar-width: thin; + scrollbar-color: rgba(255, 255, 255, 0.2) transparent; +} + +.sidebar::-webkit-scrollbar { + width: 6px; +} + +.sidebar::-webkit-scrollbar-track { + background: transparent; +} + +.sidebar::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.2); + border-radius: 4px; +} + +.sidebar::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.35); } .glass-morphism { diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx index 8d66148..47ce763 100644 --- a/apps/web/src/main.tsx +++ b/apps/web/src/main.tsx @@ -4,6 +4,7 @@ import maplibregl from 'maplibre-gl' import App from './App.tsx' import CompareView from './pages/CompareView' import IntelligenceDashboard from './pages/IntelligenceDashboard' +import { ExecutiveShowcase } from './pages/ExecutiveShowcase' import './index.css' maplibregl.setRTLTextPlugin( @@ -12,49 +13,53 @@ maplibregl.setRTLTextPlugin( true ); -// Lightweight hash router (no dependency). '#compare' and '#review' are additive -// views; anything else falls back to the existing map app, untouched. +// Lightweight hash router const NAV = [ - { hash: '#map', label: 'Map', icon: '🗺️' }, - { hash: '#review', label: 'Review', icon: '🔍' }, - { hash: '#compare', label: 'Compare', icon: '⚖️' }, + { hash: '#executive', label: 'العرض الاستراتيجي', icon: '🎖️' }, + { hash: '#map', label: 'الخريطة الحية', icon: '🗺️' }, + { hash: '#review', label: 'تدقيق الطرق', icon: '🔍' }, + { hash: '#compare', label: 'المقارنة', icon: '⚖️' }, ] function ViewNav({ hash }: { hash: string }) { - const isMap = hash !== '#compare' && hash !== '#review' + const currentHash = hash || '#map' return (
{NAV.map(n => { - const active = n.hash === '#map' ? isMap : hash === n.hash + const active = currentHash === n.hash return ( {n.icon} @@ -67,13 +72,19 @@ function ViewNav({ hash }: { hash: string }) { } function Root() { - const [hash, setHash] = useState(window.location.hash) + const [hash, setHash] = useState(window.location.hash || '#map') useEffect(() => { - const on = () => setHash(window.location.hash) + const on = () => setHash(window.location.hash || '#map') window.addEventListener('hashchange', on) return () => window.removeEventListener('hashchange', on) }, []) - const view = hash === '#compare' ? : hash === '#review' ? : + + const view = + hash === '#executive' || hash === '#pitch' ? : + hash === '#compare' ? : + hash === '#review' ? : + + return ( <> diff --git a/apps/web/src/pages/ExecutiveShowcase.tsx b/apps/web/src/pages/ExecutiveShowcase.tsx new file mode 100644 index 0000000..e1aa5f1 --- /dev/null +++ b/apps/web/src/pages/ExecutiveShowcase.tsx @@ -0,0 +1,611 @@ +import React, { useState } from 'react'; +import { + Shield, + Compass, + Map as MapIcon, + Activity, + CheckCircle2, + XCircle, + Layers, + Eye, + Crosshair, + Mountain, + Cpu, + Zap, + Globe, + Server, + ArrowRight, + Check, + ChevronRight, + Radio, + Gauge, + TrendingUp, + FileText, + Flame, + Award +} from 'lucide-react'; + +export const ExecutiveShowcase: React.FC = () => { + const [activeTab, setActiveTab] = useState<'strategy' | 'tactical' | 'comparison' | 'roadmap'>('strategy'); + + return ( +
+ {/* Top Military & National Header */} +
+ +
+ + {/* Main Container */} +
+ + {/* Hero Section */} +
+
+ البديل السيادي الكامل لمنظومات إزري (ArcGIS) في الأردن +
+ +

+ منصة خرائط وطنية ذكية تتغذى ذاتياً وتولد الشوارع والبيانات المكانية من حركة الأساطيل +

+ +

+ استثمار استراتيجي مزدوج: تطبيق نقل وخدمات لوجستية ذكي في الواجهة، ومحرك خرائط تكتيكي سيادي في الخلفية، يكتشف الطرق والمعالم تلقائياً في أي دولة أو مسرح عمليات بدون الحاجة لرخص أجنبية أو مسح ميداني بطيء. +

+ + {/* Quick Metrics Bar */} +
+
+
60 FPS
+
سرعة عرض المتجهات (Martin MVT)
+
+
+
100%
+
استقلالية تامة (Air-Gapped On-Premise)
+
+
+
$0
+
تكلفة رخص سنوية أو رسوم لكل مستخدم
+
+
+
3 دول
+
الأردن 🇯🇴 • سوريا 🇸🇾 • مصر 🇪🇬
+
+
+
+ + {/* Tab Navigation */} +
+ {[ + { id: 'strategy', label: '1. الرؤية وحجر الأساس (توليد الخرائط)', icon: }, + { id: 'tactical', label: '2. الأدوات التكتيكية والعسكرية (LOS)', icon: }, + { id: 'comparison', label: '3. المقارنة القاطعة مع إزري (Esri)', icon: }, + { id: 'roadmap', label: '4. خطة الشراكة مع المركز الجغرافي', icon: }, + ].map((tab) => ( + + ))} +
+ + {/* TAB 1: STRATEGY & SELF-HEALING MAPS */} + {activeTab === 'strategy' && ( +
+
+

+ حجر الأساس: كيف تحول حركة الأساطيل إلى خريطة سيادية حية؟ +

+

+ النموذج التقليدي المتبع لدى إزري والشركات الأجنبية يعتمد على انتظار فرق المسح الميداني أو التقاط صور أقمار صناعية باهظة كل عدة أشهر أو سنوات. في المقابل، تتبنى منصتنا فلسفة الخريطة الحية ذاتية التغذية والتوليد (Autonomous Self-Healing Map Grid): +

+ +
+
+
+ +
+

1. استيعاب التتبع اللحظي (Telemetry)

+

+ المنصة تستوعب مئات آلاف نقاط الموقع من الآليات العسكرية أو أساطيل التوصيل والنقل كل 3 ثوانٍ وتعالجها مكانياً في محرك PostGIS فائق الأداء. +

+
+ +
+
+ +
+

2. خوارزمية اكتشاف الطرق الجديدة

+

+ عندما تتحرك مركبات متعددة في مسار صحراوي أو حي جديد غير مرسوم على الخريطة، يقوم النظام بتوليد طريق مرشح (Candidate Road) وحساب طوله، سرعته، ومعدل الثقة به تلقائياً. +

+
+ +
+
+ +
+

3. التدقيق والموافقة ونشر الملاحة فوراً

+

+ يستعرض مهندسو المركز الجغرافي الشوارع المكتشفة في لوحة التدقيق (Review Dashboard) بجانب صور الأقمار الصناعية والخرائط السوفيتية، وبضغطة زر واحدة يُحقن الطريق في محرك الملاحة. +

+
+
+ + {/* Military & Tactical Deployment Expansion */} +
+ +
+
+ الأثر العسكري والتوسعي: العمل في أي مسرح عمليات فورياً +
+
+ إذا تم نشر آليات القوات المسلحة أو الأجهزة الأمنية في أي منطقة حدودية أو دولة مجاورة (مثل جنوب سوريا، غرب العراق، صحراء سيناء)، يكفي تشغيل تطبيق التتبع لتبدأ المنصة فوراً برسم شبكة الطرق والممرات الوعرة ونشرها لباقي التشكيلات في الميدان دون انتظار أي طرف أجنبي! +
+
+
+
+
+ )} + + {/* TAB 2: TACTICAL & MILITARY TOOLS */} + {activeTab === 'tactical' && ( +
+
+

+ قدرات الميدان والتحليل التكتيكي العسكري +

+

+ تم تزويد المنصة بأدوات تحليل تضاريسي مخصصة لخدمة سلاح المدفعية، الاستطلاع، وغرف العمليات والسيطرة المشتركة: +

+ +
+
+
+
+ +
+

تبادل الرؤية وخط النظر (Line of Sight)

+
+
    +
  • تحديد إمكانية الرؤية المباشرة بين نقطتين (راصد وهدف).
  • +
  • كشف وتحديد القمم الجبلية والعوائق الحاجبة للرؤية بدقة المتر.
  • +
  • حساب نسبة الأرض الميتة (Dead Ground) خلف الحواف.
  • +
  • تصحيح انكسار الضوء الجوي التكتيكي وتقوس الأرض (Earth Curvature).
  • +
+
+ +
+
+
+ +
+

حسابات الرماية وزاوية الموقع (Mils)

+
+
    +
  • حساب زاوية الموقع (Angle of Site) بالميللي العسكري (Artillery Mils).
  • +
  • حساب السمت والاتجاه البوصلّي الدقيق (Azimuth / Bearing).
  • +
  • مقطع رأسي كامل للارتفاعات فوق مستوى سطح البحر (AMSL).
  • +
  • تعديل ارتفاع عين الراصد وارتفاع الهدف حسب نوع الآلية أو البرج.
  • +
+
+ +
+
+
+ +
+

التشغيل المعزول التام (Air-Gapped Offline)

+
+
    +
  • نظام كامل يعمل داخل خادم صغير أو جهاز لوحي عسكري داخل الآلية.
  • +
  • توجيه وملاحة وحساب مسافات بدون الحاجة لأي اتصال بالإنترنت.
  • +
  • حماية تامة من التشويش أو قطع الخدمات السحابية الأجنبية.
  • +
  • تشفير مسارات وبيانات التحركات وفق معايير أمنية صارمة.
  • +
+
+
+
+
+ )} + + {/* TAB 3: DIRECT COMPARISON WITH ESRI ARCGIS */} + {activeTab === 'comparison' && ( +
+
+

+ مقارنة مباشرة: منصة انطلاق السيادية مقابل إزري (Esri ArcGIS) +

+ +
+ + + + + + + + + + {[ + { + criteria: 'التكلفة والترخيص السنوي', + esri: 'عشرات إلى مئات الآلاف $ سنوياً (تراخيص مستخدمين + استهلاك Credits)', + intaleq: 'ملكية سيادية وطنية كاملة $0 رخص سنوية أو رسوم مستخدمين' + }, + { + criteria: 'السيادة وسرية البيانات', + esri: 'تعتمد على سحابة إزري الأمريكية في البحث والتوجيه وتحديث البيانات', + intaleq: 'سيرفرات داخلية 100% داخل المركز الجغرافي أو القيادة العامة (On-Premise)' + }, + { + criteria: 'سرعة عرض الخرائط التفاعلية', + esri: 'ثقيلة وبطيئة على المتصفحات وتطبيقات الميدان (15-25 FPS)', + intaleq: 'فائقة السرعة عبر Vector Tiles ورندرة بكرت الشاشة (60 FPS)' + }, + { + criteria: 'تحديث شبكة الطرق', + esri: 'يتطلب مسحاً ميدانياً بطيئاً أو شراء مجموعات بيانات دورية باهظة', + intaleq: 'تحديث تلقائي لحظي من بيانات تتبع حركة السائقين والآليات' + }, + { + criteria: 'البحث بالعربية والمسميات المحلية', + esri: 'ضعيف في فهم اللهجة الشعبية، التقسيمات العشائرية والأخطاء الإملائية', + intaleq: 'محرك بحث ذكي يفهم اللهجة الأردنية، الاستعلامات النسبية وبوابات المجمعات' + }, + { + criteria: 'التكامل مع تطبيقات الموبايل والميدان', + esri: 'يحتاج مكتبات SDK ضخمة وتراخيص App Development مدفوعة', + intaleq: 'واجهات REST APIs و MapLibre مفتوحة وسهلة الدمج مع أي تطبيق فلاتر أو أندرويد' + }, + { + criteria: 'الاستخدام في مسارح عمليات خارج الأردن', + esri: 'شراء تراخيص خرائط منفصلة لكل دولة إضافية', + intaleq: 'إضافة أي دولة (سوريا، مصر، العراق) بسكربت واحد خلال دقائق معدودة' + } + ].map((row, idx) => ( + + + + + + ))} + +
المعيارمنظومة إزري (Esri ArcGIS)منصة انطلاق السيادية (Intaleq)
{row.criteria}✕ {row.esri}✓ {row.intaleq}
+
+
+
+ )} + + {/* TAB 4: ROADMAP WITH RJGC */} + {activeTab === 'roadmap' && ( +
+
+

+ خطة الشراكة والتنفيذ المقترحة مع المركز الجغرافي الملكي +

+

+ لا نطلب من المركز إلغاء ما لديه فجأة، بل نقترح مسار شراكة استراتيجي آمن يبدأ بإثبات الجدارة: +

+ +
+ {[ + { + phase: 'المرحلة الأولى: إثبات المفهوم (POC) لمدة 30 يوماً', + duration: 'الشهر الأول', + desc: 'تنصيب نسخة سريعة داخل خوادم المركز الجغرافي لعرض خرائط المملكة وبلاطات المتجهات ومقارنة سرعتها وأدائها مع خوادم ArcGIS الحالية دون أي التزام مالي.' + }, + { + phase: 'المرحلة الثانية: ربط أساطيل التتبع وتفعيل التحديث التلقائي', + duration: 'الشهر الثاني - الثالث', + desc: 'ربط بيانات تتبع آليات حكومية أو تجارية لبدء اكتشاف الطرق الجديدة تلقائياً وتزويد مهندسي المركز بلوحة مراجعة واعتماد الشوارع.' + }, + { + phase: 'المرحلة الثالثة: دمج الأدوات التكتيكية مع القيادة العامة وسلاح المدفعية', + duration: 'الشهر الرابع فصاعداً', + desc: 'تخصيص محرك تبادل الرؤية (LOS) ومقاطع التضاريس والخرائط غير المتصلة (Offline) ليتم تعميمها على الأجهزة اللوحية الميدانية في القوات المسلحة.' + } + ].map((item, idx) => ( +
+
+ {idx + 1} +
+
+
+

{item.phase}

+ + {item.duration} + +
+

+ {item.desc} +

+
+
+ ))} +
+
+
+ )} + + {/* Live Demo Launcher Banner */} +
+
+

+ هل ترغب في استعراض النظام عملياً الآن؟ +

+

+ الخريطة الحية وأدوات التوجيه وتبادل الرؤية والطقس جاهزة وتعمل بالكامل داخل المتصفح. +

+
+ +
+ +
+
+ ); +}; diff --git a/apps/web/src/pages/IntelligenceDashboard.tsx b/apps/web/src/pages/IntelligenceDashboard.tsx index 6230838..37792ac 100644 --- a/apps/web/src/pages/IntelligenceDashboard.tsx +++ b/apps/web/src/pages/IntelligenceDashboard.tsx @@ -225,9 +225,9 @@ const IntelligenceDashboard: React.FC = () => { closesRef.current = safeCloses; pushMapData(); setNeedsAuth(false); - } catch (e: any) { + } catch (e: unknown) { console.error(e); - setMsg(e.message || 'Error loading dashboard'); + setMsg((e as any)?.message || 'Error loading dashboard'); } setLoading(false); }; @@ -484,7 +484,7 @@ const IntelligenceDashboard: React.FC = () => { setMsg('Road submitted for intelligence analysis!'); cancelDrawing(); load(); - } catch (e: any) { setMsg(e.message || 'Error submitting'); } + } catch (e: unknown) { setMsg((e as any)?.message || 'Error submitting'); } setTimeout(() => setMsg(''), 5000); }; @@ -495,7 +495,7 @@ const IntelligenceDashboard: React.FC = () => { const r = await fetch(`${API}/maps/sync-routes`, { method: 'POST', headers: { 'x-api-key': apiKey } }); if (!r.ok) throw new Error('Failed'); setMsg('✅ Routing sync requested! Check back in 5-10 min.'); - } catch (e: any) { setMsg(e.message || 'Error'); } + } catch (e: unknown) { setMsg((e as any)?.message || 'Error'); } setTimeout(() => setMsg(''), 5000); }; diff --git a/apps/web/src/utils/elevationService.ts b/apps/web/src/utils/elevationService.ts new file mode 100644 index 0000000..f79ea3b --- /dev/null +++ b/apps/web/src/utils/elevationService.ts @@ -0,0 +1,363 @@ +/** + * Tactical Elevation & Line of Sight (LOS) Calculation Service + * خدمة حساب مقطع الارتفاع التضاريسي وتبادل الرؤية العسكري (Intervisibility) + */ + +export interface ElevationPoint { + distance: number; // Distance from observer (meters) + lat: number; + lng: number; + elevation: number; // Terrain elevation AMSL (meters) + rayHeight: number; // Line of Sight ray elevation at this distance (meters) + isVisible: boolean; // Can observer see this terrain point? + isTargetRayBlocked: boolean; // Does this terrain point block the ray to the final target? + clearance: number; // Clearance distance (rayHeight - elevation) in meters +} + +export interface ObstacleInfo { + distance: number; + elevation: number; + lat: number; + lng: number; + excessHeight: number; // How much the obstacle penetrates above the ray (meters) +} + +export interface LineOfSightResult { + points: ElevationPoint[]; + totalDistance: number; // Total distance in meters + isDirectlyVisible: boolean; // Is target visible from observer? + observerElevation: number; // Ground elevation + observer height + targetElevation: number; // Ground elevation + target height + observerGroundElev: number; // Raw ground elevation + targetGroundElev: number; // Raw ground elevation + minElevation: number; + maxElevation: number; + highestObstacle: ObstacleInfo | null; + deadGroundPercentage: number; // % of line hidden behind crests + angleDegrees: number; // Vertical angle (degrees) + angleMils: number; // Military Artillery Mils (6400 mils = 360 deg) + azimuthDegrees: number; // Compass Bearing (0-360 deg) +} + +// In-memory cache for DEM tile image data to avoid re-fetching +const tileCache = new Map(); + +/** + * Calculates Great-Circle Haversine distance in meters + */ +export function calculateDistance(lat1: number, lon1: number, lat2: number, lon2: number): number { + const R = 6371000; // Earth radius in meters + const dLat = (lat2 - lat1) * (Math.PI / 180); + const dLon = (lon2 - lon1) * (Math.PI / 180); + const a = + Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) * + Math.sin(dLon / 2) * Math.sin(dLon / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + return R * c; +} + +/** + * Calculates Forward Azimuth / Bearing (0-360 degrees) + */ +export function calculateAzimuth(lat1: number, lon1: number, lat2: number, lon2: number): number { + const phi1 = lat1 * (Math.PI / 180); + const phi2 = lat2 * (Math.PI / 180); + const deltaLambda = (lon2 - lon1) * (Math.PI / 180); + const y = Math.sin(deltaLambda) * Math.cos(phi2); + const x = Math.cos(phi1) * Math.sin(phi2) - Math.sin(phi1) * Math.cos(phi2) * Math.cos(deltaLambda); + const theta = Math.atan2(y, x); + return (theta * (180 / Math.PI) + 360) % 360; +} + +/** + * Samples elevation from Terrarium DEM tile or fallback topographic model + */ +async function sampleElevationAt(lat: number, lng: number): Promise { + const zoom = 12; + const n = Math.pow(2, zoom); + const x = Math.floor(((lng + 180) / 360) * n); + const latRad = (lat * Math.PI) / 180; + const y = Math.floor((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * n); + + const tileKey = `${zoom}/${x}/${y}`; + + try { + let imgData = tileCache.get(tileKey); + + if (!imgData) { + const tileUrl = `https://s3.amazonaws.com/elevation-tiles-prod/terrarium/${zoom}/${x}/${y}.png`; + const img = new Image(); + img.crossOrigin = 'anonymous'; + + const loadPromise = new Promise((resolve, reject) => { + img.onload = () => resolve(img); + img.onerror = (e) => reject(e); + img.src = tileUrl; + }); + + // 1.5s timeout for fast responsiveness + const loadedImg = await Promise.race([ + loadPromise, + new Promise((_, reject) => setTimeout(() => reject(new Error('DEM Timeout')), 1500)) + ]); + + const canvas = document.createElement('canvas'); + canvas.width = 256; + canvas.height = 256; + const ctx = canvas.getContext('2d'); + if (ctx) { + ctx.drawImage(loadedImg, 0, 0); + imgData = ctx.getImageData(0, 0, 256, 256); + tileCache.set(tileKey, imgData); + } + } + + if (imgData) { + // Calculate exact sub-pixel inside tile + const subX = (((lng + 180) / 360) * n - x) * 256; + const subY = ((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * n - y) * 256; + const px = Math.min(255, Math.max(0, Math.floor(subX))); + const py = Math.min(255, Math.max(0, Math.floor(subY))); + + const index = (py * 256 + px) * 4; + const r = imgData.data[index]; + const g = imgData.data[index + 1]; + const b = imgData.data[index + 2]; + + // Terrarium formula: (R * 256 + G + B / 256) - 32768 + const elev = (r * 256 + g + b / 256) - 32768; + return Math.round(elev); + } + } catch (err) { + // Fallback topographic approximation for Jordan/Levant region + } + + return getApproximateElevation(lat, lng); +} + +/** + * Topographic estimation model for Jordan terrain when tiles are offline + */ +function getApproximateElevation(lat: number, lng: number): number { + // Jordan Valley & Dead Sea trench model + if (lng < 35.6 && lat < 32.2 && lat > 31.0) { + const distFromRift = Math.abs(lng - 35.5); + return -400 + distFromRift * 3000; + } + // Northern Highlands (Ajloun / Jerash / Salt) + if (lat >= 32.1 && lng < 36.0) { + return 850 + Math.sin(lat * 50) * 250 + Math.cos(lng * 40) * 150; + } + // Amman Plateau + if (lat >= 31.8 && lat < 32.1 && lng >= 35.8 && lng < 36.2) { + return 900 + Math.sin((lat - 31.95) * 100) * 120 + Math.cos((lng - 35.9) * 100) * 100; + } + // Southern Highlands (Karak / Tafilah / Shobak / Petra) + if (lat < 31.5 && lat > 30.0 && lng < 35.7) { + return 1100 + Math.sin(lat * 30) * 350; + } + // Eastern Desert (Badia) + return 650 + (lng - 36.0) * 30; +} + +/** + * Calculates Line of Sight and Elevation Profile between two coordinates + * + * @param startLat Observer Latitude + * @param startLng Observer Longitude + * @param endLat Target Latitude + * @param endLng Target Longitude + * @param obsHeight Observer Eye Level offset above ground (default: 2 meters) + * @param tgtHeight Target Height offset above ground (default: 2 meters) + * @param samples Number of sampling steps along the ray (default: 60) + */ +export async function calculateLineOfSight( + startLat: number, + startLng: number, + endLat: number, + endLng: number, + obsHeight: number = 2, + tgtHeight: number = 2, + samples: number = 60 +): Promise { + const totalDistance = calculateDistance(startLat, startLng, endLat, endLng); + const azimuthDegrees = calculateAzimuth(startLat, startLng, endLat, endLng); + + // Try fetching high-precision result from Backend Tactical API + try { + const apiUrl = (import.meta as any).env.VITE_API_URL || '/api'; + const apiKey = (import.meta as any).env.VITE_API_KEY; + + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 3000); + + const res = await fetch(`${apiUrl}/tactical/line-of-sight?observerLat=${startLat}&observerLng=${startLng}&targetLat=${endLat}&targetLng=${endLng}&observerHeight=${obsHeight}&targetHeight=${tgtHeight}&samples=${samples}`, { + headers: { 'x-api-key': apiKey }, + signal: controller.signal + }); + clearTimeout(timeoutId); + + if (res.ok) { + const data = await res.json(); + return { + points: (data.profile || []).map((p: any) => ({ + distance: p.distanceMeters, + lat: p.lat, + lng: p.lng, + elevation: p.groundElevationMeters, + rayHeight: p.rayElevationMeters, + isVisible: p.isVisible, + isTargetRayBlocked: p.isTargetRayBlocked, + clearance: p.clearanceMeters + })), + totalDistance: data.summary.totalDistanceMeters, + isDirectlyVisible: data.isDirectlyVisible, + observerElevation: data.summary.observerTotalElevationMeters, + targetElevation: data.summary.targetTotalElevationMeters, + observerGroundElev: data.summary.observerGroundElevationMeters, + targetGroundElev: data.summary.targetGroundElevationMeters, + minElevation: data.summary.minElevationMeters, + maxElevation: data.summary.maxElevationMeters, + highestObstacle: data.highestObstacle ? { + distance: data.highestObstacle.distanceMeters, + elevation: data.highestObstacle.groundElevationMeters, + lat: data.highestObstacle.lat, + lng: data.highestObstacle.lng, + excessHeight: data.highestObstacle.excessHeightMeters + } : null, + deadGroundPercentage: data.summary.deadGroundPercentage, + angleDegrees: data.summary.verticalAngleDegrees, + angleMils: data.summary.verticalAngleMilsNato, + azimuthDegrees: data.summary.azimuthDegrees + }; + } + } catch { + // API not available or timed out, fall back to local DEM tile processing + } + + // Generate sample coordinates along the geodesic path + const sampleCoords: { lat: number; lng: number; dist: number }[] = []; + for (let i = 0; i <= samples; i++) { + const fraction = i / samples; + const lat = startLat + (endLat - startLat) * fraction; + const lng = startLng + (endLng - startLng) * fraction; + const dist = totalDistance * fraction; + sampleCoords.push({ lat, lng, dist }); + } + + // Fetch elevations for all sample points in parallel + const elevations = await Promise.all( + sampleCoords.map((coord) => sampleElevationAt(coord.lat, coord.lng)) + ); + + const observerGroundElev = elevations[0]; + const targetGroundElev = elevations[elevations.length - 1]; + const observerElevation = observerGroundElev + obsHeight; + const targetElevation = targetGroundElev + tgtHeight; + + // Earth curvature & atmospheric refraction parameter (k ≈ 0.13 for standard atmosphere) + const R_earth = 6371000; + const k_refraction = 0.13; + const effectiveEarthRadius = R_earth / (1 - k_refraction); + + let isDirectlyVisible = true; + let highestObstacle: ObstacleInfo | null = null; + let maxObstacleExcess = 0; + let deadGroundCount = 0; + + // Horizon angle tracking from observer (tan of highest angle encountered so far) + let maxAngleSoFar = -Infinity; + + const points: ElevationPoint[] = []; + let minElev = Infinity; + let maxElev = -Infinity; + + for (let i = 0; i <= samples; i++) { + const d = sampleCoords[i].dist; + const elev = elevations[i]; + minElev = Math.min(minElev, elev); + maxElev = Math.max(maxElev, elev); + + // Earth curvature sagitta at distance d: deltaH = (d * (totalDistance - d)) / (2 * R_effective) + const earthCurvatureDrop = (d * (totalDistance - d)) / (2 * effectiveEarthRadius); + + // Theoretical straight ray height AMSL connecting Observer to Target + const rayHeight = observerElevation + ((targetElevation - observerElevation) * (d / totalDistance)) - earthCurvatureDrop; + + // Clearance (positive = ray above terrain, negative = obstacle) + const clearance = rayHeight - elev; + + // Check if this point blocks the direct ray to the target (ignore start and end margins) + let isTargetRayBlocked = false; + if (i > 1 && i < samples) { + if (elev > rayHeight) { + isDirectlyVisible = false; + isTargetRayBlocked = true; + const excess = elev - rayHeight; + if (excess > maxObstacleExcess) { + maxObstacleExcess = excess; + highestObstacle = { + distance: Math.round(d), + elevation: elev, + lat: sampleCoords[i].lat, + lng: sampleCoords[i].lng, + excessHeight: Math.round(excess * 10) / 10, + }; + } + } + } + + // Check visibility from observer's eye (Viewshed / Shadowing along profile) + let isVisible = true; + if (i === 0) { + isVisible = true; + } else { + const angleFromObs = (elev - observerElevation) / d; + if (angleFromObs >= maxAngleSoFar) { + maxAngleSoFar = angleFromObs; + isVisible = true; + } else { + isVisible = false; + deadGroundCount++; + } + } + + points.push({ + distance: Math.round(d), + lat: sampleCoords[i].lat, + lng: sampleCoords[i].lng, + elevation: elev, + rayHeight: Math.round(rayHeight * 10) / 10, + isVisible, + isTargetRayBlocked, + clearance: Math.round(clearance * 10) / 10, + }); + } + + // Calculate Vertical Angle (Degrees & Artillery Mils) + // 1 Degree = 17.7778 Artillery Mils (6400 Mils in full circle) + const verticalDiff = targetElevation - observerElevation; + const angleRad = Math.atan2(verticalDiff, totalDistance); + const angleDegrees = Math.round((angleRad * (180 / Math.PI)) * 100) / 100; + const angleMils = Math.round((angleDegrees * (6400 / 360)) * 10) / 10; + + const deadGroundPercentage = Math.round((deadGroundCount / samples) * 100); + + return { + points, + totalDistance: Math.round(totalDistance), + isDirectlyVisible, + observerElevation: Math.round(observerElevation), + targetElevation: Math.round(targetElevation), + observerGroundElev: Math.round(observerGroundElev), + targetGroundElev: Math.round(targetGroundElev), + minElevation: Math.round(minElev), + maxElevation: Math.round(maxElev), + highestObstacle, + deadGroundPercentage, + angleDegrees, + angleMils, + azimuthDegrees: Math.round(azimuthDegrees * 10) / 10, + }; +} diff --git a/apps/web/src/utils/weatherIcons.ts b/apps/web/src/utils/weatherIcons.ts new file mode 100644 index 0000000..05d24da --- /dev/null +++ b/apps/web/src/utils/weatherIcons.ts @@ -0,0 +1,36 @@ +export function getWeatherDescription(code: number): { icon: string, description_ar: string, description_en: string } { + switch (code) { + case 0: return { icon: '☀️', description_ar: 'صافي', description_en: 'Clear' }; + case 1: return { icon: '🌤️', description_ar: 'صافي غالباً', description_en: 'Mainly clear' }; + case 2: return { icon: '⛅', description_ar: 'غائم جزئياً', description_en: 'Partly cloudy' }; + case 3: return { icon: '☁️', description_ar: 'غائم', description_en: 'Overcast' }; + case 45: + case 48: return { icon: '🌫️', description_ar: 'ضباب', description_en: 'Fog' }; + case 51: + case 53: + case 55: return { icon: '🌦️', description_ar: 'رذاذ', description_en: 'Drizzle' }; + case 61: return { icon: '🌧️', description_ar: 'أمطار خفيفة', description_en: 'Light rain' }; + case 63: return { icon: '🌧️', description_ar: 'أمطار متوسطة', description_en: 'Moderate rain' }; + case 65: return { icon: '🌧️', description_ar: 'أمطار غزيرة', description_en: 'Heavy rain' }; + case 71: + case 73: + case 75: return { icon: '🌨️', description_ar: 'ثلوج', description_en: 'Snow' }; + case 80: + case 81: + case 82: return { icon: '🌧️', description_ar: 'زخات مطرية', description_en: 'Rain showers' }; + case 95: return { icon: '⛈️', description_ar: 'عاصفة رعدية', description_en: 'Thunderstorm' }; + case 96: + case 99: return { icon: '⛈️', description_ar: 'عاصفة رعدية مع بَرَد', description_en: 'Thunderstorm with hail' }; + default: return { icon: '🌡️', description_ar: 'غير معروف', description_en: 'Unknown' }; + } +} + +export function getTemperatureColor(temp: number): string { + if (temp <= 0) return '#0047AB'; + if (temp <= 10) return '#4169E1'; + if (temp <= 20) return '#32CD32'; + if (temp <= 30) return '#FFD700'; + if (temp <= 40) return '#FF8C00'; + if (temp <= 45) return '#FF4500'; + return '#DC143C'; +} diff --git a/data/boundaries/generate_sql.py b/data/boundaries/generate_sql.py new file mode 100644 index 0000000..3412971 --- /dev/null +++ b/data/boundaries/generate_sql.py @@ -0,0 +1,57 @@ +import json +import os + +with open("data/boundaries/jordan_adm0.geojson", "r") as f: + adm0 = json.load(f) + +with open("data/boundaries/jordan_adm1.geojson", "r") as f: + adm1 = json.load(f) + +lines = [] +lines.append("BEGIN;") +lines.append("-- 1. Delete previous dummy borders") +lines.append("DELETE FROM planet_osm_line WHERE osm_id >= 999000 AND osm_id <= 999999;") +lines.append("DELETE FROM planet_osm_polygon WHERE osm_id >= 999000 AND osm_id <= 999999;") +lines.append("") + +# National border (ADM0) +geom0_str = json.dumps(adm0["features"][0]["geometry"]).replace("'", "''") +lines.append("-- 2. Official Jordan National Boundary (ADM0)") +lines.append(f"""INSERT INTO planet_osm_line (osm_id, boundary, admin_level, name, way) +SELECT + 999000, + 'administrative', + '2', + 'المملكة الأردنية الهاشمية - Jordan Official National Border', + ST_Transform(ST_Boundary(ST_SetSRID(ST_GeomFromGeoJSON('{geom0_str}'), 4326)), 3857); +""") + +# Governorates (ADM1) +for idx, feat in enumerate(adm1["features"]): + name = feat["properties"].get("shapeName", f"Governorate {idx}").replace("'", "''") + geom_str = json.dumps(feat["geometry"]).replace("'", "''") + osm_id = 999010 + idx + lines.append(f"""-- Governorate {name} +INSERT INTO planet_osm_polygon (osm_id, boundary, admin_level, name, way) +SELECT + {osm_id}, + 'administrative', + '4', + '{name}', + ST_Transform(ST_SetSRID(ST_GeomFromGeoJSON('{geom_str}'), 4326), 3857); + +INSERT INTO planet_osm_line (osm_id, boundary, admin_level, name, way) +SELECT + {osm_id}, + 'administrative', + '4', + '{name}', + ST_Transform(ST_Boundary(ST_SetSRID(ST_GeomFromGeoJSON('{geom_str}')), 4326), 3857); +""") + +lines.append("COMMIT;") + +with open("data/boundaries/import_official_jordan.sql", "w") as f: + f.write("\n".join(lines)) + +print(f"Generated SQL with {len(adm1['features'])} governorates + ADM0 national boundary.") diff --git a/data/boundaries/jordan_adm0.geojson b/data/boundaries/jordan_adm0.geojson new file mode 100644 index 0000000..ca22a9c --- /dev/null +++ b/data/boundaries/jordan_adm0.geojson @@ -0,0 +1,7 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "shapeName": "the Hashemite Kingdom of Jordan", "shapeISO": "JOR", "shapeID": "64752131B76849546124065", "shapeGroup": "JOR", "shapeType": "ADM0" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 39.076936554000042, 32.33079305900003 ], [ 39.068924499000047, 32.332364648000066 ], [ 39.060626299000035, 32.334298875000059 ], [ 39.05089737600008, 32.339134260000037 ], [ 39.042026887000077, 32.346749468000041 ], [ 39.033156398000074, 32.355451777000042 ], [ 39.023141330000044, 32.368745355000044 ], [ 39.018563013000062, 32.379982946000041 ], [ 39.01398469600008, 32.393152108000038 ], [ 39.00940637900004, 32.406077766000067 ], [ 39.006688004000068, 32.41791459500007 ], [ 39.007403365000073, 32.431440498000029 ], [ 39.008261800000071, 32.443394742000066 ], [ 39.009549451000055, 32.45088043100003 ], [ 39.010837103000028, 32.455951028000072 ], [ 39.011409392000076, 32.461021340000059 ], [ 39.013841623000076, 32.466815633000067 ], [ 39.01641692700008, 32.471523220000051 ], [ 39.01942144800006, 32.475868468000044 ], [ 39.024572054000032, 32.482506636000039 ], [ 39.028291936000073, 32.489627035000069 ], [ 39.033871760000068, 32.497591560000046 ], [ 39.037448570000038, 32.504469445000041 ], [ 39.040596163000032, 32.509537024000053 ], [ 39.045889842000065, 32.517620428000043 ], [ 39.050754304000066, 32.528115703000026 ], [ 39.05204195500005, 32.535111873000062 ], [ 39.052900390000048, 32.544399049000049 ], [ 39.053053731000034, 32.551965105000079 ], [ 39.052984710000032, 32.567015647000062 ], [ 39.052020230000039, 32.576459763000059 ], [ 39.050356383000064, 32.587113004000059 ], [ 39.048729564000041, 32.598487801000033 ], [ 39.046652499000061, 32.609798777000037 ], [ 39.043314294000027, 32.621478689000071 ], [ 38.79336984300005, 33.374339039000063 ], [ 38.791497366000044, 33.373650316000067 ], [ 38.451569757000073, 33.194180221000067 ], [ 37.555584356000054, 32.713316761000044 ], [ 36.981355049000058, 32.402386827000043 ], [ 36.867914529000075, 32.340732567000032 ], [ 36.855960035000066, 32.327622932000054 ], [ 36.839172873000052, 32.309782185000074 ], [ 36.835103258000061, 32.310857029000033 ], [ 36.821622658000024, 32.313651561000029 ], [ 36.809668164000072, 32.316016099000024 ], [ 36.796187563000046, 32.318165625000063 ], [ 36.77990910300008, 32.321819702000028 ], [ 36.762358889000041, 32.326333358000056 ], [ 36.751930500000071, 32.328267713000059 ], [ 36.738449900000035, 32.329987105000043 ], [ 36.72980196900005, 32.328912489000061 ], [ 36.72369754500005, 32.328482639000072 ], [ 36.714795262000052, 32.329127413000037 ], [ 36.704621225000039, 32.331491546000052 ], [ 36.692666731000031, 32.335574904000055 ], [ 36.566508664000025, 32.35061726400005 ], [ 36.499360015000036, 32.360286031000044 ], [ 36.484607661000041, 32.369738938000069 ], [ 36.469600955000033, 32.372746473000063 ], [ 36.448744178000027, 32.374035387000049 ], [ 36.427124349000053, 32.375753909000025 ], [ 36.397619640000073, 32.38026487500008 ], [ 36.383630338000046, 32.398091726000075 ], [ 36.361756157000059, 32.418491634000077 ], [ 36.342171134000068, 32.435237585000039 ], [ 36.330470991000027, 32.445755887000075 ], [ 36.308342459000073, 32.46228216600008 ], [ 36.295370561000027, 32.468076378000035 ], [ 36.285705226000061, 32.474084796000056 ], [ 36.268918063000058, 32.482023876000028 ], [ 36.255437463000078, 32.491034956000078 ], [ 36.247806935000028, 32.495754686000055 ], [ 36.244246022000027, 32.498328980000053 ], [ 36.235598090000053, 32.504335378000064 ], [ 36.23051107100008, 32.509912389000078 ], [ 36.221100086000035, 32.515489054000057 ], [ 36.213978260000033, 32.522352166000076 ], [ 36.20634773200004, 32.527284704000067 ], [ 36.196682397000075, 32.530286987000068 ], [ 36.187525762000064, 32.524925698000061 ], [ 36.179132182000046, 32.518277256000033 ], [ 36.16514287900003, 32.51441664500004 ], [ 36.157512351000037, 32.520207500000026 ], [ 36.153697087000069, 32.523638941000058 ], [ 36.144031752000046, 32.522352166000076 ], [ 36.13614687300003, 32.522781094000038 ], [ 36.124192378000032, 32.523424480000074 ], [ 36.116816200000073, 32.523638941000058 ], [ 36.109440023000047, 32.520850905000032 ], [ 36.104607355000041, 32.519349619000025 ], [ 36.093924616000038, 32.517633833000048 ], [ 36.085785386000055, 32.515918013000032 ], [ 36.077900507000038, 32.512915252000028 ], [ 36.076120050000043, 32.519135148000032 ], [ 36.075611349000042, 32.529429202000074 ], [ 36.074339594000037, 32.540150922000066 ], [ 36.069506925000042, 32.549799374000031 ], [ 36.065691662000063, 32.558803662000059 ], [ 36.061367696000048, 32.567807045000052 ], [ 36.056280676000029, 32.577452525000069 ], [ 36.046106640000062, 32.587954201000059 ], [ 36.037713058000065, 32.594168899000067 ], [ 36.028047722000053, 32.599526052000044 ], [ 36.024232459000075, 32.605097151000052 ], [ 36.021943300000032, 32.609810887000037 ], [ 36.021943300000032, 32.618594915000074 ], [ 36.023215054000048, 32.627592294000067 ], [ 36.023978108000051, 32.633804242000053 ], [ 36.024486809000052, 32.641515025000047 ], [ 36.024995511000043, 32.648368498000025 ], [ 36.023215054000048, 32.655435590000025 ], [ 36.019654142000036, 32.658005304000028 ], [ 36.014139813000043, 32.662887556000044 ], [ 36.010884121000061, 32.663435723000077 ], [ 36.006977291000055, 32.664669084000025 ], [ 36.000140337000062, 32.665491315000054 ], [ 35.993140600000061, 32.666313539000043 ], [ 35.986140861000024, 32.666861684000025 ], [ 35.981420108000066, 32.66713575600005 ], [ 35.975071509000031, 32.667409826000039 ], [ 35.968071770000051, 32.668917198000031 ], [ 35.962048741000046, 32.672754031000068 ], [ 35.959118618000048, 32.674809409000034 ], [ 35.957327987000042, 32.677686860000051 ], [ 35.961723171000074, 32.680153172000075 ], [ 35.965955570000062, 32.68316746000005 ], [ 35.967257847000042, 32.68878472800003 ], [ 35.964164940000046, 32.693853666000052 ], [ 35.959769756000071, 32.698785329000032 ], [ 35.955374572000039, 32.703442761000076 ], [ 35.949677110000039, 32.704264636000062 ], [ 35.943328511000061, 32.705634410000073 ], [ 35.93763105000005, 32.70851086700003 ], [ 35.935026496000035, 32.712209032000032 ], [ 35.933073081000032, 32.718783170000052 ], [ 35.92932903500008, 32.722754810000026 ], [ 35.922329297000033, 32.725767660000031 ], [ 35.914352852000036, 32.726726273000054 ], [ 35.904585776000033, 32.726452385000073 ], [ 35.893679208000037, 32.726452385000073 ], [ 35.886882950000029, 32.728215527000032 ], [ 35.883067686000061, 32.729285377000053 ], [ 35.876454562000049, 32.730783146000078 ], [ 35.872130596000034, 32.732922773000041 ], [ 35.865263120000066, 32.735062347000053 ], [ 35.862210909000055, 32.735062347000053 ], [ 35.857632592000073, 32.73484839200006 ], [ 35.849239011000066, 32.733136732000048 ], [ 35.842880237000031, 32.732066928000052 ], [ 35.838047570000072, 32.730355215000031 ], [ 35.828127883000036, 32.72864346800003 ], [ 35.823803917000077, 32.728857438000034 ], [ 35.817953845000034, 32.730783146000078 ], [ 35.813884230000042, 32.73377860800008 ], [ 35.811340721000079, 32.736132115000032 ], [ 35.801421034000043, 32.738699507000035 ], [ 35.79887752500008, 32.741480764000073 ], [ 35.79938622700007, 32.744048002000056 ], [ 35.800403630000062, 32.747898719000034 ], [ 35.800912333000042, 32.752818838000053 ], [ 35.797097068000028, 32.754957934000061 ], [ 35.790992646000063, 32.754316211000059 ], [ 35.784379521000062, 32.752604925000071 ], [ 35.77776639700005, 32.751107522000041 ], [ 35.769881518000034, 32.749824015000058 ], [ 35.761996638000028, 32.746187309000049 ], [ 35.75563786500004, 32.739983175000077 ], [ 35.751059548000057, 32.734206524000058 ], [ 35.748516038000048, 32.72864346800003 ], [ 35.748007337000047, 32.726717715000063 ], [ 35.742411616000027, 32.72329404900006 ], [ 35.735544140000059, 32.723508032000041 ], [ 35.730308581000031, 32.722820546000037 ], [ 35.726245477000077, 32.721856414000058 ], [ 35.719890366000072, 32.719226907000063 ], [ 35.715202170000055, 32.715370157000052 ], [ 35.711347430000046, 32.712740459000031 ], [ 35.706138323000062, 32.709584720000066 ], [ 35.700199941000051, 32.705990547000056 ], [ 35.695615927000063, 32.703448240000057 ], [ 35.691657004000035, 32.700993530000062 ], [ 35.684572619000051, 32.699327796000034 ], [ 35.679571875000079, 32.697837375000063 ], [ 35.67561295400003, 32.696171582000034 ], [ 35.671862397000041, 32.695207160000052 ], [ 35.667278382000063, 32.694944135000071 ], [ 35.662486004000073, 32.694944135000071 ], [ 35.657172714000069, 32.695031810000046 ], [ 35.651130150000029, 32.695207160000052 ], [ 35.646025225000074, 32.69354131800003 ], [ 35.643316490000075, 32.69125073400005 ], [ 35.63908409000004, 32.689195734000066 ], [ 35.635828397000068, 32.688099714000032 ], [ 35.630619290000027, 32.686318654000047 ], [ 35.628014737000058, 32.68494858400004 ], [ 35.624433476000036, 32.684263540000074 ], [ 35.621177783000064, 32.684126531000061 ], [ 35.616945383000029, 32.682893439000054 ], [ 35.612875769000027, 32.681934355000067 ], [ 35.608806154000035, 32.680701232000047 ], [ 35.603922615000045, 32.67754984000004 ], [ 35.600504139000066, 32.67412428800003 ], [ 35.600992492000046, 32.67042454500006 ], [ 35.602131985000028, 32.667409826000039 ], [ 35.602457554000068, 32.664943162000043 ], [ 35.600178569000036, 32.660831904000077 ], [ 35.598062370000036, 32.660283722000031 ], [ 35.594806678000054, 32.659598489000075 ], [ 35.592364909000025, 32.657542761000059 ], [ 35.591225417000032, 32.655898144000048 ], [ 35.58796972500005, 32.650004687000035 ], [ 35.585853525000061, 32.648908186000028 ], [ 35.584388463000039, 32.647948738000025 ], [ 35.58064441700003, 32.646441012000025 ], [ 35.576412018000042, 32.64438498100003 ], [ 35.572505187000047, 32.641917681000052 ], [ 35.567458864000059, 32.638764922000064 ], [ 35.564203172000077, 32.636434550000047 ], [ 35.562738112000034, 32.632184892000055 ], [ 35.563389249000068, 32.628757602000064 ], [ 35.564691526000047, 32.622725252000066 ], [ 35.565505449000057, 32.614635781000061 ], [ 35.567621649000046, 32.607368345000054 ], [ 35.569086711000068, 32.60380297200004 ], [ 35.571691264000037, 32.600511733000076 ], [ 35.573481895000043, 32.599140347000059 ], [ 35.576574803000028, 32.59845464700004 ], [ 35.577877080000064, 32.595986082000024 ], [ 35.578365433000045, 32.591460201000075 ], [ 35.577388726000038, 32.587757038000063 ], [ 35.575923664000072, 32.584602372000063 ], [ 35.574295818000053, 32.580075916000055 ], [ 35.574295818000053, 32.574863351000033 ], [ 35.574458603000039, 32.569650484000078 ], [ 35.577225941000052, 32.565397657000062 ], [ 35.58064441700003, 32.561007430000075 ], [ 35.582435048000036, 32.557440213000064 ], [ 35.582923402000063, 32.552912387000049 ], [ 35.582923402000063, 32.551540274000047 ], [ 35.581132771000057, 32.549344848000032 ], [ 35.580156063000061, 32.548795984000037 ], [ 35.576412018000042, 32.548109898000064 ], [ 35.573807464000026, 32.547012150000057 ], [ 35.572993541000073, 32.545502724000073 ], [ 35.573319110000057, 32.543444376000025 ], [ 35.572993541000073, 32.540699839000069 ], [ 35.570551772000044, 32.539602001000048 ], [ 35.567133295000076, 32.542072119000068 ], [ 35.564040388000024, 32.54289547500008 ], [ 35.561598619000051, 32.540562610000052 ], [ 35.561761404000038, 32.537269049000031 ], [ 35.562738112000034, 32.535759460000065 ], [ 35.564854311000033, 32.533426409000072 ], [ 35.566482157000053, 32.532191239000042 ], [ 35.568110003000072, 32.528760125000076 ], [ 35.568110003000072, 32.525603383000032 ], [ 35.56664494100005, 32.523270068000045 ], [ 35.563714818000051, 32.522446530000025 ], [ 35.557366219000073, 32.520662173000062 ], [ 35.555738373000054, 32.516132493000043 ], [ 35.556389512000067, 32.51297530800008 ], [ 35.558505712000056, 32.509955288000072 ], [ 35.562738112000034, 32.506660605000036 ], [ 35.56664494100005, 32.502130218000048 ], [ 35.571202910000068, 32.49787419300003 ], [ 35.577388726000038, 32.493480666000039 ], [ 35.579667710000024, 32.488125763000028 ], [ 35.578365433000045, 32.483045178000054 ], [ 35.575435310000046, 32.47686569900003 ], [ 35.57234240300005, 32.47260847900003 ], [ 35.569575064000048, 32.468076378000035 ], [ 35.568435572000055, 32.464780161000078 ], [ 35.568761141000039, 32.459835610000027 ], [ 35.570226203000061, 32.456401734000053 ], [ 35.572016834000067, 32.454478706000032 ], [ 35.574621387000036, 32.453105090000065 ], [ 35.576574803000028, 32.452006182000048 ], [ 35.578853787000071, 32.449533589000055 ], [ 35.578853787000071, 32.448572007000053 ], [ 35.577877080000064, 32.446648812000035 ], [ 35.575109741000063, 32.443626567000024 ], [ 35.571691264000037, 32.441291125000077 ], [ 35.571040126000071, 32.437169610000069 ], [ 35.571202910000068, 32.432635726000058 ], [ 35.569737849000035, 32.42906341500003 ], [ 35.568435572000055, 32.427277206000042 ], [ 35.566482157000053, 32.425490961000037 ], [ 35.563389249000068, 32.421093901000063 ], [ 35.562738112000034, 32.417933382000058 ], [ 35.563389249000068, 32.412436564000075 ], [ 35.563389249000068, 32.407626573000073 ], [ 35.563552034000054, 32.402953764000074 ], [ 35.562575327000047, 32.400479828000073 ], [ 35.558994066000025, 32.397456034000072 ], [ 35.554924450000044, 32.39443213900006 ], [ 35.555250020000074, 32.390583399000036 ], [ 35.557203435000076, 32.387834200000043 ], [ 35.561110266000071, 32.384122646000037 ], [ 35.560621912000045, 32.380685887000027 ], [ 35.558017358000029, 32.378348816000027 ], [ 35.554273312000078, 32.375049319000027 ], [ 35.554549134000069, 32.36829201300003 ], [ 35.554415781000046, 32.366489862000037 ], [ 35.554549134000069, 32.363504971000054 ], [ 35.555615959000079, 32.360238373000072 ], [ 35.557349550000026, 32.357365922000042 ], [ 35.558749758000033, 32.355450904000065 ], [ 35.562617, 32.351789727000039 ], [ 35.564483943000027, 32.350099903000057 ], [ 35.56568412200005, 32.346945481000034 ], [ 35.565484092000077, 32.344466929000077 ], [ 35.56435059000006, 32.341593978000049 ], [ 35.563750501000072, 32.338833604000058 ], [ 35.563877603000037, 32.33365789800007 ], [ 35.562412542000061, 32.32994412100004 ], [ 35.561924189000024, 32.328431057000046 ], [ 35.560621912000045, 32.323479034000059 ], [ 35.560459127000058, 32.320039969000049 ], [ 35.560296342000072, 32.314812342000039 ], [ 35.561273050000068, 32.309997155000076 ], [ 35.564528741000061, 32.305869647000065 ], [ 35.565505449000057, 32.302292323000074 ], [ 35.566970511000079, 32.297614070000066 ], [ 35.566156588000069, 32.295687660000056 ], [ 35.564854311000033, 32.291972325000074 ], [ 35.563389249000068, 32.288532066000073 ], [ 35.561924189000024, 32.284541200000035 ], [ 35.562738112000034, 32.279036270000063 ], [ 35.565179880000073, 32.273255734000031 ], [ 35.569412280000051, 32.267474829000037 ], [ 35.569737849000035, 32.262381822000066 ], [ 35.569086711000068, 32.258252148000054 ], [ 35.568272787000069, 32.25481060900006 ], [ 35.56664494100005, 32.251093600000047 ], [ 35.56583101800004, 32.244622889000027 ], [ 35.568110003000072, 32.238427094000031 ], [ 35.570714557000031, 32.233745548000059 ], [ 35.570877341000028, 32.228926056000034 ], [ 35.570877341000028, 32.22534569700008 ], [ 35.570714557000031, 32.21818455600004 ], [ 35.572993541000073, 32.213364239000043 ], [ 35.575923664000072, 32.203034129000059 ], [ 35.575760880000075, 32.192840603000036 ], [ 35.57315632600006, 32.185263595000038 ], [ 35.569086711000068, 32.176997049000079 ], [ 35.564854311000033, 32.169005340000069 ], [ 35.562575327000047, 32.157981143000029 ], [ 35.561924189000024, 32.139236948000075 ], [ 35.561110266000071, 32.12834700600007 ], [ 35.558668496000053, 32.12117823400007 ], [ 35.556063943000026, 32.11387102100008 ], [ 35.551994327000045, 32.106839 ], [ 35.549552558000073, 32.100495928000043 ], [ 35.542227252000032, 32.090980494000064 ], [ 35.537994852000054, 32.080222723000077 ], [ 35.537832067000068, 32.074015741000039 ], [ 35.534576375000029, 32.069739575000028 ], [ 35.530995113000074, 32.064773453000043 ], [ 35.52953005300003, 32.05815153900005 ], [ 35.529692837000027, 32.049321574000032 ], [ 35.53115789800006, 32.03842091000007 ], [ 35.533436883000036, 32.032625092000046 ], [ 35.533612690000041, 32.02542672800007 ], [ 35.534029418000046, 32.021716920000074 ], [ 35.536008880000054, 32.017035282000052 ], [ 35.539134344000047, 32.01376682700004 ], [ 35.543197447000068, 32.010674938000079 ], [ 35.546843822000028, 32.005992735000063 ], [ 35.547260552000068, 32.003607371000044 ], [ 35.546114547000059, 32.000691840000059 ], [ 35.544135087000029, 31.998217985000053 ], [ 35.540592894000042, 31.994507076000048 ], [ 35.538717615000053, 31.98849861900004 ], [ 35.541217987000039, 31.983373448000066 ], [ 35.543093265000039, 31.97754100800006 ], [ 35.545906183000056, 31.972591981000051 ], [ 35.547260552000068, 31.970559268000045 ], [ 35.549344194000071, 31.96684724000005 ], [ 35.551427837000062, 31.962781514000028 ], [ 35.552782205000028, 31.954914706000068 ], [ 35.552365476000034, 31.948992057000055 ], [ 35.550698562000036, 31.939532708000058 ], [ 35.549865104000048, 31.931929161000028 ], [ 35.54830237300007, 31.927773468000055 ], [ 35.546114547000059, 31.922202776000063 ], [ 35.543614176000062, 31.919461519000038 ], [ 35.542155626000067, 31.917073905000052 ], [ 35.53850925100005, 31.913359716000059 ], [ 35.535696333000033, 31.911767875000066 ], [ 35.532466687000067, 31.908053472000063 ], [ 35.531737412000041, 31.904515806000063 ], [ 35.532466687000067, 31.900978004000024 ], [ 35.533195962000036, 31.897086265000041 ], [ 35.534862876000034, 31.892840543000034 ], [ 35.535696333000033, 31.89000995300006 ], [ 35.537779976000024, 31.88461390100008 ], [ 35.539134344000047, 31.881783058000053 ], [ 35.539622698000073, 31.879455288000031 ], [ 35.540762190000066, 31.874617099000034 ], [ 35.542227252000032, 31.871022850000031 ], [ 35.543692313000065, 31.868396196000049 ], [ 35.545320159000028, 31.866737218000026 ], [ 35.54727357400003, 31.864663453000048 ], [ 35.551343189000079, 31.863004408000052 ], [ 35.555250020000074, 31.860377524000057 ], [ 35.556389512000067, 31.858441878000065 ], [ 35.556389512000067, 31.855261800000051 ], [ 35.555575589000057, 31.852496427000062 ], [ 35.553622173000065, 31.849316143000067 ], [ 35.550529266000069, 31.847518543000035 ], [ 35.54890142000005, 31.843231818000049 ], [ 35.549552558000073, 31.839774636000072 ], [ 35.551831543000048, 31.837147092000066 ], [ 35.554273312000078, 31.834242876000076 ], [ 35.555412804000071, 31.832168380000041 ], [ 35.557203435000076, 31.82774263400006 ], [ 35.557203435000076, 31.823040046000074 ], [ 35.553459389000068, 31.815847389000055 ], [ 35.552157112000032, 31.808654172000047 ], [ 35.552157112000032, 31.804780669000024 ], [ 35.554110527000034, 31.794542773000046 ], [ 35.556063943000026, 31.786517682000067 ], [ 35.557203435000076, 31.777938368000036 ], [ 35.561435835000054, 31.76977344200003 ], [ 35.562900896000031, 31.760362125000029 ], [ 35.564854311000033, 31.754687192000063 ], [ 35.562249758000064, 31.750396159000047 ], [ 35.554436096000074, 31.74112130900005 ], [ 35.54890142000005, 31.731153271000039 ], [ 35.539439565000066, 31.714745207000078 ], [ 35.53155468600005, 31.69462059500006 ], [ 35.522906754000076, 31.669512810000072 ], [ 35.508663101000025, 31.634004013000038 ], [ 35.497726010000065, 31.603031005000048 ], [ 35.490136179000046, 31.573737957000048 ], [ 35.488508333000027, 31.536562403000062 ], [ 35.485740994000025, 31.473552120000079 ], [ 35.484927071000072, 31.455362846000071 ], [ 35.48297365600007, 31.419529364000027 ], [ 35.479717965000077, 31.401468544000068 ], [ 35.47434607200006, 31.388684941000065 ], [ 35.468160257000079, 31.370201220000069 ], [ 35.459369889000072, 31.353799085000048 ], [ 35.447161043000051, 31.336420820000058 ], [ 35.435766121000029, 31.319456539000043 ], [ 35.429091953000068, 31.306661781000059 ], [ 35.421603861000051, 31.295951788000025 ], [ 35.413599437000073, 31.279000325000027 ], [ 35.406843240000057, 31.26779096000007 ], [ 35.403266430000031, 31.253862319000064 ], [ 35.40406127600005, 31.241290804000073 ], [ 35.408432933000029, 31.230416794000064 ], [ 35.419560788000069, 31.215123100000028 ], [ 35.435457721000034, 31.194387696000035 ], [ 35.446585574000039, 31.179088175000061 ], [ 35.454931465000072, 31.154263692000029 ], [ 35.456521158000044, 31.139638008000077 ], [ 35.456123735000062, 31.119906767000032 ], [ 35.456123735000062, 31.10289378300007 ], [ 35.453468947000033, 31.092344203000039 ], [ 35.452197192000028, 31.085374031000072 ], [ 35.450416735000033, 31.079928228000028 ], [ 35.445075366000026, 31.069907135000051 ], [ 35.441260102000058, 31.062499562000028 ], [ 35.435155679000047, 31.050515502000053 ], [ 35.428033853000045, 31.040055453000036 ], [ 35.423964238000053, 31.032645555000045 ], [ 35.420657676000076, 31.014554267000051 ], [ 35.420148974000028, 30.999729928000079 ], [ 35.421420729000033, 30.990354524000054 ], [ 35.425235992000069, 30.983594941000035 ], [ 35.427779502000078, 30.976616804000059 ], [ 35.427525151000054, 30.966802936000079 ], [ 35.425235992000069, 30.960696019000068 ], [ 35.421675080000057, 30.952625567000041 ], [ 35.414807604000032, 30.944118136000043 ], [ 35.407431427000063, 30.938882417000059 ], [ 35.397766091000051, 30.932773716000042 ], [ 35.39115296600005, 30.929719219000049 ], [ 35.384031140000047, 30.927101002000029 ], [ 35.373857102000045, 30.922300749000044 ], [ 35.36215696000005, 30.914663488000031 ], [ 35.354526431000068, 30.903970297000058 ], [ 35.347913307000056, 30.893057647000035 ], [ 35.342490545000032, 30.883881329000076 ], [ 35.340211560000057, 30.880109266000034 ], [ 35.335490806000053, 30.874241318000031 ], [ 35.332397899000057, 30.866836014000057 ], [ 35.331583976000047, 30.85901091900007 ], [ 35.331746760000044, 30.848809392000078 ], [ 35.334839668000029, 30.833015846000023 ], [ 35.334676883000043, 30.82337072200005 ], [ 35.332560683000054, 30.818198299000073 ], [ 35.328816638000035, 30.814283849000049 ], [ 35.319212346000029, 30.811208097000076 ], [ 35.311073117000035, 30.806174836000025 ], [ 35.305050086000051, 30.79946341200008 ], [ 35.29935262500004, 30.792471846000069 ], [ 35.294469087000039, 30.787297760000058 ], [ 35.291701749000026, 30.776808894000055 ], [ 35.290887826000073, 30.76701825400005 ], [ 35.29186453300008, 30.750231982000059 ], [ 35.291213395000057, 30.743936376000079 ], [ 35.289911118000077, 30.731343928000058 ], [ 35.287143780000065, 30.722808112000052 ], [ 35.281771887000048, 30.713571787000035 ], [ 35.276888350000036, 30.704754470000069 ], [ 35.273469873000067, 30.696496252000031 ], [ 35.26760962700007, 30.687117417000024 ], [ 35.263377228000024, 30.679557695000028 ], [ 35.25735419800003, 30.67199738000005 ], [ 35.254261290000045, 30.666816822000044 ], [ 35.251656736000029, 30.660935853000069 ], [ 35.251493952000033, 30.653514119000079 ], [ 35.252145090000056, 30.647772386000042 ], [ 35.243517507000035, 30.638248762000046 ], [ 35.237494476000052, 30.634186931000045 ], [ 35.230651011000077, 30.62353011700003 ], [ 35.227421365000055, 30.615730064000047 ], [ 35.223462444000063, 30.610440016000041 ], [ 35.220962072000077, 30.60568769200006 ], [ 35.217732425000065, 30.599410681000052 ], [ 35.213669322000044, 30.592146774000071 ], [ 35.208876943000064, 30.582550409000078 ], [ 35.207830955000077, 30.575077142000055 ], [ 35.205897334000042, 30.570140092000031 ], [ 35.205630627000062, 30.563365592000025 ], [ 35.204963862000056, 30.556877705000034 ], [ 35.204563803000042, 30.549757753000051 ], [ 35.203096917000039, 30.545106536000048 ], [ 35.200429854000049, 30.539363983000044 ], [ 35.198429558000043, 30.535688572000026 ], [ 35.197429409000051, 30.528222464000066 ], [ 35.197362732000045, 30.524087143000031 ], [ 35.195895848000077, 30.518228468000075 ], [ 35.193495491000078, 30.509841909000045 ], [ 35.194095580000067, 30.504269617000034 ], [ 35.192161960000078, 30.497260714000049 ], [ 35.19002830900007, 30.49260698300003 ], [ 35.189428220000025, 30.488585060000048 ], [ 35.186694481000075, 30.479678784000043 ], [ 35.186198407000063, 30.474330029000043 ], [ 35.184832871000026, 30.469659111000055 ], [ 35.183402543000057, 30.464820277000058 ], [ 35.180845434000048, 30.457683210000027 ], [ 35.177426958000069, 30.450807240000074 ], [ 35.172706204000065, 30.446316550000063 ], [ 35.168311020000033, 30.441965997000068 ], [ 35.16486190300003, 30.434932819000039 ], [ 35.164392500000076, 30.433019570000056 ], [ 35.162984291000043, 30.425918147000061 ], [ 35.163837751000074, 30.419073799000046 ], [ 35.16571536400005, 30.412670587000036 ], [ 35.168091717000038, 30.406099038000036 ], [ 35.174292638000054, 30.396150017000025 ], [ 35.179360057000054, 30.386775156000056 ], [ 35.183827388000054, 30.374523215000067 ], [ 35.187894659000051, 30.362729991000037 ], [ 35.191695223000067, 30.35001472700003 ], [ 35.191828576000034, 30.344490840000049 ], [ 35.190761751000025, 30.340175087000034 ], [ 35.189094838000074, 30.331485458000031 ], [ 35.186827834000042, 30.327744652000035 ], [ 35.185294272000078, 30.324349028000029 ], [ 35.181984926000041, 30.319790693000073 ], [ 35.177589743000055, 30.315575028000069 ], [ 35.171729497000058, 30.310094394000032 ], [ 35.167822666000063, 30.306299928000044 ], [ 35.163101913000048, 30.300397135000026 ], [ 35.160497360000079, 30.294353431000047 ], [ 35.157892806000064, 30.286903701000028 ], [ 35.157892806000064, 30.277766468000038 ], [ 35.157730021000077, 30.267222450000077 ], [ 35.155125467000062, 30.260895495000057 ], [ 35.153985975000069, 30.255271194000045 ], [ 35.148451298000055, 30.249646569000049 ], [ 35.146009530000072, 30.244162251000034 ], [ 35.14291662200003, 30.239380801000038 ], [ 35.139986499000031, 30.233473982000078 ], [ 35.137887229000057, 30.226976971000056 ], [ 35.137220464000052, 30.222713659000078 ], [ 35.136753728000031, 30.21712498200003 ], [ 35.136353668000027, 30.214013623000028 ], [ 35.135486872000058, 30.209634507000032 ], [ 35.135753579000038, 30.205255195000063 ], [ 35.137087111000028, 30.200587556000073 ], [ 35.138687348000076, 30.196150213000067 ], [ 35.139020731000073, 30.190387130000033 ], [ 35.140846002000046, 30.182159746000025 ], [ 35.140533456000071, 30.178557347000037 ], [ 35.141054366000049, 30.173964098000056 ], [ 35.142304552000041, 30.168199718000039 ], [ 35.143554738000034, 30.163966287000051 ], [ 35.143450556000062, 30.158831881000026 ], [ 35.143658920000064, 30.154507964000061 ], [ 35.146576020000055, 30.148922624000079 ], [ 35.145950928000047, 30.143517154000051 ], [ 35.146263474000079, 30.139643052000054 ], [ 35.146576020000055, 30.136399501000028 ], [ 35.14803457000005, 30.132615224000062 ], [ 35.148868028000038, 30.128830801000049 ], [ 35.148555480000027, 30.123874790000059 ], [ 35.149503035000066, 30.119495975000063 ], [ 35.149912696000058, 30.118409300000053 ], [ 35.150950503000047, 30.117204494000077 ], [ 35.177936293000073, 30.096592686000065 ], [ 35.151381421000053, 30.116248806000044 ], [ 35.151706991000026, 30.112306043000046 ], [ 35.152195344000063, 30.108926406000023 ], [ 35.153660406000029, 30.104420043000061 ], [ 35.156264960000044, 30.100899304000052 ], [ 35.156916098000067, 30.097941788000071 ], [ 35.153660406000029, 30.09442081800006 ], [ 35.149753575000034, 30.090054642000041 ], [ 35.146172315000058, 30.084420581000074 ], [ 35.143242192000059, 30.080617410000059 ], [ 35.140963207000027, 30.076814091000074 ], [ 35.138521438000055, 30.073433241000032 ], [ 35.135916884000039, 30.070615777000057 ], [ 35.134404270000061, 30.06883072100004 ], [ 35.132335623000074, 30.066389432000051 ], [ 35.128754362000052, 30.05990868400005 ], [ 35.123382470000024, 30.053850211000054 ], [ 35.118824501000063, 30.04934133900008 ], [ 35.115568809000024, 30.045395908000046 ], [ 35.110196917000053, 30.039195627000026 ], [ 35.105638948000035, 30.033699599000045 ], [ 35.100918195000077, 30.028767006000066 ], [ 35.096523011000045, 30.024116052000068 ], [ 35.092290611000067, 30.018337288000055 ], [ 35.091313903000071, 30.011994357000049 ], [ 35.090988334000031, 30.00720165000007 ], [ 35.090337196000064, 30.001703848000034 ], [ 35.089523273000054, 29.99409100400004 ], [ 35.088872134000042, 29.987323541000023 ], [ 35.086267581000072, 29.981119629000034 ], [ 35.083011888000044, 29.969133701000032 ], [ 35.082523534000075, 29.962223509000069 ], [ 35.083825811000054, 29.941066872000079 ], [ 35.084639734000064, 29.919059197000024 ], [ 35.083825811000054, 29.902832474000036 ], [ 35.085290873000076, 29.894788684000048 ], [ 35.084476950000067, 29.88872013200006 ], [ 35.083825811000054, 29.885474010000053 ], [ 35.082686319000061, 29.882651210000063 ], [ 35.081058473000041, 29.880251768000051 ], [ 35.080732904000058, 29.876723070000025 ], [ 35.079918982000038, 29.874041176000048 ], [ 35.077639997000063, 29.870371099000067 ], [ 35.07568658200006, 29.868112524000026 ], [ 35.073733166000068, 29.866418559000067 ], [ 35.070803043000069, 29.86345405000003 ], [ 35.068849628000066, 29.858371830000067 ], [ 35.063803306000068, 29.851171577000059 ], [ 35.061035968000056, 29.848065424000026 ], [ 35.058105845000057, 29.844253196000068 ], [ 35.053547876000039, 29.838463979000039 ], [ 35.05094332200008, 29.832956851000063 ], [ 35.047850414000038, 29.826884537000069 ], [ 35.045408646000055, 29.820670626000037 ], [ 35.044594723000046, 29.812196487000051 ], [ 35.044822736000071, 29.808011688000079 ], [ 35.044310659000075, 29.804049699000075 ], [ 35.044097294000039, 29.800494885000035 ], [ 35.043286507000062, 29.796236346000057 ], [ 35.042689085000063, 29.788755693000041 ], [ 35.042177009000056, 29.78642250300004 ], [ 35.039829994000058, 29.784015188000069 ], [ 35.038336439000034, 29.782385587000078 ], [ 35.037226940000039, 29.780681885000035 ], [ 35.034197157000051, 29.776385465000033 ], [ 35.03236221700007, 29.77371862900003 ], [ 35.030744845000072, 29.770020371000044 ], [ 35.029071062000071, 29.764490643000045 ], [ 35.02753750100004, 29.759397060000026 ], [ 35.026003940000066, 29.753898015000061 ], [ 35.024136995000049, 29.749035450000065 ], [ 35.021642094000072, 29.740137323000056 ], [ 35.017898048000063, 29.72925329900005 ], [ 35.015944632000071, 29.723457427000028 ], [ 35.014805140000078, 29.717378470000028 ], [ 35.013665649000075, 29.707198928000025 ], [ 35.012526156000035, 29.700836190000075 ], [ 35.012363372000038, 29.694755863000069 ], [ 35.014642355000035, 29.685281133000046 ], [ 35.015944632000071, 29.677926996000053 ], [ 35.016802573000064, 29.671723759000031 ], [ 35.01773604400006, 29.66587228700007 ], [ 35.018669516000045, 29.657644891000075 ], [ 35.018602840000028, 29.652314107000052 ], [ 35.01773604400006, 29.648141992000035 ], [ 35.015935777000038, 29.644317400000034 ], [ 35.013935480000043, 29.638406383000074 ], [ 35.010134916000027, 29.633712092000053 ], [ 35.006267674000071, 29.629133500000023 ], [ 35.003933994000079, 29.625829828000064 ], [ 35.00180034400006, 29.623163629000032 ], [ 34.99919995700003, 29.618700486000023 ], [ 34.99786642600003, 29.615744269000061 ], [ 34.996666247000064, 29.613019835000046 ], [ 34.994799304000026, 29.609367819000056 ], [ 34.992332270000077, 29.605077981000079 ], [ 34.991265445000067, 29.602527179000049 ], [ 34.98966520700003, 29.59870085600005 ], [ 34.987464880000061, 29.593366952000054 ], [ 34.984997847000045, 29.589946147000035 ], [ 34.982072413000026, 29.584448700000053 ], [ 34.980613862000041, 29.579556192000041 ], [ 34.97957204100004, 29.574210402000062 ], [ 34.978738583000052, 29.568773716000067 ], [ 34.978426037000077, 29.563517974000035 ], [ 34.978217673000074, 29.556177602000048 ], [ 34.978217673000074, 29.550649314000054 ], [ 34.977905127000042, 29.547205310000038 ], [ 34.978217673000074, 29.542310998000062 ], [ 34.979884588000061, 29.541676532000054 ], [ 34.981759866000061, 29.541495256000076 ], [ 34.987281520000067, 29.540770147000046 ], [ 34.988114977000066, 29.540588869000032 ], [ 34.990615348000063, 29.538957350000032 ], [ 34.991761352000026, 29.536872594000045 ], [ 34.994886817000065, 29.534515862000035 ], [ 34.994939530000067, 29.534492670000077 ], [ 34.996553731000063, 29.533700058000079 ], [ 34.998845738000057, 29.533156184000063 ], [ 35.000512653000044, 29.532612308000068 ], [ 35.00197120200005, 29.532068429000049 ], [ 35.003325570000072, 29.530980661000058 ], [ 35.004784120000068, 29.529348989000027 ], [ 35.006242670000063, 29.527717289000066 ], [ 35.007701220000058, 29.525360343000045 ], [ 35.008534677000057, 29.523365962000071 ], [ 35.008430495000027, 29.520918258000052 ], [ 35.008117949000052, 29.517926540000076 ], [ 35.007284492000053, 29.514390759000037 ], [ 35.005409213000064, 29.512033503000055 ], [ 35.004263210000033, 29.509948192000024 ], [ 35.003533934000075, 29.508225512000024 ], [ 35.003685957000073, 29.504448714000034 ], [ 35.003856649000056, 29.503743069000052 ], [ 35.003728630000069, 29.502480324000032 ], [ 35.003600611000024, 29.50188608600007 ], [ 35.00296051600003, 29.500437616000056 ], [ 35.002320421000036, 29.49954623900004 ], [ 35.001338942000075, 29.49854343100003 ], [ 35.000442809000049, 29.497540613000069 ], [ 34.999802713000065, 29.495943512000053 ], [ 34.999930732000053, 29.494532098000036 ], [ 34.999888059000057, 29.493194953000057 ], [ 34.999333310000054, 29.491263489000062 ], [ 34.998949254000024, 29.490409175000025 ], [ 34.998266485000045, 29.48951771000003 ], [ 34.997711736000042, 29.488886251000054 ], [ 34.996218181000074, 29.487400449000063 ], [ 34.995322048000048, 29.486397521000072 ], [ 34.994852645000037, 29.484985975000029 ], [ 34.994865980000043, 29.483669598000063 ], [ 34.994332568000061, 29.48181224700005 ], [ 34.994265890000065, 29.480767471000036 ], [ 34.993665801000077, 29.479316378000078 ], [ 34.993132389000039, 29.47838766700005 ], [ 34.991732181000032, 29.476472173000047 ], [ 34.991265445000067, 29.475543436000066 ], [ 34.990865385000063, 29.473627888000067 ], [ 34.990331973000025, 29.472118643000044 ], [ 34.989331824000033, 29.470609376000027 ], [ 34.987398204000044, 29.468345433000025 ], [ 34.986664761000043, 29.467474673000027 ], [ 34.985464583000066, 29.466139491000035 ], [ 34.984264405000033, 29.464920398000061 ], [ 34.983264256000041, 29.463933502000032 ], [ 34.982330785000045, 29.462946596000052 ], [ 34.981864048000034, 29.461843572000078 ], [ 34.98166401800006, 29.46079859200006 ], [ 34.981263959000046, 29.459521379000023 ], [ 34.981063929000072, 29.458302205000052 ], [ 34.980997253000055, 29.456676619000064 ], [ 34.981330635000063, 29.455341295000039 ], [ 34.98139731200007, 29.454470423000032 ], [ 34.981325301000027, 29.452329206000059 ], [ 34.981069263000052, 29.450545599000066 ], [ 34.980514514000049, 29.448910597000065 ], [ 34.979703727000071, 29.447089770000048 ], [ 34.978978286000029, 29.445974961000047 ], [ 34.978210172000047, 29.445045945000061 ], [ 34.976887309000062, 29.444191242000045 ], [ 34.975991176000036, 29.443559501000038 ], [ 34.975223062000055, 29.442221682000024 ], [ 34.97496702400008, 29.441032495000059 ], [ 34.974668312000063, 29.439880458000061 ], [ 34.974454947000027, 29.439062874000058 ], [ 34.974454947000027, 29.437947977000078 ], [ 34.974710985000058, 29.43620128200007 ], [ 34.974881678000031, 29.435235011000032 ], [ 34.97506303800003, 29.434380225000041 ], [ 34.975596450000069, 29.433218821000025 ], [ 34.976063187000079, 29.432696185000054 ], [ 34.976463246000037, 29.432347758000049 ], [ 34.97746339400004, 29.430431396000074 ], [ 34.978130160000035, 29.429269945000044 ], [ 34.978530219000049, 29.428108483000074 ], [ 34.978863603000036, 29.426714709000066 ], [ 34.97879692500004, 29.425611292000042 ], [ 34.978530219000049, 29.424101333000067 ], [ 34.977863454000044, 29.422881734000043 ], [ 34.977196688000049, 29.421720199000049 ], [ 34.976463246000037, 29.420732882000038 ], [ 34.975863157000049, 29.420035947000031 ], [ 34.975263067000071, 29.41864206300005 ], [ 34.975129714000047, 29.416841602000034 ], [ 34.975263067000071, 29.415738077000071 ], [ 34.975529773000062, 29.414692621000029 ], [ 34.975929834000056, 29.413879482000027 ], [ 34.977196688000049, 29.412078936000057 ], [ 34.978196836000052, 29.411033443000065 ], [ 34.978530219000049, 29.410162190000051 ], [ 34.97879692500004, 29.407896899000036 ], [ 34.978596896000056, 29.406735192000042 ], [ 34.978063483000028, 29.405399211000031 ], [ 34.976596599000061, 29.403133814000057 ], [ 34.975129714000047, 29.402146317000074 ], [ 34.973596153000074, 29.400577921000036 ], [ 34.972591837000039, 29.399456066000027 ], [ 34.970508195000036, 29.397459208000043 ], [ 34.969362190000027, 29.396551531000057 ], [ 34.967070184000079, 29.394736155000032 ], [ 34.965507451000065, 29.393465373000026 ], [ 34.964778176000038, 29.391377624000029 ], [ 34.964569812000036, 29.390288347000023 ], [ 34.964569812000036, 29.389289832000031 ], [ 34.965403269000035, 29.387837430000047 ], [ 34.966132544000061, 29.387292774000059 ], [ 34.967070184000079, 29.385931121000056 ], [ 34.967695277000075, 29.385114120000026 ], [ 34.967695277000075, 29.384569450000072 ], [ 34.966861820000076, 29.382753860000037 ], [ 34.966757638000047, 29.382481518000077 ], [ 34.964361448000034, 29.380756673000064 ], [ 34.963319626000043, 29.380302761000053 ], [ 34.962381987000072, 29.377306895000061 ], [ 34.962277805000042, 29.37521881400005 ], [ 34.962277805000042, 29.373493847000077 ], [ 34.962277805000042, 29.371859639000036 ], [ 34.961756894000075, 29.370497779000061 ], [ 34.960506709000072, 29.368318766000073 ], [ 34.959256523000079, 29.367047653000043 ], [ 34.957693791000054, 29.365685730000052 ], [ 34.958006337000029, 29.364051397000026 ], [ 34.959256523000079, 29.363234221000027 ], [ 34.960610891000044, 29.362053843000069 ], [ 34.960923437000076, 29.36123665100007 ], [ 34.960610891000044, 29.359420644000068 ], [ 34.959777433000056, 29.356787378000035 ], [ 36.072336779000068, 29.184136630000069 ], [ 36.505586527000048, 29.500699775000044 ], [ 36.755707908000034, 29.867452987000036 ], [ 37.505760902000077, 30.000763272000029 ], [ 37.672370453000042, 30.334068257000069 ], [ 38.005880638000065, 30.50069084900008 ], [ 37.005698070000051, 31.500797982000051 ], [ 38.918675305000079, 31.978928600000074 ], [ 38.923074608000036, 31.980103793000069 ], [ 39.005899414000055, 32.000956892000033 ], [ 39.019651212000042, 32.01122566500004 ], [ 39.265599457000064, 32.203034129000059 ], [ 39.301900423000063, 32.230853883000066 ], [ 39.302388777000033, 32.234020939000061 ], [ 39.30043536200003, 32.244760568000061 ], [ 39.298644731000024, 32.253571623000028 ], [ 39.297179669000059, 32.26362068800006 ], [ 39.293110054000067, 32.274081548000026 ], [ 39.287738163000029, 32.287155925000036 ], [ 39.280087286000025, 32.297063671000046 ], [ 39.268366795000077, 32.308621340000059 ], [ 39.259901995000064, 32.317426194000063 ], [ 39.25176276600007, 32.324854623000078 ], [ 39.243786320000027, 32.32966902000004 ], [ 39.234888488000024, 32.333210878000045 ], [ 39.222298117000037, 32.335870403000058 ], [ 39.211710759000027, 32.335749518000057 ], [ 39.194112853000036, 32.335145086000068 ], [ 39.177230309000038, 32.334540650000065 ], [ 39.164926082000079, 32.333694434000051 ], [ 39.152764928000067, 32.332364648000066 ], [ 39.144323657000029, 32.331034844000044 ], [ 39.137456181000061, 32.329946807000056 ], [ 39.128013402000079, 32.329705020000063 ], [ 39.123005868000064, 32.329705020000063 ], [ 39.112132365000036, 32.330188594000049 ], [ 39.108984772000042, 32.330188594000049 ], [ 39.097109763000049, 32.330067701000075 ], [ 39.087237767000033, 32.330672167000046 ], [ 39.082516378000037, 32.330551273000026 ], [ 39.076936554000042, 32.33079305900003 ] ] ] } } +] +} diff --git a/data/boundaries/jordan_adm1.geojson b/data/boundaries/jordan_adm1.geojson new file mode 100644 index 0000000..9efc71e --- /dev/null +++ b/data/boundaries/jordan_adm1.geojson @@ -0,0 +1,18 @@ +{ +"type": "FeatureCollection", +"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, +"features": [ +{ "type": "Feature", "properties": { "shapeName": "Ma'an", "shapeISO": "JO-MN", "shapeID": "50493656B90517147106903", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.737249712104585, 29.236882253113549 ], [ 36.071699543798957, 29.18380698730266 ], [ 36.137363223733814, 29.229895693531489 ], [ 36.404079614582599, 29.420529256719874 ], [ 36.519160291814046, 29.50304598088735 ], [ 36.648456816129226, 29.699047716079292 ], [ 36.758121931581911, 29.867667953912985 ], [ 36.926004329636157, 29.899362638475054 ], [ 37.23062964933888, 29.954510822716372 ], [ 37.501407711296906, 30.00259384572945 ], [ 37.573840843680046, 30.152556754690522 ], [ 37.66252065870151, 30.338521684428258 ], [ 37.70990681954413, 30.362472662083746 ], [ 38.003024071703578, 30.502555794414434 ], [ 37.877112272713248, 30.636030623814293 ], [ 37.604980320085758, 30.917528977780137 ], [ 37.351125887449825, 31.169823974297003 ], [ 37.245789602907905, 31.268742117554723 ], [ 37.088362856060996, 31.264953442847172 ], [ 37.001713875694861, 31.265323770175883 ], [ 36.803287712158237, 31.266805062403762 ], [ 36.62262458895367, 31.269026958027723 ], [ 36.466656425553651, 31.273100296941209 ], [ 36.344048118825697, 31.273840885048855 ], [ 36.143044667377524, 31.27410749536466 ], [ 36.144819238417199, 31.239368342175283 ], [ 36.14765855280001, 31.183516210005166 ], [ 36.176406604181466, 31.157248241513173 ], [ 36.223965110201732, 31.114414324761356 ], [ 36.185456917202998, 31.050735316381804 ], [ 36.146593809456817, 30.983210315004101 ], [ 36.093356676469512, 30.892950325497168 ], [ 36.045798170449245, 30.810988156578219 ], [ 36.027751704756952, 30.779632093164281 ], [ 36.006047778082518, 30.741921124560292 ], [ 35.961860957217482, 30.668378173014332 ], [ 35.94588981696154, 30.638914764904541 ], [ 35.930096134529037, 30.645021908034664 ], [ 35.911108223865483, 30.653571260905039 ], [ 35.897976397093089, 30.658456266743372 ], [ 35.88448965737183, 30.661967211018009 ], [ 35.866743946076326, 30.661051325258484 ], [ 35.855564148166934, 30.657998307675825 ], [ 35.848288406185077, 30.649754679335047 ], [ 35.840835208178362, 30.640594267711322 ], [ 35.832317266828454, 30.634334154397777 ], [ 35.792744330486528, 30.628989835112861 ], [ 35.746073110885391, 30.621507291328498 ], [ 35.709694402774517, 30.619063886389313 ], [ 35.695142919710008, 30.616773138669487 ], [ 35.685915149764412, 30.610664212183679 ], [ 35.677219751490384, 30.602874772053156 ], [ 35.671363666699904, 30.600278152314957 ], [ 35.662490811501812, 30.600125407861356 ], [ 35.653617956303719, 30.603638470039414 ], [ 35.646342214321805, 30.607762336462713 ], [ 35.629838703293558, 30.61188602841753 ], [ 35.609963507110194, 30.613107828463569 ], [ 35.589201024507702, 30.611275121649612 ], [ 35.549273175216911, 30.609289650596963 ], [ 35.515733780589528, 30.608678727641234 ], [ 35.504376525756129, 30.609900569056094 ], [ 35.490357414363245, 30.614024169280015 ], [ 35.472789159991805, 30.61814759323687 ], [ 35.465335961085771, 30.619980170548502 ], [ 35.460367162714419, 30.618605741162071 ], [ 35.456208011390686, 30.616095448246369 ], [ 35.455891235991771, 30.616103967524111 ], [ 35.457655899200461, 30.606032646989092 ], [ 35.458441894078192, 30.586818229477785 ], [ 35.458913492263889, 30.567058588083398 ], [ 35.459070691059594, 30.55866629011723 ], [ 35.458284695282487, 30.551627028464623 ], [ 35.454197521198694, 30.543098008366428 ], [ 35.435333636937855, 30.504369546217617 ], [ 35.433918845977985, 30.493398192272821 ], [ 35.434862039651478, 30.46860650228831 ], [ 35.434704840855773, 30.459528185277577 ], [ 35.411910981306789, 30.421037566830307 ], [ 35.380313976608761, 30.366257136957358 ], [ 35.368052452558686, 30.345367403882619 ], [ 35.386130341042474, 30.286743836358994 ], [ 35.39606335484001, 30.252632408159172 ], [ 35.397291471724088, 30.243720755308686 ], [ 35.397537095460621, 30.229715095075619 ], [ 35.397537095460621, 30.223135990433661 ], [ 35.380589074726061, 30.198088921766384 ], [ 35.359711078703356, 30.171761404665119 ], [ 35.348903645986525, 30.161355850192365 ], [ 35.335148730229776, 30.148612857897149 ], [ 35.323850050939143, 30.136080644206402 ], [ 35.318200710394535, 30.126308661215774 ], [ 35.315253228253937, 30.113561143532024 ], [ 35.312551369849871, 30.103361943898619 ], [ 35.312060123276126, 30.09273665986899 ], [ 35.31107763012858, 30.082747850333078 ], [ 35.308130147987981, 30.071695227352905 ], [ 35.304200171800517, 30.061066539389344 ], [ 35.301989560869572, 30.0514997439181 ], [ 35.301252689659975, 30.043845643661598 ], [ 35.301252689659975, 30.034915111343366 ], [ 35.302235183706841, 30.023644481907354 ], [ 35.305919536157717, 30.011734500147099 ], [ 35.312060123276126, 29.998121340927185 ], [ 35.324586920350157, 29.981102265657114 ], [ 35.33735934206004, 29.96620818226188 ], [ 35.34497367069838, 29.96173952206135 ], [ 35.3560267271518, 29.95492974760981 ], [ 35.374939734181453, 29.949609288238094 ], [ 35.393607119273213, 29.948332334569614 ], [ 35.412028881527704, 29.948757988190664 ], [ 35.427503160742333, 29.954291308097424 ], [ 35.441749322173507, 29.957057852038304 ], [ 35.475399739906152, 29.957696275362878 ], [ 35.504874558614063, 29.949822111900971 ], [ 35.530173776498657, 29.940031741371797 ], [ 35.554981748708769, 29.927047374636686 ], [ 35.565052311115323, 29.91959656253141 ], [ 35.572666639753663, 29.911719382743343 ], [ 35.581017837803017, 29.902138190924802 ], [ 35.586667178347682, 29.895111396573725 ], [ 35.590842777372302, 29.888297063458765 ], [ 35.596983364490711, 29.874666998783027 ], [ 35.601158963515388, 29.861674109172839 ], [ 35.60484331596632, 29.846549107755152 ], [ 35.606071432850399, 29.839092278286046 ], [ 35.608527668417196, 29.827586361921135 ], [ 35.611229526821262, 29.81927571070554 ], [ 35.614913878372818, 29.813095547121861 ], [ 35.619580723971296, 29.808406892963774 ], [ 35.629896911013702, 29.800520932195298 ], [ 35.63726561591551, 29.791994870866631 ], [ 35.642178085250464, 29.783468081986427 ], [ 35.647581802058596, 29.771529358792918 ], [ 35.651511777346684, 29.754898049605345 ], [ 35.654950506061084, 29.740183437615599 ], [ 35.662319210962892, 29.709041054601016 ], [ 35.668214174344712, 29.687918461867582 ], [ 35.674109138625909, 29.673834265638902 ], [ 35.679021607960863, 29.660388419889728 ], [ 35.68319720698554, 29.645659955642486 ], [ 35.68663593569994, 29.62794025274053 ], [ 35.703338332697967, 29.53117419523295 ], [ 35.707130146039447, 29.506781148631148 ], [ 35.715957239235252, 29.443299641265469 ], [ 35.726319479660333, 29.331944149303126 ], [ 35.737249712104585, 29.236882253113549 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Karak", "shapeISO": "JO-KA", "shapeID": "50493656B94904250637342", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 36.143044667377524, 31.27410749536466 ], [ 36.02876228774943, 31.274410838489473 ], [ 35.904364853555194, 31.272135746167805 ], [ 35.872600030866806, 31.270922341293044 ], [ 35.845449092701529, 31.272590768948874 ], [ 35.829300495521522, 31.277899205284143 ], [ 35.826638638962095, 31.282904029597319 ], [ 35.825218981770661, 31.289425067712784 ], [ 35.82504152484654, 31.299888116743261 ], [ 35.826461182037974, 31.30655959974581 ], [ 35.830720152712956, 31.320204342256659 ], [ 35.837286065199805, 31.336575424516298 ], [ 35.840302836506737, 31.34976117014196 ], [ 35.838883179315303, 31.383399178129594 ], [ 35.834446751716257, 31.393851781534522 ], [ 35.824509153174915, 31.410210043059067 ], [ 35.810490041782032, 31.424596896229843 ], [ 35.797713129757199, 31.428685388719771 ], [ 35.7703847346678, 31.437164657423068 ], [ 35.747670225000945, 31.44004137730775 ], [ 35.720696743759788, 31.441555405757413 ], [ 35.702951032464227, 31.439738569279598 ], [ 35.688222092475655, 31.435347735509652 ], [ 35.670653839003535, 31.426565451934096 ], [ 35.658054383902765, 31.424899753720695 ], [ 35.644922557130371, 31.426262599839163 ], [ 35.630548531889303, 31.431410951454325 ], [ 35.606591821955078, 31.440192781771486 ], [ 35.585829339352586, 31.448671009059865 ], [ 35.56293737276161, 31.454726415092011 ], [ 35.545191661466049, 31.45745122059742 ], [ 35.518928008820581, 31.457299844911972 ], [ 35.498875355713153, 31.454726415092011 ], [ 35.471398265817356, 31.452753351985677 ], [ 35.470903678262175, 31.438196123152636 ], [ 35.465635420038666, 31.422107749972724 ], [ 35.459258054915381, 31.404360019699197 ], [ 35.457317118290405, 31.393709770489579 ], [ 35.455930734216054, 31.373115862207328 ], [ 35.442066897969028, 31.357489885349992 ], [ 35.43125310524664, 31.343755823072854 ], [ 35.41849837500007, 31.326466997054297 ], [ 35.408793689177458, 31.304199995433521 ], [ 35.400752663704509, 31.287140859862859 ], [ 35.397702620179814, 31.272211583297974 ], [ 35.397979896455126, 31.259413180174192 ], [ 35.39881172707959, 31.246613042258161 ], [ 35.405189092202875, 31.23499659921373 ], [ 35.417943821550182, 31.221244678199412 ], [ 35.431530381521952, 31.211047997567107 ], [ 35.442621451418916, 31.198241305392003 ], [ 35.449830646267344, 31.18306075824745 ], [ 35.45509890449091, 31.169064035476879 ], [ 35.459258054915381, 31.144149496302248 ], [ 35.458980778640068, 31.12967232781574 ], [ 35.455653457940798, 31.120652647501743 ], [ 35.450662476891864, 31.111157320254165 ], [ 35.447057879017962, 31.099286825926299 ], [ 35.442621451418916, 31.084090428230752 ], [ 35.437353193195349, 31.069366600887975 ], [ 35.426816677647594, 31.057253355258183 ], [ 35.416280161200518, 31.049889648788337 ], [ 35.411289180151584, 31.040862392585382 ], [ 35.408793689177458, 31.019003385497911 ], [ 35.409348242627345, 31.001179830684691 ], [ 35.407130028827794, 30.978360818896704 ], [ 35.403802708128524, 30.960291896653757 ], [ 35.396316236105463, 30.949591582185803 ], [ 35.378015972259391, 30.935798296853989 ], [ 35.366093071737907, 30.922478752792244 ], [ 35.365270037382345, 30.921452882644473 ], [ 35.374812011565155, 30.918338695874183 ], [ 35.382671963040707, 30.914967108745145 ], [ 35.389588719943504, 30.910921046269323 ], [ 35.396033879559923, 30.906335303331616 ], [ 35.403107836157744, 30.900130712362511 ], [ 35.409867394264893, 30.895544451415333 ], [ 35.418356142721848, 30.892306958599306 ], [ 35.428731277626412, 30.890553270716907 ], [ 35.438792015838885, 30.890013668496067 ], [ 35.44759516098793, 30.891362669551597 ], [ 35.454511918790047, 30.893655927279269 ], [ 35.459542287446652, 30.898781834514125 ], [ 35.462057472674303, 30.904446992334897 ], [ 35.462529069061361, 30.911460531578314 ], [ 35.462686268756329, 30.930070894256403 ], [ 35.462057472674303, 30.945846409484261 ], [ 35.469131428372748, 30.957305619558724 ], [ 35.477148578644062, 30.968898246756737 ], [ 35.478406170808171, 30.975233156684908 ], [ 35.475576588888543, 30.983050125063301 ], [ 35.473690200642295, 30.989114574677956 ], [ 35.473847399438, 30.996256653122089 ], [ 35.476048186174921, 31.001242315580441 ], [ 35.481707350913553, 31.004206640224311 ], [ 35.492082486717436, 31.00461085940367 ], [ 35.49978523939734, 31.003667679220086 ], [ 35.507802389668598, 31.002320262769956 ], [ 35.518649122758859, 31.003398197368938 ], [ 35.525094283274598, 31.005149815012032 ], [ 35.532797035954502, 31.00622771813471 ], [ 35.539713792857299, 31.005823505250646 ], [ 35.547259345842178, 30.997065157131374 ], [ 35.558577677118137, 30.989249336287912 ], [ 35.569110010818406, 30.985341184847869 ], [ 35.589860283325493, 30.981837189634632 ], [ 35.606680578745738, 30.980085143914323 ], [ 35.628845643112015, 30.979815595513401 ], [ 35.652897093925787, 30.98237627474532 ], [ 35.662014637565505, 30.984128278197545 ], [ 35.674433361310605, 30.98426304610274 ], [ 35.683079307663945, 30.98291535535941 ], [ 35.696284026286833, 30.976850512741009 ], [ 35.70917434641899, 30.970111346761314 ], [ 35.719549483122194, 30.963641299306573 ], [ 35.731496608681596, 30.958518867951454 ], [ 35.753976070639226, 30.950699889588293 ], [ 35.781171501863355, 30.937217390170474 ], [ 35.792018234953616, 30.931554173986001 ], [ 35.800035385224874, 30.92872243908937 ], [ 35.825816026388566, 30.926295171584968 ], [ 35.835405167314661, 30.923598135345742 ], [ 35.838549147725018, 30.919552438894016 ], [ 35.840278337175562, 30.914562510051837 ], [ 35.842321924217458, 30.909167700129331 ], [ 35.844051114567321, 30.905121393037916 ], [ 35.848609885937549, 30.900670257926095 ], [ 35.85426905067618, 30.897837609318287 ], [ 35.85914222053708, 30.895274664694057 ], [ 35.866844973216985, 30.893251238653818 ], [ 35.877691706307246, 30.887180705125502 ], [ 35.885708856578503, 30.881514526574222 ], [ 35.889481633970263, 30.87625277404635 ], [ 35.893568808054113, 30.873419403282867 ], [ 35.901743158020395, 30.872474928075519 ], [ 35.908659914923192, 30.87207014951781 ], [ 35.914319080561143, 30.868831864399056 ], [ 35.916834263990154, 30.860735670015231 ], [ 35.923436623301598, 30.853988319305529 ], [ 35.929095788939549, 30.847510416272769 ], [ 35.937741736192208, 30.841841893188871 ], [ 35.947330876219041, 30.835363169075038 ], [ 35.959120802982738, 30.828074083851959 ], [ 35.96965313848159, 30.823484374004693 ], [ 35.977670288752847, 30.81929944901043 ], [ 35.993075794112656, 30.807283649420924 ], [ 36.005808915449165, 30.796211582198794 ], [ 36.027751704756952, 30.779632093164281 ], [ 36.045798170449245, 30.810988156578219 ], [ 36.093356676469512, 30.892950325497168 ], [ 36.146593809456817, 30.983210315004101 ], [ 36.185456917202998, 31.050735316381804 ], [ 36.223965110201732, 31.114414324761356 ], [ 36.176406604181466, 31.157248241513173 ], [ 36.14765855280001, 31.183516210005166 ], [ 36.144819238417199, 31.239368342175283 ], [ 36.143044667377524, 31.27410749536466 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Madaba", "shapeISO": "JO-MD", "shapeID": "50493656B40052368003294", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.810490041782032, 31.424596896229843 ], [ 35.828058296153472, 31.441404003991636 ], [ 35.83781843687143, 31.451850145767651 ], [ 35.843851978585974, 31.469409151511172 ], [ 35.848110949260956, 31.484089584766593 ], [ 35.860000575766037, 31.509358748207717 ], [ 35.866566489152206, 31.527814539009796 ], [ 35.869938174307379, 31.536738572826948 ], [ 35.874197144982304, 31.543393228614661 ], [ 35.855031776495366, 31.559725372927687 ], [ 35.858226004726362, 31.570158301864183 ], [ 35.861952603729719, 31.576659392117278 ], [ 35.861242775134031, 31.589811373596092 ], [ 35.851305177492009, 31.605530846671286 ], [ 35.839770464835112, 31.614598566970358 ], [ 35.824154239326731, 31.620945445076302 ], [ 35.81439409860883, 31.624269827690455 ], [ 35.806231071107106, 31.631824801073776 ], [ 35.802859385951933, 31.638019421259344 ], [ 35.799487700796817, 31.649047845281871 ], [ 35.796825844237389, 31.65780922231778 ], [ 35.793809073829721, 31.66702288279987 ], [ 35.792211959714223, 31.677443791397934 ], [ 35.792744330486528, 31.690128535503561 ], [ 35.795228730121835, 31.700395868674434 ], [ 35.798068044504703, 31.706434945716239 ], [ 35.805521242511361, 31.713530358339426 ], [ 35.815103926305198, 31.718511919889238 ], [ 35.822202211362992, 31.724096988585188 ], [ 35.824331696250852, 31.732700353838311 ], [ 35.821847296615488, 31.747037522163964 ], [ 35.819362896980181, 31.764390071444666 ], [ 35.817410869016442, 31.782342762608437 ], [ 35.817588325940562, 31.79184571790563 ], [ 35.817943240688066, 31.804816429334778 ], [ 35.816523583496632, 31.815221847110593 ], [ 35.81350681308902, 31.820650294375639 ], [ 35.810312584857968, 31.823213617614385 ], [ 35.806231071107106, 31.824118302317856 ], [ 35.798422958352887, 31.823816741649352 ], [ 35.794518901526146, 31.820650294375639 ], [ 35.791502131118534, 31.816277402979836 ], [ 35.78795298903924, 31.813864684707482 ], [ 35.781919447324697, 31.811904304739926 ], [ 35.772869134303164, 31.811451903482634 ], [ 35.75867256508684, 31.811904304739926 ], [ 35.748734967444818, 31.812658301739305 ], [ 35.734538398228551, 31.812959899279974 ], [ 35.720164372088163, 31.809491472253683 ], [ 35.707032546215089, 31.802554226996051 ], [ 35.698514604865181, 31.798180479445648 ], [ 35.694668277319181, 31.797696175638066 ], [ 35.684140578724794, 31.796370592029234 ], [ 35.670476381180094, 31.795918114329538 ], [ 35.657876926978645, 31.796521417329586 ], [ 35.649004070881233, 31.796672241730619 ], [ 35.641373415051135, 31.79606894052921 ], [ 35.635872245008159, 31.793203203165319 ], [ 35.63303293152461, 31.788074820996258 ], [ 35.62824158917806, 31.78415292521737 ], [ 35.623805161579014, 31.782342762608437 ], [ 35.621498218867771, 31.779627453044554 ], [ 35.619191276156528, 31.773442283834356 ], [ 35.617061791268725, 31.736020738066657 ], [ 35.615642134077291, 31.727719554913563 ], [ 35.611383163402309, 31.721530917018242 ], [ 35.606591821955078, 31.71805906177633 ], [ 35.599138623049043, 31.713832278736731 ], [ 35.589910853103447, 31.709303369355041 ], [ 35.573229885151136, 31.705076187915779 ], [ 35.562227544165864, 31.702811546615635 ], [ 35.552604112989457, 31.701867503982157 ], [ 35.539084995875896, 31.70173376040475 ], [ 35.52084990859646, 31.701065037121793 ], [ 35.504454163329001, 31.701603715738941 ], [ 35.501126842629731, 31.694290339827376 ], [ 35.491144879632543, 31.671166844574259 ], [ 35.482272024434451, 31.649689871290605 ], [ 35.480053810634899, 31.635526514037451 ], [ 35.477003766210885, 31.60837404972267 ], [ 35.47395372268619, 31.587118770115183 ], [ 35.472844615786414, 31.567276132987217 ], [ 35.470349124812287, 31.546247779311614 ], [ 35.469794571362456, 31.529232609797134 ], [ 35.468685464462681, 31.495429399047566 ], [ 35.469794571362456, 31.481242592871411 ], [ 35.471458231712063, 31.45451826700446 ], [ 35.471398265817356, 31.452753351985677 ], [ 35.498875355713153, 31.454726415092011 ], [ 35.518928008820581, 31.457299844911972 ], [ 35.545191661466049, 31.45745122059742 ], [ 35.56293737276161, 31.454726415092011 ], [ 35.585829339352586, 31.448671009059865 ], [ 35.606591821955078, 31.440192781771486 ], [ 35.630548531889303, 31.431410951454325 ], [ 35.644922557130371, 31.426262599839163 ], [ 35.658054383902765, 31.424899753720695 ], [ 35.670653839003535, 31.426565451934096 ], [ 35.688222092475655, 31.435347735509652 ], [ 35.702951032464227, 31.439738569279598 ], [ 35.720696743759788, 31.441555405757413 ], [ 35.747670225000945, 31.44004137730775 ], [ 35.7703847346678, 31.437164657423068 ], [ 35.797713129757199, 31.428685388719771 ], [ 35.810490041782032, 31.424596896229843 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Balqa", "shapeISO": "JO-BA", "shapeID": "50493656B62478729305943", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.694668277319181, 31.797696175638066 ], [ 35.694083239549911, 31.808266591130348 ], [ 35.694083239549911, 31.822826792222713 ], [ 35.696598423878186, 31.832176168495437 ], [ 35.700214001574977, 31.840055622668899 ], [ 35.707287958172799, 31.846064923157712 ], [ 35.713418720197808, 31.849670316032302 ], [ 35.715305108444056, 31.857014197846979 ], [ 35.713890317484243, 31.863422925927352 ], [ 35.707916754254882, 31.870231711124632 ], [ 35.69942800669719, 31.876906502732993 ], [ 35.689367268484716, 31.880777660560625 ], [ 35.679778127558563, 31.881845537141885 ], [ 35.670503385123197, 31.882646437383244 ], [ 35.661385841483423, 31.886116921159044 ], [ 35.653211491517197, 31.889053383007251 ], [ 35.648967117738323, 31.893457899062867 ], [ 35.647709525574214, 31.901599027173404 ], [ 35.653211491517197, 31.915877626251529 ], [ 35.658399059868771, 31.922815958789499 ], [ 35.672704170960799, 31.928953277771598 ], [ 35.72568024424794, 31.949763744601171 ], [ 35.762464817297541, 31.965368501954856 ], [ 35.781014303067707, 31.977637047911458 ], [ 35.789031453338964, 31.984170712508444 ], [ 35.791232239176566, 31.98963729822276 ], [ 35.792804229831404, 31.998036539854468 ], [ 35.793275827117782, 32.00776803266865 ], [ 35.7948478168733, 32.016432191192735 ], [ 35.799720987633521, 32.021230449325799 ], [ 35.807738137904778, 32.025362081394974 ], [ 35.822200448691831, 32.02602845654809 ], [ 35.853011458512071, 32.027361191565774 ], [ 35.862443399743142, 32.032958466759908 ], [ 35.872032540669295, 32.040554222599326 ], [ 35.878792098776387, 32.050281199917492 ], [ 35.883508069841582, 32.061206160535903 ], [ 35.888381239702483, 32.066002072337824 ], [ 35.897184385750847, 32.070398104189223 ], [ 35.905515933613515, 32.077191555945603 ], [ 35.896398389973797, 32.081720244094015 ], [ 35.885551656883536, 32.08718100939609 ], [ 35.876591312938785, 32.094772263229402 ], [ 35.870303351218752, 32.101031244296564 ], [ 35.869202957850291, 32.107289796387022 ], [ 35.868731361463233, 32.119006782736903 ], [ 35.85804182716862, 32.120737572980659 ], [ 35.84939588081528, 32.12313399913478 ], [ 35.84216472542181, 32.127793535043679 ], [ 35.834619171537611, 32.132985309524486 ], [ 35.827073618552731, 32.140705863384937 ], [ 35.823300842060291, 32.144299690978016 ], [ 35.82110005532337, 32.149889808467947 ], [ 35.817170079135906, 32.155878840036507 ], [ 35.813240103847761, 32.160802859364537 ], [ 35.801135778593334, 32.165194328955181 ], [ 35.793433025913487, 32.167722654177226 ], [ 35.784315482273712, 32.168387991512645 ], [ 35.772368355815047, 32.168121856938171 ], [ 35.763408010970977, 32.16705731234515 ], [ 35.749731695961032, 32.164528968237335 ], [ 35.739828156544263, 32.162266706543335 ], [ 35.729610220435404, 32.162266706543335 ], [ 35.722693462633231, 32.162532857305564 ], [ 35.718606287650118, 32.165061257171317 ], [ 35.714676312361973, 32.16865412428848 ], [ 35.710903535869534, 32.169851715484356 ], [ 35.704929972640173, 32.16958558540648 ], [ 35.701785992229816, 32.168254924225437 ], [ 35.698013214838056, 32.16559354250802 ], [ 35.694083239549911, 32.16306515793076 ], [ 35.689838865771094, 32.161069015522685 ], [ 35.686066089278654, 32.160270546148865 ], [ 35.681507317009107, 32.160935937443583 ], [ 35.676162549861829, 32.164395895554208 ], [ 35.675219356188393, 32.167456517804112 ], [ 35.67836333659875, 32.17184766633676 ], [ 35.683865302541733, 32.179165775380284 ], [ 35.652897093925787, 32.179298826479737 ], [ 35.643307952999692, 32.1803632289799 ], [ 35.63591959881046, 32.184088536556771 ], [ 35.630103234376804, 32.188611920503774 ], [ 35.627116452762152, 32.19393326031178 ], [ 35.625544462107314, 32.202712791961858 ], [ 35.600707015516377, 32.201781668988872 ], [ 35.586087505933676, 32.202712791961858 ], [ 35.573511583392929, 32.204575007330789 ], [ 35.564551239448178, 32.206304173398962 ], [ 35.551313931193022, 32.206941860178745 ], [ 35.549650270843358, 32.200607121121777 ], [ 35.545491120418944, 32.194975872238786 ], [ 35.542718353169505, 32.183947000353839 ], [ 35.541886522545042, 32.175029063040881 ], [ 35.538281924671139, 32.167518544045606 ], [ 35.532459113897062, 32.158364261301642 ], [ 35.529963622922935, 32.147565720181888 ], [ 35.52608174877372, 32.12666925927897 ], [ 35.525804471599145, 32.110465337605319 ], [ 35.528022685398639, 32.098251786091112 ], [ 35.521922597449986, 32.089090550688411 ], [ 35.513049742251837, 32.080163335069926 ], [ 35.506395099953977, 32.070060434841253 ], [ 35.50306777925465, 32.055726496880368 ], [ 35.503345056429282, 32.039745035105341 ], [ 35.507781484028328, 32.026816811246874 ], [ 35.516931616401052, 32.016472917890894 ], [ 35.522199874624562, 32.006598111813446 ], [ 35.524418088424113, 31.975320876357387 ], [ 35.52608174877372, 31.957678635660557 ], [ 35.524140811249481, 31.949209156077757 ], [ 35.518872553925291, 31.945915258682305 ], [ 35.514158849151613, 31.943327113255748 ], [ 35.512217911627374, 31.937679998533156 ], [ 35.512217911627374, 31.928738023241237 ], [ 35.517486169850883, 31.920971918719147 ], [ 35.524140811249481, 31.905673126913314 ], [ 35.528577238848527, 31.89013636729959 ], [ 35.53024090009751, 31.874596985262713 ], [ 35.531627283272542, 31.861645498640883 ], [ 35.531904560447174, 31.85363821393247 ], [ 35.529686345748303, 31.846336849366139 ], [ 35.528299962573271, 31.835501499894349 ], [ 35.529131792298415, 31.826314012381829 ], [ 35.537727371221251, 31.806993747363606 ], [ 35.540500138470691, 31.798746061281747 ], [ 35.539945585020803, 31.786019617411455 ], [ 35.538004648395884, 31.776120061092001 ], [ 35.53301366734695, 31.767398144508832 ], [ 35.525527195323832, 31.755374696185356 ], [ 35.520258937100323, 31.740284237727451 ], [ 35.508890590928104, 31.714341767158885 ], [ 35.504454163329001, 31.701603715738941 ], [ 35.52084990859646, 31.701065037121793 ], [ 35.539084995875896, 31.70173376040475 ], [ 35.552604112989457, 31.701867503982157 ], [ 35.562227544165864, 31.702811546615635 ], [ 35.573229885151136, 31.705076187915779 ], [ 35.589910853103447, 31.709303369355041 ], [ 35.599138623049043, 31.713832278736731 ], [ 35.606591821955078, 31.71805906177633 ], [ 35.611383163402309, 31.721530917018242 ], [ 35.615642134077291, 31.727719554913563 ], [ 35.617061791268725, 31.736020738066657 ], [ 35.619191276156528, 31.773442283834356 ], [ 35.621498218867771, 31.779627453044554 ], [ 35.623805161579014, 31.782342762608437 ], [ 35.62824158917806, 31.78415292521737 ], [ 35.63303293152461, 31.788074820996258 ], [ 35.635872245008159, 31.793203203165319 ], [ 35.641373415051135, 31.79606894052921 ], [ 35.649004070881233, 31.796672241730619 ], [ 35.657876926978645, 31.796521417329586 ], [ 35.670476381180094, 31.795918114329538 ], [ 35.684140578724794, 31.796370592029234 ], [ 35.694668277319181, 31.797696175638066 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Jerash", "shapeISO": "JO-JA", "shapeID": "50493656B9527447842434", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.868731361463233, 32.119006782736903 ], [ 35.875490919570325, 32.128059787429322 ], [ 35.882093278881769, 32.136313214783115 ], [ 35.89294001197203, 32.144965199184639 ], [ 35.905830332104188, 32.154947238624231 ], [ 35.916519866398744, 32.161468247061975 ], [ 35.923908220587975, 32.166125825146764 ], [ 35.930196181408689, 32.169319455328662 ], [ 35.93994252113049, 32.170117844662855 ], [ 35.949688861751611, 32.171448479763569 ], [ 35.959120802982738, 32.176903877012364 ], [ 35.964465570130017, 32.188744958113375 ], [ 35.966351958376208, 32.199121267532519 ], [ 35.966666356866938, 32.209629401375821 ], [ 35.96583260349189, 32.213206810046302 ], [ 35.964465570130017, 32.219072383583693 ], [ 35.960849992433282, 32.227583527857576 ], [ 35.955819623776677, 32.237556511124126 ], [ 35.951103652711481, 32.244736380879317 ], [ 35.946230482850581, 32.25018738493992 ], [ 35.941042914498951, 32.255903939015639 ], [ 35.934912152473885, 32.262018925133361 ], [ 35.930196181408689, 32.269329780245187 ], [ 35.928938589244524, 32.276374229187354 ], [ 35.929724585021631, 32.282089133906481 ], [ 35.93506935126959, 32.287405002239097 ], [ 35.946859278932607, 32.293119212681574 ], [ 35.963522375557261, 32.303749343157733 ], [ 35.977984686344257, 32.315175343067665 ], [ 35.986001837514834, 32.323278957757736 ], [ 35.991189404967145, 32.334038374771239 ], [ 35.9921325995399, 32.34519493779618 ], [ 35.984272648064291, 32.345726169127431 ], [ 35.978927880917013, 32.344132467939119 ], [ 35.97342591497403, 32.343999657857978 ], [ 35.965251565007748, 32.347054231267805 ], [ 35.96100719122893, 32.350905503286413 ], [ 35.960063997555494, 32.35356145759522 ], [ 35.958963604187034, 32.358873132389192 ], [ 35.956920017145137, 32.362192770180229 ], [ 35.950003259343021, 32.364184494219103 ], [ 35.94371529852225, 32.364715613135104 ], [ 35.935855347046697, 32.363122246494527 ], [ 35.928309793162498, 32.359271495183407 ], [ 35.916519866398744, 32.351038303474979 ], [ 35.889010035784565, 32.338554292546632 ], [ 35.87674851173449, 32.333241425251629 ], [ 35.860871409987624, 32.329389401399794 ], [ 35.84939588081528, 32.325005864728951 ], [ 35.837605953152263, 32.319426510325229 ], [ 35.821886050201101, 32.307469594746067 ], [ 35.809781724946674, 32.291923244761961 ], [ 35.802236171961795, 32.276241319281496 ], [ 35.798463394570035, 32.256834507106873 ], [ 35.799092190652118, 32.244071602022871 ], [ 35.795633812650408, 32.237955407216305 ], [ 35.784158283478064, 32.231306902791403 ], [ 35.771896758528612, 32.224657911833219 ], [ 35.759792433274242, 32.221599213233162 ], [ 35.74643051585565, 32.218274423226092 ], [ 35.735112186378331, 32.217476455673932 ], [ 35.720649875591334, 32.214816512871835 ], [ 35.712003928338675, 32.211358471216499 ], [ 35.706187564804338, 32.206304173398962 ], [ 35.694397637141265, 32.190474425454397 ], [ 35.683865302541733, 32.179165775380284 ], [ 35.67836333659875, 32.17184766633676 ], [ 35.675219356188393, 32.167456517804112 ], [ 35.676162549861829, 32.164395895554208 ], [ 35.681507317009107, 32.160935937443583 ], [ 35.686066089278654, 32.160270546148865 ], [ 35.689838865771094, 32.161069015522685 ], [ 35.694083239549911, 32.16306515793076 ], [ 35.698013214838056, 32.16559354250802 ], [ 35.701785992229816, 32.168254924225437 ], [ 35.704929972640173, 32.16958558540648 ], [ 35.710903535869534, 32.169851715484356 ], [ 35.714676312361973, 32.16865412428848 ], [ 35.718606287650118, 32.165061257171317 ], [ 35.722693462633231, 32.162532857305564 ], [ 35.729610220435404, 32.162266706543335 ], [ 35.739828156544263, 32.162266706543335 ], [ 35.749731695961032, 32.164528968237335 ], [ 35.763408010970977, 32.16705731234515 ], [ 35.772368355815047, 32.168121856938171 ], [ 35.784315482273712, 32.168387991512645 ], [ 35.793433025913487, 32.167722654177226 ], [ 35.801135778593334, 32.165194328955181 ], [ 35.813240103847761, 32.160802859364537 ], [ 35.817170079135906, 32.155878840036507 ], [ 35.82110005532337, 32.149889808467947 ], [ 35.823300842060291, 32.144299690978016 ], [ 35.827073618552731, 32.140705863384937 ], [ 35.834619171537611, 32.132985309524486 ], [ 35.84216472542181, 32.127793535043679 ], [ 35.84939588081528, 32.12313399913478 ], [ 35.85804182716862, 32.120737572980659 ], [ 35.868731361463233, 32.119006782736903 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Ajloun", "shapeISO": "JO-AJ", "shapeID": "50493656B18053261503870", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.683865302541733, 32.179165775380284 ], [ 35.694397637141265, 32.190474425454397 ], [ 35.706187564804338, 32.206304173398962 ], [ 35.712003928338675, 32.211358471216499 ], [ 35.720649875591334, 32.214816512871835 ], [ 35.735112186378331, 32.217476455673932 ], [ 35.74643051585565, 32.218274423226092 ], [ 35.759792433274242, 32.221599213233162 ], [ 35.771896758528612, 32.224657911833219 ], [ 35.784158283478064, 32.231306902791403 ], [ 35.795633812650408, 32.237955407216305 ], [ 35.799092190652118, 32.244071602022871 ], [ 35.798463394570035, 32.256834507106873 ], [ 35.802236171961795, 32.276241319281496 ], [ 35.809781724946674, 32.291923244761961 ], [ 35.821886050201101, 32.307469594746067 ], [ 35.837605953152263, 32.319426510325229 ], [ 35.84939588081528, 32.325005864728951 ], [ 35.860871409987624, 32.329389401399794 ], [ 35.87674851173449, 32.333241425251629 ], [ 35.889010035784565, 32.338554292546632 ], [ 35.887280846334022, 32.347718255593065 ], [ 35.885551656883536, 32.35356145759522 ], [ 35.882093278881769, 32.357014081734519 ], [ 35.88020689063552, 32.358076400505524 ], [ 35.87674851173449, 32.360068215375918 ], [ 35.874862123488242, 32.362325553281721 ], [ 35.874233327406159, 32.364715613135104 ], [ 35.874233327406159, 32.36737116184969 ], [ 35.874233327406159, 32.369761088603411 ], [ 35.873604531324133, 32.373213094009145 ], [ 35.872346939159968, 32.375071811914665 ], [ 35.869202957850291, 32.376532205696776 ], [ 35.864486987684359, 32.377727055759067 ], [ 35.857727428677947, 32.378523614073572 ], [ 35.85426905067618, 32.379187407273093 ], [ 35.848924283528902, 32.381577021062697 ], [ 35.84703789528271, 32.383568318822881 ], [ 35.846094700709898, 32.386754302968768 ], [ 35.846566297996333, 32.392329504303234 ], [ 35.850339074488772, 32.396975243712575 ], [ 35.853483054899129, 32.400028027471535 ], [ 35.853954652185507, 32.403611598296663 ], [ 35.84939588081528, 32.406531439774199 ], [ 35.842950720299541, 32.407991325439355 ], [ 35.835719564906071, 32.408654901902253 ], [ 35.830846395045171, 32.407991325439355 ], [ 35.826130423979919, 32.404407928183389 ], [ 35.823143642365267, 32.399098929771867 ], [ 35.819528064668475, 32.389940174699348 ], [ 35.815440890584682, 32.385161324835337 ], [ 35.807109341822695, 32.382373545202995 ], [ 35.793904623199865, 32.381842530608367 ], [ 35.77645553079816, 32.382373545202995 ], [ 35.758856534001893, 32.384264572152347 ], [ 35.745334901484568, 32.383775198866374 ], [ 35.736642424208583, 32.379425097190563 ], [ 35.729430887525496, 32.372899551673015 ], [ 35.723185181351084, 32.365068275080887 ], [ 35.710951324044402, 32.359466320714205 ], [ 35.703997342403454, 32.356801191521811 ], [ 35.695047309186009, 32.356474843739079 ], [ 35.687127497036386, 32.357399492492618 ], [ 35.683714894526815, 32.358976812529932 ], [ 35.678885740184796, 32.362784024962821 ], [ 35.674120974603341, 32.364741956975763 ], [ 35.664076334255469, 32.367243697338836 ], [ 35.65544824484067, 32.369092765518758 ], [ 35.650425925116394, 32.368603309495199 ], [ 35.642441723306945, 32.366047221302267 ], [ 35.638514011612415, 32.361696266169815 ], [ 35.632215989176586, 32.35330648990265 ], [ 35.618030348521813, 32.328996219599901 ], [ 35.608673862209002, 32.309271203902995 ], [ 35.601933168281164, 32.292518572574124 ], [ 35.599921020638646, 32.283843405448863 ], [ 35.599317376795568, 32.274316774599527 ], [ 35.600323450167139, 32.265639865487458 ], [ 35.602939241652734, 32.259089100281813 ], [ 35.609176899794136, 32.251687017941549 ], [ 35.614710305136498, 32.243518501877418 ], [ 35.621551607121035, 32.233732333880141 ], [ 35.624469220977801, 32.225477094392431 ], [ 35.625374687192107, 32.21270978352976 ], [ 35.625544462107314, 32.202712791961858 ], [ 35.627116452762152, 32.19393326031178 ], [ 35.630103234376804, 32.188611920503774 ], [ 35.63591959881046, 32.184088536556771 ], [ 35.643307952999692, 32.1803632289799 ], [ 35.652897093925787, 32.179298826479737 ], [ 35.683865302541733, 32.179165775380284 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Irbid", "shapeISO": "JO-IR", "shapeID": "50493656B72492647240238", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.625544462107314, 32.202712791961858 ], [ 35.625374687192107, 32.21270978352976 ], [ 35.624469220977801, 32.225477094392431 ], [ 35.621551607121035, 32.233732333880141 ], [ 35.614710305136498, 32.243518501877418 ], [ 35.609176899794136, 32.251687017941549 ], [ 35.602939241652734, 32.259089100281813 ], [ 35.600323450167139, 32.265639865487458 ], [ 35.599317376795568, 32.274316774599527 ], [ 35.599921020638646, 32.283843405448863 ], [ 35.601933168281164, 32.292518572574124 ], [ 35.608673862209002, 32.309271203902995 ], [ 35.618030348521813, 32.328996219599901 ], [ 35.632215989176586, 32.35330648990265 ], [ 35.638514011612415, 32.361696266169815 ], [ 35.642441723306945, 32.366047221302267 ], [ 35.650425925116394, 32.368603309495199 ], [ 35.65544824484067, 32.369092765518758 ], [ 35.664076334255469, 32.367243697338836 ], [ 35.674120974603341, 32.364741956975763 ], [ 35.678885740184796, 32.362784024962821 ], [ 35.683714894526815, 32.358976812529932 ], [ 35.687127497036386, 32.357399492492618 ], [ 35.695047309186009, 32.356474843739079 ], [ 35.703997342403454, 32.356801191521811 ], [ 35.710951324044402, 32.359466320714205 ], [ 35.723185181351084, 32.365068275080887 ], [ 35.729430887525496, 32.372899551673015 ], [ 35.736642424208583, 32.379425097190563 ], [ 35.745334901484568, 32.383775198866374 ], [ 35.758856534001893, 32.384264572152347 ], [ 35.77645553079816, 32.382373545202995 ], [ 35.793904623199865, 32.381842530608367 ], [ 35.807109341822695, 32.382373545202995 ], [ 35.815440890584682, 32.385161324835337 ], [ 35.819528064668475, 32.389940174699348 ], [ 35.823143642365267, 32.399098929771867 ], [ 35.826130423979919, 32.404407928183389 ], [ 35.830846395045171, 32.407991325439355 ], [ 35.835719564906071, 32.408654901902253 ], [ 35.842950720299541, 32.407991325439355 ], [ 35.84939588081528, 32.406531439774199 ], [ 35.853954652185507, 32.403611598296663 ], [ 35.853483054899129, 32.400028027471535 ], [ 35.850339074488772, 32.396975243712575 ], [ 35.846566297996333, 32.392329504303234 ], [ 35.846094700709898, 32.386754302968768 ], [ 35.84703789528271, 32.383568318822881 ], [ 35.848924283528902, 32.381577021062697 ], [ 35.85426905067618, 32.379187407273093 ], [ 35.857727428677947, 32.378523614073572 ], [ 35.864486987684359, 32.377727055759067 ], [ 35.869202957850291, 32.376532205696776 ], [ 35.872346939159968, 32.375071811914665 ], [ 35.873604531324133, 32.373213094009145 ], [ 35.874233327406159, 32.369761088603411 ], [ 35.874233327406159, 32.36737116184969 ], [ 35.874233327406159, 32.364715613135104 ], [ 35.874862123488242, 32.362325553281721 ], [ 35.87674851173449, 32.360068215375918 ], [ 35.88020689063552, 32.358076400505524 ], [ 35.882093278881769, 32.357014081734519 ], [ 35.885551656883536, 32.35356145759522 ], [ 35.887280846334022, 32.347718255593065 ], [ 35.889010035784565, 32.338554292546632 ], [ 35.916519866398744, 32.351038303474979 ], [ 35.928309793162498, 32.359271495183407 ], [ 35.935855347046697, 32.363122246494527 ], [ 35.94371529852225, 32.364715613135104 ], [ 35.950003259343021, 32.364184494219103 ], [ 35.956920017145137, 32.362192770180229 ], [ 35.958963604187034, 32.358873132389192 ], [ 35.960063997555494, 32.35356145759522 ], [ 35.96100719122893, 32.350905503286413 ], [ 35.965251565007748, 32.347054231267805 ], [ 35.97342591497403, 32.343999657857978 ], [ 35.978927880917013, 32.344132467939119 ], [ 35.984272648064291, 32.345726169127431 ], [ 35.9921325995399, 32.34519493779618 ], [ 36.005494516958436, 32.354756611628375 ], [ 36.014454861802506, 32.363918933412094 ], [ 36.017127244926485, 32.368035036887477 ], [ 36.018227638294945, 32.37520457523101 ], [ 36.015083657884531, 32.37985119507664 ], [ 36.00942449224658, 32.384099323524993 ], [ 36.001092944383913, 32.389807432067414 ], [ 35.994176186581797, 32.394718771853888 ], [ 35.991189404967145, 32.400293482158531 ], [ 35.991818201049171, 32.405867848022808 ], [ 35.993861788990444, 32.411707290858828 ], [ 35.997634565482883, 32.416882844267889 ], [ 36.003765327507892, 32.419669558203623 ], [ 36.010524885615041, 32.42099653486224 ], [ 36.020114026541137, 32.422456185804378 ], [ 36.029703167467233, 32.422058101800019 ], [ 36.038191915024925, 32.419536859638413 ], [ 36.046051866500477, 32.416086624997774 ], [ 36.051239434852107, 32.409716614530168 ], [ 36.055955405017983, 32.405071530726616 ], [ 36.063029361615804, 32.402682538368481 ], [ 36.071046511887062, 32.403213430655342 ], [ 36.077963269689178, 32.405071530726616 ], [ 36.081421647690945, 32.409451186822878 ], [ 36.084722827796327, 32.47153978913002 ], [ 36.084094031714244, 32.485994453881005 ], [ 36.08126444889524, 32.50270062353502 ], [ 36.076476068915497, 32.513529351298587 ], [ 36.076476068915497, 32.520543606402384 ], [ 36.075644238291034, 32.537375585814686 ], [ 36.070375980966787, 32.550932387219973 ], [ 36.063444062393614, 32.562617640991391 ], [ 36.046530181722574, 32.58761897193807 ], [ 36.033498175200691, 32.599299447611486 ], [ 36.024902596277855, 32.610744836005438 ], [ 36.027675363527237, 32.634098233047041 ], [ 36.029616300152156, 32.643437885849778 ], [ 36.026566256627518, 32.652309651968892 ], [ 36.019357060879713, 32.657678977802618 ], [ 36.007711438432182, 32.662814553648786 ], [ 35.996620368535218, 32.663047981679085 ], [ 35.988856620236902, 32.658846180007231 ], [ 35.97915193441429, 32.661180538551037 ], [ 35.958078902419459, 32.672851416659626 ], [ 35.956969795519683, 32.680086595619969 ], [ 35.962238053743249, 32.682887152819887 ], [ 35.966119927892407, 32.691054942231858 ], [ 35.960019839943698, 32.695021885052029 ], [ 35.951978814470749, 32.696188598924778 ], [ 35.943383235547913, 32.697355297509034 ], [ 35.938114977324403, 32.702721917282702 ], [ 35.935896763524852, 32.711821098564883 ], [ 35.928964845850999, 32.713687482291505 ], [ 35.916487392779004, 32.714853952447982 ], [ 35.906228153506504, 32.718353272085892 ], [ 35.889868825386031, 32.722085727474393 ], [ 35.873509498164879, 32.726751077500296 ], [ 35.860477491642996, 32.727684118727154 ], [ 35.843286333797323, 32.7274508588701 ], [ 35.833858925149343, 32.726751077500296 ], [ 35.824154239326731, 32.730249930390016 ], [ 35.815835937578527, 32.736081045503909 ], [ 35.80724035865569, 32.741212111249979 ], [ 35.793376521509288, 32.746109671624083 ], [ 35.780344514987405, 32.747508924996964 ], [ 35.772026213239201, 32.746109671624083 ], [ 35.761766973966701, 32.741212111249979 ], [ 35.753171395043921, 32.733748644784157 ], [ 35.74069394197187, 32.726051290734517 ], [ 35.716848142727656, 32.718819837665421 ], [ 35.701597922406222, 32.713920778121462 ], [ 35.689952299059428, 32.710654588838281 ], [ 35.681633997311167, 32.703188563801234 ], [ 35.67913850633704, 32.696421939720778 ], [ 35.672761142113075, 32.6880212789589 ], [ 35.660560965316336, 32.685920989662009 ], [ 35.638378826421729, 32.684520770417294 ], [ 35.618137625051418, 32.683120527790152 ], [ 35.60815566205423, 32.676585775912883 ], [ 35.604273787905015, 32.66841666269886 ], [ 35.593182718907428, 32.658846180007231 ], [ 35.587082630059399, 32.655577976242682 ], [ 35.575714283887123, 32.651609281543188 ], [ 35.567950535588807, 32.648574278280364 ], [ 35.562959554539873, 32.641803516419202 ], [ 35.563791384265016, 32.636199740026029 ], [ 35.569336919663158, 32.631062635332398 ], [ 35.570446026562934, 32.623122895105553 ], [ 35.566286875239143, 32.617050853414185 ], [ 35.566286875239143, 32.607942018809183 ], [ 35.571000580012822, 32.601635360183764 ], [ 35.575159730437235, 32.589721569794676 ], [ 35.57488245416198, 32.576871590551491 ], [ 35.570446026562934, 32.566590281016715 ], [ 35.559632233840546, 32.555840378830453 ], [ 35.555750359691388, 32.544387980221188 ], [ 35.552700315267373, 32.527323533254503 ], [ 35.557136742866419, 32.516101308029022 ], [ 35.565455045514, 32.497394485866892 ], [ 35.561573170465522, 32.485934635475076 ], [ 35.561850447640097, 32.47634465997811 ], [ 35.562959554539873, 32.466987600797211 ], [ 35.55935495666597, 32.457395606322223 ], [ 35.552977591542685, 32.444994685556367 ], [ 35.549372994568103, 32.436102408599311 ], [ 35.546045673868832, 32.428145416677694 ], [ 35.548818441118215, 32.420421783538529 ], [ 35.549372994568103, 32.412463408459587 ], [ 35.544659289794424, 32.404504331909436 ], [ 35.54244107599493, 32.398417506262945 ], [ 35.546322950144088, 32.391862003428741 ], [ 35.546877503593976, 32.383198645301263 ], [ 35.543827460069281, 32.377344554307797 ], [ 35.542995629444817, 32.371021709684214 ], [ 35.542995629444817, 32.358374694836357 ], [ 35.54244107599493, 32.345491657414129 ], [ 35.545491120418944, 32.328623816635854 ], [ 35.54992754801799, 32.319954397977142 ], [ 35.5551958062415, 32.309409391929933 ], [ 35.554641252791612, 32.301909974166051 ], [ 35.55186848464291, 32.294175550061652 ], [ 35.54909571739347, 32.286674871448213 ], [ 35.550482101467878, 32.279173572302568 ], [ 35.553254868717261, 32.274250508054536 ], [ 35.552700315267373, 32.266748181883145 ], [ 35.548818441118215, 32.25971418755978 ], [ 35.548541163943639, 32.253148633902356 ], [ 35.553532145891893, 32.248224157718766 ], [ 35.553809422167149, 32.239077993154922 ], [ 35.551036654917766, 32.232745493409823 ], [ 35.546322950144088, 32.225474301997508 ], [ 35.547154780768551, 32.215387491539559 ], [ 35.551313931193022, 32.206941860178745 ], [ 35.564551239448178, 32.206304173398962 ], [ 35.573511583392929, 32.204575007330789 ], [ 35.586087505933676, 32.202712791961858 ], [ 35.600707015516377, 32.201781668988872 ], [ 35.625544462107314, 32.202712791961858 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Mafraq", "shapeISO": "JO-MA", "shapeID": "50493656B24919758862355", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.96583260349189, 32.213206810046302 ], [ 35.972954317687652, 32.213619513429876 ], [ 35.981914662531722, 32.213619513429876 ], [ 35.988517021843109, 32.212023489292676 ], [ 35.994804982663879, 32.209496394343148 ], [ 35.998106162769261, 32.206836218616672 ], [ 36.000306949506182, 32.203111840938732 ], [ 36.000306949506182, 32.200052416585834 ], [ 35.999049357342017, 32.19446537747524 ], [ 35.997477366687178, 32.191937795093224 ], [ 35.994333386276821, 32.18754761513037 ], [ 35.992761395621983, 32.183157223826868 ], [ 35.991189405866464, 32.176238602629439 ], [ 35.992604196826278, 32.17171460354615 ], [ 35.999835352219804, 32.165194328955181 ], [ 36.008166900981735, 32.160137467170443 ], [ 36.014454861802506, 32.15681043155621 ], [ 36.020900022318244, 32.155346497143171 ], [ 36.026401988261227, 32.154281803262677 ], [ 36.031117959326423, 32.154281803262677 ], [ 36.037563119842162, 32.154414891234296 ], [ 36.043379483376498, 32.156011925310167 ], [ 36.049038648115186, 32.159205909824948 ], [ 36.052654225811921, 32.16306515793076 ], [ 36.055169411039515, 32.166791174173397 ], [ 36.06019977969612, 32.170916228601129 ], [ 36.064758551066348, 32.173045215264551 ], [ 36.067116537498237, 32.17277909417993 ], [ 36.070574915500003, 32.17078316401188 ], [ 36.074819289278821, 32.16665810418823 ], [ 36.076548478729364, 32.163198232412526 ], [ 36.080006857630451, 32.15933898970269 ], [ 36.086923614533248, 32.154281803262677 ], [ 36.092897177762609, 32.150155996102399 ], [ 36.099342337379028, 32.146828596262765 ], [ 36.106101896385439, 32.145896903119649 ], [ 36.112547056901235, 32.145896903119649 ], [ 36.118049021944842, 32.146828596262765 ], [ 36.126694969197501, 32.14922433623417 ], [ 36.141786076066637, 32.154148715291058 ], [ 36.162693546470052, 32.160137467170443 ], [ 36.172597084987558, 32.161202092702467 ], [ 36.189888978593558, 32.16306515793076 ], [ 36.203250896911413, 32.162932083448936 ], [ 36.212997235733894, 32.162399781924421 ], [ 36.228402741093703, 32.159072829047886 ], [ 36.238149080815504, 32.154681065378895 ], [ 36.249624609987791, 32.149091241067993 ], [ 36.269117289431392, 32.141105183957109 ], [ 36.280435619808031, 32.137111893699 ], [ 36.288609969774313, 32.136046986679162 ], [ 36.295998323064225, 32.135780757675889 ], [ 36.301971886293586, 32.135913872627157 ], [ 36.308417046809325, 32.136712555140377 ], [ 36.31344741636525, 32.138443009937021 ], [ 36.319420978695234, 32.141504503630017 ], [ 36.324294149455511, 32.145630701995344 ], [ 36.328695722029977, 32.149756714201033 ], [ 36.333411692195909, 32.151886196390876 ], [ 36.371611057104644, 32.153882539347762 ], [ 36.380257003457984, 32.152418558169984 ], [ 36.387959756137889, 32.151220738546272 ], [ 36.395190911531415, 32.151087646078054 ], [ 36.401950469638507, 32.152019287060511 ], [ 36.409024426236329, 32.153483274533528 ], [ 36.418456367467456, 32.15321709679165 ], [ 36.427573912006494, 32.152551648839562 ], [ 36.43228988217237, 32.150555276205068 ], [ 36.437791848115353, 32.146429299972283 ], [ 36.439521037565896, 32.14323486759514 ], [ 36.44093582852571, 32.13498206706879 ], [ 36.444079808936067, 32.125264101856885 ], [ 36.448638581205614, 32.120205025941232 ], [ 36.453826149557187, 32.115012524808208 ], [ 36.460900105255689, 32.111550692510491 ], [ 36.47206123683668, 32.108355038854029 ], [ 36.571725421690928, 32.074927128684067 ], [ 36.687581106782716, 32.034291101053498 ], [ 36.800764407851204, 31.995103558382539 ], [ 36.900428592705453, 31.961500903643866 ], [ 37.048510077677975, 31.914276398636957 ], [ 37.188417214482911, 31.872768188701002 ], [ 37.330210739534039, 31.833645270412944 ], [ 37.465873501660838, 31.797177926020538 ], [ 37.608295821894728, 31.759359585876211 ], [ 37.73043946780723, 31.725403458902576 ], [ 37.814897014385735, 31.700528244383008 ], [ 37.844618905638015, 31.707537115245714 ], [ 38.143828664461353, 31.781799177290225 ], [ 38.4633467770322, 31.862901173450439 ], [ 38.763910426525001, 31.936463948752305 ], [ 38.985271492085758, 31.990449154005319 ], [ 39.301404879331756, 32.232416579861308 ], [ 39.258757334483448, 32.35544689256011 ], [ 39.03942710447734, 32.303393977849851 ], [ 38.983240656531109, 32.478881132158563 ], [ 39.088167155989538, 32.503433525137154 ], [ 39.024534310709896, 32.708725257064998 ], [ 38.959547576559487, 32.905020937466361 ], [ 38.882375828181978, 33.126397502842508 ], [ 38.792342122490993, 33.376617794875358 ], [ 38.791015310408284, 33.37979787856932 ], [ 38.746928309793702, 33.356872626270729 ], [ 38.504865719477436, 33.229864054582492 ], [ 38.277221518858084, 33.107083842445434 ], [ 38.058172898060832, 32.986225071429942 ], [ 37.819437628443836, 32.851924395494507 ], [ 37.621739315916727, 32.738180153990982 ], [ 37.382449493749164, 32.602336121814631 ], [ 37.187246671296919, 32.494821994039853 ], [ 37.09103164459475, 32.443356699951778 ], [ 36.976793629422502, 32.383901110248075 ], [ 36.872814853522698, 32.334481061551799 ], [ 36.861446507350479, 32.325109287663565 ], [ 36.838432537831409, 32.309409391929933 ], [ 36.722530862309497, 32.330732468728513 ], [ 36.707280641988064, 32.323000504269885 ], [ 36.695080466090701, 32.333309643325435 ], [ 36.628811325682193, 32.343851865970862 ], [ 36.492391172514658, 32.361887932382217 ], [ 36.481300102617695, 32.372426824838158 ], [ 36.396453422087802, 32.379920400606068 ], [ 36.306615759609656, 32.457629569449125 ], [ 36.293029199637886, 32.466051840919761 ], [ 36.247833091224209, 32.493418784549306 ], [ 36.19459595823696, 32.531063962931569 ], [ 36.186000379314123, 32.52592083188091 ], [ 36.171027435268002, 32.517270355642438 ], [ 36.161045473170077, 32.515166059865805 ], [ 36.152449894247297, 32.519140798908779 ], [ 36.141358825249654, 32.52147879880755 ], [ 36.124999497129124, 32.521245002055252 ], [ 36.110303830257635, 32.519608404104645 ], [ 36.091449012961618, 32.517036547198927 ], [ 36.076476068915497, 32.513529351298587 ], [ 36.08126444889524, 32.50270062353502 ], [ 36.084094031714244, 32.485994453881005 ], [ 36.084722827796327, 32.47153978913002 ], [ 36.081421647690945, 32.409451186822878 ], [ 36.077963269689178, 32.405071530726616 ], [ 36.071046511887062, 32.403213430655342 ], [ 36.063029361615804, 32.402682538368481 ], [ 36.055955405017983, 32.405071530726616 ], [ 36.051239434852107, 32.409716614530168 ], [ 36.046051866500477, 32.416086624997774 ], [ 36.038191915024925, 32.419536859638413 ], [ 36.029703167467233, 32.422058101800019 ], [ 36.020114026541137, 32.422456185804378 ], [ 36.010524885615041, 32.42099653486224 ], [ 36.003765327507892, 32.419669558203623 ], [ 35.997634565482883, 32.416882844267889 ], [ 35.993861788990444, 32.411707290858828 ], [ 35.991818201049171, 32.405867848022808 ], [ 35.991189404967145, 32.400293482158531 ], [ 35.994176186581797, 32.394718771853888 ], [ 36.001092944383913, 32.389807432067414 ], [ 36.00942449224658, 32.384099323524993 ], [ 36.015083657884531, 32.37985119507664 ], [ 36.018227638294945, 32.37520457523101 ], [ 36.017127244926485, 32.368035036887477 ], [ 36.014454861802506, 32.363918933412094 ], [ 36.005494516958436, 32.354756611628375 ], [ 35.9921325995399, 32.34519493779618 ], [ 35.991189404967145, 32.334038374771239 ], [ 35.986001837514834, 32.323278957757736 ], [ 35.977984686344257, 32.315175343067665 ], [ 35.963522375557261, 32.303749343157733 ], [ 35.946859278932607, 32.293119212681574 ], [ 35.93506935126959, 32.287405002239097 ], [ 35.929724585021631, 32.282089133906481 ], [ 35.928938589244524, 32.276374229187354 ], [ 35.930196181408689, 32.269329780245187 ], [ 35.934912152473885, 32.262018925133361 ], [ 35.941042914498951, 32.255903939015639 ], [ 35.946230482850581, 32.25018738493992 ], [ 35.951103652711481, 32.244736380879317 ], [ 35.955819623776677, 32.237556511124126 ], [ 35.960849992433282, 32.227583527857576 ], [ 35.964465570130017, 32.219072383583693 ], [ 35.96583260349189, 32.213206810046302 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Tafilah", "shapeISO": "JO-AT", "shapeID": "50493656B42397385377058", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 36.027751704756952, 30.779632093164281 ], [ 36.005808915449165, 30.796211582198794 ], [ 35.993075794112656, 30.807283649420924 ], [ 35.977670288752847, 30.81929944901043 ], [ 35.96965313848159, 30.823484374004693 ], [ 35.959120802982738, 30.828074083851959 ], [ 35.947330876219041, 30.835363169075038 ], [ 35.937741736192208, 30.841841893188871 ], [ 35.929095788939549, 30.847510416272769 ], [ 35.923436623301598, 30.853988319305529 ], [ 35.916834263990154, 30.860735670015231 ], [ 35.914319080561143, 30.868831864399056 ], [ 35.908659914923192, 30.87207014951781 ], [ 35.901743158020395, 30.872474928075519 ], [ 35.893568808054113, 30.873419403282867 ], [ 35.889481633970263, 30.87625277404635 ], [ 35.885708856578503, 30.881514526574222 ], [ 35.877691706307246, 30.887180705125502 ], [ 35.866844973216985, 30.893251238653818 ], [ 35.85914222053708, 30.895274664694057 ], [ 35.85426905067618, 30.897837609318287 ], [ 35.848609885937549, 30.900670257926095 ], [ 35.844051114567321, 30.905121393037916 ], [ 35.842321924217458, 30.909167700129331 ], [ 35.840278337175562, 30.914562510051837 ], [ 35.838549147725018, 30.919552438894016 ], [ 35.835405167314661, 30.923598135345742 ], [ 35.825816026388566, 30.926295171584968 ], [ 35.800035385224874, 30.92872243908937 ], [ 35.792018234953616, 30.931554173986001 ], [ 35.781171501863355, 30.937217390170474 ], [ 35.753976070639226, 30.950699889588293 ], [ 35.731496608681596, 30.958518867951454 ], [ 35.719549483122194, 30.963641299306573 ], [ 35.70917434641899, 30.970111346761314 ], [ 35.696284026286833, 30.976850512741009 ], [ 35.683079307663945, 30.98291535535941 ], [ 35.674433361310605, 30.98426304610274 ], [ 35.662014637565505, 30.984128278197545 ], [ 35.652897093925787, 30.98237627474532 ], [ 35.628845643112015, 30.979815595513401 ], [ 35.606680578745738, 30.980085143914323 ], [ 35.589860283325493, 30.981837189634632 ], [ 35.569110010818406, 30.985341184847869 ], [ 35.558577677118137, 30.989249336287912 ], [ 35.547259345842178, 30.997065157131374 ], [ 35.539713792857299, 31.005823505250646 ], [ 35.532797035954502, 31.00622771813471 ], [ 35.525094283274598, 31.005149815012032 ], [ 35.518649122758859, 31.003398197368938 ], [ 35.507802389668598, 31.002320262769956 ], [ 35.49978523939734, 31.003667679220086 ], [ 35.492082486717436, 31.00461085940367 ], [ 35.481707350913553, 31.004206640224311 ], [ 35.476048186174921, 31.001242315580441 ], [ 35.473847399438, 30.996256653122089 ], [ 35.473690200642295, 30.989114574677956 ], [ 35.475576588888543, 30.983050125063301 ], [ 35.478406170808171, 30.975233156684908 ], [ 35.477148578644062, 30.968898246756737 ], [ 35.469131428372748, 30.957305619558724 ], [ 35.462057472674303, 30.945846409484261 ], [ 35.462686268756329, 30.930070894256403 ], [ 35.462529069061361, 30.911460531578314 ], [ 35.462057472674303, 30.904446992334897 ], [ 35.459542287446652, 30.898781834514125 ], [ 35.454511918790047, 30.893655927279269 ], [ 35.44759516098793, 30.891362669551597 ], [ 35.438792015838885, 30.890013668496067 ], [ 35.428731277626412, 30.890553270716907 ], [ 35.418356142721848, 30.892306958599306 ], [ 35.409867394264893, 30.895544451415333 ], [ 35.403107836157744, 30.900130712362511 ], [ 35.396033879559923, 30.906335303331616 ], [ 35.389588719943504, 30.910921046269323 ], [ 35.382671963040707, 30.914967108745145 ], [ 35.374812011565155, 30.918338695874183 ], [ 35.365270037382345, 30.921452882644473 ], [ 35.351397404866418, 30.904161352364554 ], [ 35.345020040642396, 30.886316357713781 ], [ 35.343079103118157, 30.870372016355532 ], [ 35.341415442768493, 30.851806606289927 ], [ 35.340029058694142, 30.835856524559006 ], [ 35.336147184544984, 30.82323741837223 ], [ 35.328660712521923, 30.818475060275887 ], [ 35.318124196974168, 30.812283642576119 ], [ 35.308696788326188, 30.803948410191026 ], [ 35.302596699478158, 30.792277871126885 ], [ 35.297051164979337, 30.775603214616694 ], [ 35.295110227455098, 30.758687395906634 ], [ 35.293169290830178, 30.742721854829767 ], [ 35.291228353305939, 30.730090521460454 ], [ 35.283741881282822, 30.715073765142222 ], [ 35.296219335254193, 30.710306051583075 ], [ 35.306478573627317, 30.704822889564753 ], [ 35.31424232282501, 30.700531501927344 ], [ 35.322006071123326, 30.69600149717138 ], [ 35.333097141020289, 30.68598704796392 ], [ 35.352783788940769, 30.674779169623037 ], [ 35.365815795462652, 30.670724936806437 ], [ 35.376352311010407, 30.665239526482992 ], [ 35.38328422958358, 30.65856121492817 ], [ 35.38938431753229, 30.647827247829298 ], [ 35.393820746030656, 30.637330662180375 ], [ 35.401307218053716, 30.624685534110142 ], [ 35.419052928449958, 30.618481659900738 ], [ 35.438462300095125, 30.616572695073842 ], [ 35.455891235991771, 30.616103967524111 ], [ 35.456208011390686, 30.616095448246369 ], [ 35.460367162714419, 30.618605741162071 ], [ 35.465335961085771, 30.619980170548502 ], [ 35.472789159991805, 30.61814759323687 ], [ 35.490357414363245, 30.614024169280015 ], [ 35.504376525756129, 30.609900569056094 ], [ 35.515733780589528, 30.608678727641234 ], [ 35.549273175216911, 30.609289650596963 ], [ 35.589201024507702, 30.611275121649612 ], [ 35.609963507110194, 30.613107828463569 ], [ 35.629838703293558, 30.61188602841753 ], [ 35.646342214321805, 30.607762336462713 ], [ 35.653617956303719, 30.603638470039414 ], [ 35.662490811501812, 30.600125407861356 ], [ 35.671363666699904, 30.600278152314957 ], [ 35.677219751490384, 30.602874772053156 ], [ 35.685915149764412, 30.610664212183679 ], [ 35.695142919710008, 30.616773138669487 ], [ 35.709694402774517, 30.619063886389313 ], [ 35.746073110885391, 30.621507291328498 ], [ 35.792744330486528, 30.628989835112861 ], [ 35.832317266828454, 30.634334154397777 ], [ 35.840835208178362, 30.640594267711322 ], [ 35.848288406185077, 30.649754679335047 ], [ 35.855564148166934, 30.657998307675825 ], [ 35.866743946076326, 30.661051325258484 ], [ 35.88448965737183, 30.661967211018009 ], [ 35.897976397093089, 30.658456266743372 ], [ 35.911108223865483, 30.653571260905039 ], [ 35.930096134529037, 30.645021908034664 ], [ 35.94588981696154, 30.638914764904541 ], [ 35.961860957217482, 30.668378173014332 ], [ 36.006047778082518, 30.741921124560292 ], [ 36.027751704756952, 30.779632093164281 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Aqaba", "shapeISO": "JO-AQ", "shapeID": "50493656B99764555865464", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.455891235991771, 30.616103967524111 ], [ 35.438462300095125, 30.616572695073842 ], [ 35.419052928449958, 30.618481659900738 ], [ 35.401307218053716, 30.624685534110142 ], [ 35.393820746030656, 30.637330662180375 ], [ 35.38938431753229, 30.647827247829298 ], [ 35.38328422958358, 30.65856121492817 ], [ 35.376352311010407, 30.665239526482992 ], [ 35.365815795462652, 30.670724936806437 ], [ 35.352783788940769, 30.674779169623037 ], [ 35.333097141020289, 30.68598704796392 ], [ 35.322006071123326, 30.69600149717138 ], [ 35.31424232282501, 30.700531501927344 ], [ 35.306478573627317, 30.704822889564753 ], [ 35.296219335254193, 30.710306051583075 ], [ 35.283741881282822, 30.715073765142222 ], [ 35.277087239884281, 30.70267721957805 ], [ 35.267659831236301, 30.68622549870787 ], [ 35.258232421688945, 30.669532482538102 ], [ 35.246032245791582, 30.651166832583328 ], [ 35.234109346169419, 30.629934655659895 ], [ 35.221077339647536, 30.609652384050321 ], [ 35.210818100375093, 30.584830648615593 ], [ 35.208599886575541, 30.570507525002313 ], [ 35.201390690827793, 30.553316984091566 ], [ 35.197508816678578, 30.540660889688354 ], [ 35.195567880053659, 30.522748504340029 ], [ 35.195013326603771, 30.510805078591545 ], [ 35.188358684305911, 30.493603968848163 ], [ 35.179763106282394, 30.467557612194071 ], [ 35.171444803634813, 30.44867562278182 ], [ 35.166176545411304, 30.439352784603386 ], [ 35.163958331611752, 30.42572549523544 ], [ 35.168672036385431, 30.415683116682544 ], [ 35.175049401508716, 30.408987623580003 ], [ 35.182813149807089, 30.40013930278667 ], [ 35.185308640781216, 30.390811826804395 ], [ 35.185863194231104, 30.377416970816626 ], [ 35.185031363606583, 30.363063300830731 ], [ 35.180317659732282, 30.351100300438588 ], [ 35.169503867009894, 30.330041867138505 ], [ 35.16451288506164, 30.306824482663785 ], [ 35.159244627737451, 30.280967728278085 ], [ 35.157303690213212, 30.257978223915927 ], [ 35.155640029863548, 30.23881619281309 ], [ 35.160908288087057, 30.219890019708714 ], [ 35.165621991961416, 30.197365525098974 ], [ 35.170058420459782, 30.178191681401017 ], [ 35.173108463984477, 30.162849919987877 ], [ 35.174494848058828, 30.142950016729912 ], [ 35.172831187709221, 30.12088760188135 ], [ 35.168117482935543, 30.103857803095195 ], [ 35.152312709164221, 30.085145626369638 ], [ 35.134012444418829, 30.065710002614594 ], [ 35.119871330997171, 30.056590739471119 ], [ 35.10905753827484, 30.042430220478366 ], [ 35.101848343426354, 30.021785836846959 ], [ 35.098521022727084, 30.003778505573621 ], [ 35.097689192102564, 29.971357071671548 ], [ 35.082993525231075, 29.956463680754325 ], [ 35.082438971781187, 29.899511932229927 ], [ 35.082161694606555, 29.849742617427921 ], [ 35.077725267007509, 29.842046594374892 ], [ 35.063029600135962, 29.816789854168462 ], [ 35.048888486714361, 29.786954627653984 ], [ 35.042233845315764, 29.767701372920101 ], [ 35.034747373292703, 29.750370279664708 ], [ 35.027260901269642, 29.734962347934072 ], [ 35.024488134020203, 29.725331187984011 ], [ 35.023933580570315, 29.710641889211843 ], [ 35.0208835361463, 29.69498699285549 ], [ 35.017001661997142, 29.676920619291195 ], [ 35.011178850323745, 29.661260469095396 ], [ 35.008683360248938, 29.651381274326411 ], [ 35.00396965547526, 29.63764517238684 ], [ 34.990383095503489, 29.618845365721086 ], [ 34.982342070030541, 29.591844636820611 ], [ 34.978460195881382, 29.542887396336312 ], [ 34.98844215797925, 29.536374054618989 ], [ 34.999533227876213, 29.526965153119363 ], [ 34.99786956752655, 29.498733199277751 ], [ 34.994264969652704, 29.490044859782529 ], [ 34.981510240305397, 29.474355692960899 ], [ 34.970419170408434, 29.456249791494713 ], [ 34.960832543986783, 29.404017859536623 ], [ 34.956770872877541, 29.357417675585339 ], [ 35.366999636923765, 29.295447711842485 ], [ 35.714272501474795, 29.240528604711415 ], [ 35.737249712104585, 29.236882253113549 ], [ 35.726319479660333, 29.331944149303126 ], [ 35.715957239235252, 29.443299641265469 ], [ 35.707130146039447, 29.506781148631148 ], [ 35.703338332697967, 29.53117419523295 ], [ 35.68663593569994, 29.62794025274053 ], [ 35.68319720698554, 29.645659955642486 ], [ 35.679021607960863, 29.660388419889728 ], [ 35.674109138625909, 29.673834265638902 ], [ 35.668214174344712, 29.687918461867582 ], [ 35.662319210962892, 29.709041054601016 ], [ 35.654950506061084, 29.740183437615599 ], [ 35.651511777346684, 29.754898049605345 ], [ 35.647581802058596, 29.771529358792918 ], [ 35.642178085250464, 29.783468081986427 ], [ 35.63726561591551, 29.791994870866631 ], [ 35.629896911013702, 29.800520932195298 ], [ 35.619580723971296, 29.808406892963774 ], [ 35.614913878372818, 29.813095547121861 ], [ 35.611229526821262, 29.81927571070554 ], [ 35.608527668417196, 29.827586361921135 ], [ 35.606071432850399, 29.839092278286046 ], [ 35.60484331596632, 29.846549107755152 ], [ 35.601158963515388, 29.861674109172839 ], [ 35.596983364490711, 29.874666998783027 ], [ 35.590842777372302, 29.888297063458765 ], [ 35.586667178347682, 29.895111396573725 ], [ 35.581017837803017, 29.902138190924802 ], [ 35.572666639753663, 29.911719382743343 ], [ 35.565052311115323, 29.91959656253141 ], [ 35.554981748708769, 29.927047374636686 ], [ 35.530173776498657, 29.940031741371797 ], [ 35.504874558614063, 29.949822111900971 ], [ 35.475399739906152, 29.957696275362878 ], [ 35.441749322173507, 29.957057852038304 ], [ 35.427503160742333, 29.954291308097424 ], [ 35.412028881527704, 29.948757988190664 ], [ 35.393607119273213, 29.948332334569614 ], [ 35.374939734181453, 29.949609288238094 ], [ 35.3560267271518, 29.95492974760981 ], [ 35.34497367069838, 29.96173952206135 ], [ 35.33735934206004, 29.96620818226188 ], [ 35.324586920350157, 29.981102265657114 ], [ 35.312060123276126, 29.998121340927185 ], [ 35.305919536157717, 30.011734500147099 ], [ 35.302235183706841, 30.023644481907354 ], [ 35.301252689659975, 30.034915111343366 ], [ 35.301252689659975, 30.043845643661598 ], [ 35.301989560869572, 30.0514997439181 ], [ 35.304200171800517, 30.061066539389344 ], [ 35.308130147987981, 30.071695227352905 ], [ 35.31107763012858, 30.082747850333078 ], [ 35.312060123276126, 30.09273665986899 ], [ 35.312551369849871, 30.103361943898619 ], [ 35.315253228253937, 30.113561143532024 ], [ 35.318200710394535, 30.126308661215774 ], [ 35.323850050939143, 30.136080644206402 ], [ 35.335148730229776, 30.148612857897149 ], [ 35.348903645986525, 30.161355850192365 ], [ 35.359711078703356, 30.171761404665119 ], [ 35.380589074726061, 30.198088921766384 ], [ 35.397537095460621, 30.223135990433661 ], [ 35.397537095460621, 30.229715095075619 ], [ 35.397291471724088, 30.243720755308686 ], [ 35.39606335484001, 30.252632408159172 ], [ 35.386130341042474, 30.286743836358994 ], [ 35.368052452558686, 30.345367403882619 ], [ 35.380313976608761, 30.366257136957358 ], [ 35.411910981306789, 30.421037566830307 ], [ 35.434704840855773, 30.459528185277577 ], [ 35.434862039651478, 30.46860650228831 ], [ 35.433918845977985, 30.493398192272821 ], [ 35.435333636937855, 30.504369546217617 ], [ 35.454197521198694, 30.543098008366428 ], [ 35.458284695282487, 30.551627028464623 ], [ 35.459070691059594, 30.55866629011723 ], [ 35.458913492263889, 30.567058588083398 ], [ 35.458441894078192, 30.586818229477785 ], [ 35.457655899200461, 30.606032646989092 ], [ 35.455891235991771, 30.616103967524111 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Amman", "shapeISO": "JO-AM", "shapeID": "50493656B53844896346683", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 37.245789602907905, 31.268742117554723 ], [ 37.172412365838056, 31.337648478494543 ], [ 36.999114406904425, 31.500556809049556 ], [ 37.008312281586598, 31.502923036868708 ], [ 36.987831252610249, 31.520735576785512 ], [ 36.909860533936524, 31.59119532770228 ], [ 36.829846228220902, 31.664010235783792 ], [ 36.757377475490159, 31.729414673548376 ], [ 36.699685431137766, 31.781010139106684 ], [ 36.656770096962475, 31.7621664248407 ], [ 36.61338316460143, 31.741580962091803 ], [ 36.607723998963422, 31.742249393095051 ], [ 36.593418887871451, 31.746794596393556 ], [ 36.567323848217086, 31.759894228336009 ], [ 36.557263110903875, 31.768314441258497 ], [ 36.548145567264157, 31.772457439859011 ], [ 36.532582863108701, 31.783148190936288 ], [ 36.493597504221498, 31.814945866758421 ], [ 36.462786493501937, 31.844596019091057 ], [ 36.443922610140419, 31.859684555697754 ], [ 36.441879023098465, 31.867428154685626 ], [ 36.451153766433208, 31.884248215382911 ], [ 36.459799711887229, 31.894659094741485 ], [ 36.467030868180075, 31.89786220467704 ], [ 36.474104824777896, 31.901065203996041 ], [ 36.481335979272103, 31.90440154309681 ], [ 36.534626450150597, 31.929486938171692 ], [ 36.529281683902639, 31.936424243683973 ], [ 36.514504975524233, 31.95123097143221 ], [ 36.467816863057863, 31.995103558382539 ], [ 36.421914746368486, 32.037222828870483 ], [ 36.397077299777607, 32.055210916450676 ], [ 36.386230566687345, 32.060406817021033 ], [ 36.3774274215383, 32.062938046153931 ], [ 36.366423489652391, 32.062938046153931 ], [ 36.356048352949188, 32.061339384305199 ], [ 36.340485648793731, 32.058275201639276 ], [ 36.323665352474109, 32.056276765960035 ], [ 36.312032625405379, 32.055877073967849 ], [ 36.301343091110823, 32.057342603778181 ], [ 36.285780386955366, 32.060939713896744 ], [ 36.2747764550694, 32.064803118669033 ], [ 36.267073702389496, 32.064936336143035 ], [ 36.256384168094939, 32.063737367185809 ], [ 36.247738221741599, 32.059207789607854 ], [ 36.241764659411558, 32.05534414831385 ], [ 36.237205887142011, 32.049481761074446 ], [ 36.233904707935949, 32.042553000920293 ], [ 36.230603526931247, 32.032691937383049 ], [ 36.22635915405175, 32.027227919233155 ], [ 36.218656401371902, 32.021896854156523 ], [ 36.203408095707118, 32.017898352327165 ], [ 36.182186225913654, 32.014032967247715 ], [ 36.169453104577144, 32.013499797877444 ], [ 36.16316514375643, 32.014432841802261 ], [ 36.156719983240691, 32.016432191192735 ], [ 36.150274823624272, 32.018964636209034 ], [ 36.144144061599206, 32.021363730651672 ], [ 36.134869318264464, 32.023096370800943 ], [ 36.125437377033393, 32.023096370800943 ], [ 36.118992216517654, 32.020830603549541 ], [ 36.114119046656754, 32.017365205439944 ], [ 36.109560275286526, 32.012433450143646 ], [ 36.106573493671874, 32.007501430446723 ], [ 36.101857522606622, 32.00216921783516 ], [ 36.093997571131069, 31.998036539854468 ], [ 36.082364842263701, 31.997369961454581 ], [ 36.071989707359137, 31.998036539854468 ], [ 36.064286954679289, 31.997903225253708 ], [ 36.051711032138485, 31.996436743960601 ], [ 36.043851080662876, 31.993903675714137 ], [ 36.037563119842162, 31.99070391125656 ], [ 36.031275158122128, 31.986837380440818 ], [ 36.024515600014979, 31.983504033384463 ], [ 36.01807043949924, 31.983104023032297 ], [ 36.011782478678526, 31.983904041038727 ], [ 36.005337318162731, 31.986570717064978 ], [ 35.997320167891473, 31.991770511699826 ], [ 35.98835982304746, 31.999502995966566 ], [ 35.97971387669412, 32.010567311931936 ], [ 35.976255497793034, 32.018431495617108 ], [ 35.969338740890237, 32.027627736231068 ], [ 35.953147240652697, 32.039754699220055 ], [ 35.942614906053109, 32.045484463437276 ], [ 35.933968958800449, 32.048682315036842 ], [ 35.921550235055349, 32.057875517741024 ], [ 35.918563453440697, 32.062405161868753 ], [ 35.917934658257934, 32.070398104189223 ], [ 35.913690283579797, 32.073461880361549 ], [ 35.905515933613515, 32.077191555945603 ], [ 35.897184385750847, 32.070398104189223 ], [ 35.888381239702483, 32.066002072337824 ], [ 35.883508069841582, 32.061206160535903 ], [ 35.878792098776387, 32.050281199917492 ], [ 35.872032540669295, 32.040554222599326 ], [ 35.862443399743142, 32.032958466759908 ], [ 35.853011458512071, 32.027361191565774 ], [ 35.822200448691831, 32.02602845654809 ], [ 35.807738137904778, 32.025362081394974 ], [ 35.799720987633521, 32.021230449325799 ], [ 35.7948478168733, 32.016432191192735 ], [ 35.793275827117782, 32.00776803266865 ], [ 35.792804229831404, 31.998036539854468 ], [ 35.791232239176566, 31.98963729822276 ], [ 35.789031453338964, 31.984170712508444 ], [ 35.781014303067707, 31.977637047911458 ], [ 35.762464817297541, 31.965368501954856 ], [ 35.72568024424794, 31.949763744601171 ], [ 35.672704170960799, 31.928953277771598 ], [ 35.658399059868771, 31.922815958789499 ], [ 35.653211491517197, 31.915877626251529 ], [ 35.647709525574214, 31.901599027173404 ], [ 35.648967117738323, 31.893457899062867 ], [ 35.653211491517197, 31.889053383007251 ], [ 35.661385841483423, 31.886116921159044 ], [ 35.670503385123197, 31.882646437383244 ], [ 35.679778127558563, 31.881845537141885 ], [ 35.689367268484716, 31.880777660560625 ], [ 35.69942800669719, 31.876906502732993 ], [ 35.707916754254882, 31.870231711124632 ], [ 35.713890317484243, 31.863422925927352 ], [ 35.715305108444056, 31.857014197846979 ], [ 35.713418720197808, 31.849670316032302 ], [ 35.707287958172799, 31.846064923157712 ], [ 35.700214001574977, 31.840055622668899 ], [ 35.696598423878186, 31.832176168495437 ], [ 35.694083239549911, 31.822826792222713 ], [ 35.694083239549911, 31.808266591130348 ], [ 35.694668277319181, 31.797696175638066 ], [ 35.698514604865181, 31.798180479445648 ], [ 35.707032546215089, 31.802554226996051 ], [ 35.720164372088163, 31.809491472253683 ], [ 35.734538398228551, 31.812959899279974 ], [ 35.748734967444818, 31.812658301739305 ], [ 35.75867256508684, 31.811904304739926 ], [ 35.772869134303164, 31.811451903482634 ], [ 35.781919447324697, 31.811904304739926 ], [ 35.78795298903924, 31.813864684707482 ], [ 35.791502131118534, 31.816277402979836 ], [ 35.794518901526146, 31.820650294375639 ], [ 35.798422958352887, 31.823816741649352 ], [ 35.806231071107106, 31.824118302317856 ], [ 35.810312584857968, 31.823213617614385 ], [ 35.81350681308902, 31.820650294375639 ], [ 35.816523583496632, 31.815221847110593 ], [ 35.817943240688066, 31.804816429334778 ], [ 35.817588325940562, 31.79184571790563 ], [ 35.817410869016442, 31.782342762608437 ], [ 35.819362896980181, 31.764390071444666 ], [ 35.821847296615488, 31.747037522163964 ], [ 35.824331696250852, 31.732700353838311 ], [ 35.822202211362992, 31.724096988585188 ], [ 35.815103926305198, 31.718511919889238 ], [ 35.805521242511361, 31.713530358339426 ], [ 35.798068044504703, 31.706434945716239 ], [ 35.795228730121835, 31.700395868674434 ], [ 35.792744330486528, 31.690128535503561 ], [ 35.792211959714223, 31.677443791397934 ], [ 35.793809073829721, 31.66702288279987 ], [ 35.796825844237389, 31.65780922231778 ], [ 35.799487700796817, 31.649047845281871 ], [ 35.802859385951933, 31.638019421259344 ], [ 35.806231071107106, 31.631824801073776 ], [ 35.81439409860883, 31.624269827690455 ], [ 35.824154239326731, 31.620945445076302 ], [ 35.839770464835112, 31.614598566970358 ], [ 35.851305177492009, 31.605530846671286 ], [ 35.861242775134031, 31.589811373596092 ], [ 35.861952603729719, 31.576659392117278 ], [ 35.858226004726362, 31.570158301864183 ], [ 35.855031776495366, 31.559725372927687 ], [ 35.874197144982304, 31.543393228614661 ], [ 35.869938174307379, 31.536738572826948 ], [ 35.866566489152206, 31.527814539009796 ], [ 35.860000575766037, 31.509358748207717 ], [ 35.848110949260956, 31.484089584766593 ], [ 35.843851978585974, 31.469409151511172 ], [ 35.83781843687143, 31.451850145767651 ], [ 35.828058296153472, 31.441404003991636 ], [ 35.810490041782032, 31.424596896229843 ], [ 35.824509153174915, 31.410210043059067 ], [ 35.834446751716257, 31.393851781534522 ], [ 35.838883179315303, 31.383399178129594 ], [ 35.840302836506737, 31.34976117014196 ], [ 35.837286065199805, 31.336575424516298 ], [ 35.830720152712956, 31.320204342256659 ], [ 35.826461182037974, 31.30655959974581 ], [ 35.82504152484654, 31.299888116743261 ], [ 35.825218981770661, 31.289425067712784 ], [ 35.826638638962095, 31.282904029597319 ], [ 35.829300495521522, 31.277899205284143 ], [ 35.845449092701529, 31.272590768948874 ], [ 35.872600030866806, 31.270922341293044 ], [ 35.904364853555194, 31.272135746167805 ], [ 36.02876228774943, 31.274410838489473 ], [ 36.143044667377524, 31.27410749536466 ], [ 36.344048118825697, 31.273840885048855 ], [ 36.466656425553651, 31.273100296941209 ], [ 36.62262458895367, 31.269026958027723 ], [ 36.803287712158237, 31.266805062403762 ], [ 37.001713875694861, 31.265323770175883 ], [ 37.088362856060996, 31.264953442847172 ], [ 37.245789602907905, 31.268742117554723 ] ] ] } }, +{ "type": "Feature", "properties": { "shapeName": "Zarqa", "shapeISO": "JO-AZ", "shapeID": "50493656B99152079712432", "shapeGroup": "JOR", "shapeType": "ADM1" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 35.905515933613515, 32.077191555945603 ], [ 35.913690283579797, 32.073461880361549 ], [ 35.917934658257934, 32.070398104189223 ], [ 35.918563453440697, 32.062405161868753 ], [ 35.921550235055349, 32.057875517741024 ], [ 35.933968958800449, 32.048682315036842 ], [ 35.942614906053109, 32.045484463437276 ], [ 35.953147240652697, 32.039754699220055 ], [ 35.969338740890237, 32.027627736231068 ], [ 35.976255497793034, 32.018431495617108 ], [ 35.97971387669412, 32.010567311931936 ], [ 35.98835982304746, 31.999502995966566 ], [ 35.997320167891473, 31.991770511699826 ], [ 36.005337318162731, 31.986570717064978 ], [ 36.011782478678526, 31.983904041038727 ], [ 36.01807043949924, 31.983104023032297 ], [ 36.024515600014979, 31.983504033384463 ], [ 36.031275158122128, 31.986837380440818 ], [ 36.037563119842162, 31.99070391125656 ], [ 36.043851080662876, 31.993903675714137 ], [ 36.051711032138485, 31.996436743960601 ], [ 36.064286954679289, 31.997903225253708 ], [ 36.071989707359137, 31.998036539854468 ], [ 36.082364842263701, 31.997369961454581 ], [ 36.093997571131069, 31.998036539854468 ], [ 36.101857522606622, 32.00216921783516 ], [ 36.106573493671874, 32.007501430446723 ], [ 36.109560275286526, 32.012433450143646 ], [ 36.114119046656754, 32.017365205439944 ], [ 36.118992216517654, 32.020830603549541 ], [ 36.125437377033393, 32.023096370800943 ], [ 36.134869318264464, 32.023096370800943 ], [ 36.144144061599206, 32.021363730651672 ], [ 36.150274823624272, 32.018964636209034 ], [ 36.156719983240691, 32.016432191192735 ], [ 36.16316514375643, 32.014432841802261 ], [ 36.169453104577144, 32.013499797877444 ], [ 36.182186225913654, 32.014032967247715 ], [ 36.203408095707118, 32.017898352327165 ], [ 36.218656401371902, 32.021896854156523 ], [ 36.22635915405175, 32.027227919233155 ], [ 36.230603526931247, 32.032691937383049 ], [ 36.233904707935949, 32.042553000920293 ], [ 36.237205887142011, 32.049481761074446 ], [ 36.241764659411558, 32.05534414831385 ], [ 36.247738221741599, 32.059207789607854 ], [ 36.256384168094939, 32.063737367185809 ], [ 36.267073702389496, 32.064936336143035 ], [ 36.2747764550694, 32.064803118669033 ], [ 36.285780386955366, 32.060939713896744 ], [ 36.301343091110823, 32.057342603778181 ], [ 36.312032625405379, 32.055877073967849 ], [ 36.323665352474109, 32.056276765960035 ], [ 36.340485648793731, 32.058275201639276 ], [ 36.356048352949188, 32.061339384305199 ], [ 36.366423489652391, 32.062938046153931 ], [ 36.3774274215383, 32.062938046153931 ], [ 36.386230566687345, 32.060406817021033 ], [ 36.397077299777607, 32.055210916450676 ], [ 36.421914746368486, 32.037222828870483 ], [ 36.467816863057863, 31.995103558382539 ], [ 36.514504975524233, 31.95123097143221 ], [ 36.529281683902639, 31.936424243683973 ], [ 36.534626450150597, 31.929486938171692 ], [ 36.481335979272103, 31.90440154309681 ], [ 36.474104824777896, 31.901065203996041 ], [ 36.467030868180075, 31.89786220467704 ], [ 36.459799711887229, 31.894659094741485 ], [ 36.451153766433208, 31.884248215382911 ], [ 36.441879023098465, 31.867428154685626 ], [ 36.443922610140419, 31.859684555697754 ], [ 36.462786493501937, 31.844596019091057 ], [ 36.493597504221498, 31.814945866758421 ], [ 36.532582863108701, 31.783148190936288 ], [ 36.548145567264157, 31.772457439859011 ], [ 36.557263110903875, 31.768314441258497 ], [ 36.567323848217086, 31.759894228336009 ], [ 36.593418887871451, 31.746794596393556 ], [ 36.607723998963422, 31.742249393095051 ], [ 36.61338316460143, 31.741580962091803 ], [ 36.656770096962475, 31.7621664248407 ], [ 36.699685431137766, 31.781010139106684 ], [ 36.757377475490159, 31.729414673548376 ], [ 36.829846228220902, 31.664010235783792 ], [ 36.909860533936524, 31.59119532770228 ], [ 36.987831252610249, 31.520735576785512 ], [ 37.008312281586598, 31.502923036868708 ], [ 37.292908603948945, 31.576137743062418 ], [ 37.619873113853146, 31.654538665027417 ], [ 37.814897014385735, 31.700528244383008 ], [ 37.73043946780723, 31.725403458902576 ], [ 37.608295821894728, 31.759359585876211 ], [ 37.465873501660838, 31.797177926020538 ], [ 37.330210739534039, 31.833645270412944 ], [ 37.188417214482911, 31.872768188701002 ], [ 37.048510077677975, 31.914276398636957 ], [ 36.900428592705453, 31.961500903643866 ], [ 36.800764407851204, 31.995103558382539 ], [ 36.687581106782716, 32.034291101053498 ], [ 36.571725421690928, 32.074927128684067 ], [ 36.47206123683668, 32.108355038854029 ], [ 36.460900105255689, 32.111550692510491 ], [ 36.453826149557187, 32.115012524808208 ], [ 36.448638581205614, 32.120205025941232 ], [ 36.444079808936067, 32.125264101856885 ], [ 36.44093582852571, 32.13498206706879 ], [ 36.439521037565896, 32.14323486759514 ], [ 36.437791848115353, 32.146429299972283 ], [ 36.43228988217237, 32.150555276205068 ], [ 36.427573912006494, 32.152551648839562 ], [ 36.418456367467456, 32.15321709679165 ], [ 36.409024426236329, 32.153483274533528 ], [ 36.401950469638507, 32.152019287060511 ], [ 36.395190911531415, 32.151087646078054 ], [ 36.387959756137889, 32.151220738546272 ], [ 36.380257003457984, 32.152418558169984 ], [ 36.371611057104644, 32.153882539347762 ], [ 36.333411692195909, 32.151886196390876 ], [ 36.328695722029977, 32.149756714201033 ], [ 36.324294149455511, 32.145630701995344 ], [ 36.319420978695234, 32.141504503630017 ], [ 36.31344741636525, 32.138443009937021 ], [ 36.308417046809325, 32.136712555140377 ], [ 36.301971886293586, 32.135913872627157 ], [ 36.295998323064225, 32.135780757675889 ], [ 36.288609969774313, 32.136046986679162 ], [ 36.280435619808031, 32.137111893699 ], [ 36.269117289431392, 32.141105183957109 ], [ 36.249624609987791, 32.149091241067993 ], [ 36.238149080815504, 32.154681065378895 ], [ 36.228402741093703, 32.159072829047886 ], [ 36.212997235733894, 32.162399781924421 ], [ 36.203250896911413, 32.162932083448936 ], [ 36.189888978593558, 32.16306515793076 ], [ 36.172597084987558, 32.161202092702467 ], [ 36.162693546470052, 32.160137467170443 ], [ 36.141786076066637, 32.154148715291058 ], [ 36.126694969197501, 32.14922433623417 ], [ 36.118049021944842, 32.146828596262765 ], [ 36.112547056901235, 32.145896903119649 ], [ 36.106101896385439, 32.145896903119649 ], [ 36.099342337379028, 32.146828596262765 ], [ 36.092897177762609, 32.150155996102399 ], [ 36.086923614533248, 32.154281803262677 ], [ 36.080006857630451, 32.15933898970269 ], [ 36.076548478729364, 32.163198232412526 ], [ 36.074819289278821, 32.16665810418823 ], [ 36.070574915500003, 32.17078316401188 ], [ 36.067116537498237, 32.17277909417993 ], [ 36.064758551066348, 32.173045215264551 ], [ 36.06019977969612, 32.170916228601129 ], [ 36.055169411039515, 32.166791174173397 ], [ 36.052654225811921, 32.16306515793076 ], [ 36.049038648115186, 32.159205909824948 ], [ 36.043379483376498, 32.156011925310167 ], [ 36.037563119842162, 32.154414891234296 ], [ 36.031117959326423, 32.154281803262677 ], [ 36.026401988261227, 32.154281803262677 ], [ 36.020900022318244, 32.155346497143171 ], [ 36.014454861802506, 32.15681043155621 ], [ 36.008166900981735, 32.160137467170443 ], [ 35.999835352219804, 32.165194328955181 ], [ 35.992604196826278, 32.17171460354615 ], [ 35.991189405866464, 32.176238602629439 ], [ 35.992761395621983, 32.183157223826868 ], [ 35.994333386276821, 32.18754761513037 ], [ 35.997477366687178, 32.191937795093224 ], [ 35.999049357342017, 32.19446537747524 ], [ 36.000306949506182, 32.200052416585834 ], [ 36.000306949506182, 32.203111840938732 ], [ 35.998106162769261, 32.206836218616672 ], [ 35.994804982663879, 32.209496394343148 ], [ 35.988517021843109, 32.212023489292676 ], [ 35.981914662531722, 32.213619513429876 ], [ 35.972954317687652, 32.213619513429876 ], [ 35.96583260349189, 32.213206810046302 ], [ 35.966666356866938, 32.209629401375821 ], [ 35.966351958376208, 32.199121267532519 ], [ 35.964465570130017, 32.188744958113375 ], [ 35.959120802982738, 32.176903877012364 ], [ 35.949688861751611, 32.171448479763569 ], [ 35.93994252113049, 32.170117844662855 ], [ 35.930196181408689, 32.169319455328662 ], [ 35.923908220587975, 32.166125825146764 ], [ 35.916519866398744, 32.161468247061975 ], [ 35.905830332104188, 32.154947238624231 ], [ 35.89294001197203, 32.144965199184639 ], [ 35.882093278881769, 32.136313214783115 ], [ 35.875490919570325, 32.128059787429322 ], [ 35.868731361463233, 32.119006782736903 ], [ 35.869202957850291, 32.107289796387022 ], [ 35.870303351218752, 32.101031244296564 ], [ 35.876591312938785, 32.094772263229402 ], [ 35.885551656883536, 32.08718100939609 ], [ 35.896398389973797, 32.081720244094015 ], [ 35.905515933613515, 32.077191555945603 ] ] ] } } +] +} diff --git a/fix_exact_border.sh b/fix_exact_border.sh new file mode 100755 index 0000000..5d2cd2d --- /dev/null +++ b/fix_exact_border.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -e + +# ============================================================================== +# Script: fix_exact_border.sh +# Purpose: Clean rogue lines and set exact straight border segment: +# From (36.839237, 32.311852) to (38.793024, 33.371104) +# ============================================================================== + +echo "=================================================================" +echo "🇯🇴 Applying Exact Jordan-Syria Border Fix..." +echo "=================================================================" + +if [ -f .env ]; then + export $(grep -v '^#' .env | xargs) +fi + +DB_USER=${POSTGRES_USER:-postgres} +DB_NAME=${POSTGRES_DB:-gis} + +docker exec -i map-db psql -U "$DB_USER" -d "$DB_NAME" << 'EOF' +BEGIN; + +-- 1. Remove all dummy / experimental lines previously added +DELETE FROM planet_osm_line WHERE osm_id >= 900000; +DELETE FROM planet_osm_polygon WHERE osm_id >= 900000; + +-- 2. Remove any rogue lines north of the border line in the desert area +-- (Bounding box covering the false upper lines in Syria) +DELETE FROM planet_osm_line +WHERE boundary = 'administrative' + AND admin_level IN ('2', '3', '4', '5') + AND ST_Intersects( + way, + ST_Transform( + ST_MakeEnvelope(36.80, 32.35, 38.85, 33.70, 4326), + 3857 + ) + ) + AND NOT ST_Intersects( + way, + ST_Transform( + ST_MakeEnvelope(35.5, 31.0, 36.80, 33.0, 4326), + 3857 + ) + ); + +-- 3. Insert the EXACT official straight border segment from user coordinates: +-- Point A: (36.839237, 32.311852) -> Point B: (38.793024, 33.371104) +INSERT INTO planet_osm_line (osm_id, boundary, admin_level, name, way) +VALUES ( + 999555, + 'administrative', + '2', + 'Jordan - Syria International Border', + ST_Transform( + ST_Segmentize( + ST_GeomFromText('LINESTRING(36.839237 32.311852, 38.793024 33.371104)', 4326), + 1000 + ), + 3857 + ) +); + +COMMIT; +EOF + +echo "Restarting Martin..." +docker compose restart martin + +echo "=================================================================" +echo "✅ Exact border fixed and applied successfully!" +echo "=================================================================" diff --git a/import_official_boundaries.sh b/import_official_boundaries.sh new file mode 100755 index 0000000..b61d66d --- /dev/null +++ b/import_official_boundaries.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -e + +# ============================================================================== +# Script: import_official_boundaries.sh +# Purpose: Import and standardize Jordan Official International & Governorate Boundaries +# Source: UN geoBoundaries Official ADM0 (National) & ADM1 (12 Governorates) +# ============================================================================== + +echo "=================================================================" +echo "🇯🇴 Importing Official Jordan International & Governorate Boundaries..." +echo "=================================================================" + +if [ -f .env ]; then + export $(grep -v '^#' .env | xargs) +fi + +DB_USER=${POSTGRES_USER:-postgres} +DB_NAME=${POSTGRES_DB:-gis} + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SQL_FILE="$SCRIPT_DIR/data/boundaries/import_official_jordan.sql" + +if [ ! -f "$SQL_FILE" ]; then + echo "Generating SQL from official GeoJSON files..." + python3 "$SCRIPT_DIR/data/boundaries/generate_sql.py" +fi + +echo "1. Inserting official Jordan National Boundary & 12 Governorates into PostGIS..." +docker exec -i map-db psql -U "$DB_USER" -d "$DB_NAME" < "$SQL_FILE" + +echo "2. Restarting Martin Tile Server to apply updated boundary tiles..." +docker compose restart martin + +echo "=================================================================" +echo "✅ Official Jordan Boundaries applied successfully!" +echo "Refresh your browser at https://map-saas.intaleqapp.com/#compare" +echo "=================================================================" diff --git a/restore_osm_roads.sh b/restore_osm_roads.sh new file mode 100755 index 0000000..d987c6b --- /dev/null +++ b/restore_osm_roads.sh @@ -0,0 +1,102 @@ +#!/usr/bin/env bash +set -e + +# ============================================================================== +# Script: restore_osm_roads.sh +# Purpose: Restore all OSM roads for Jordan & Syria cleanly using osm2pgsql, +# then apply the exact border line without deleting any roads! +# ============================================================================== + +echo "=================================================================" +echo "🔄 Restoring OSM Road Network & Setting Official Jordan Border..." +echo "=================================================================" + +cd "$(dirname "$0")" + +if [ -f .env ]; then + export $(grep -v '^#' .env | xargs) +fi + +DB_USER=${POSTGRES_USER:-mapuser} +DB_NAME=${POSTGRES_DB:-mapdb} +DATA_DIR="./infrastructure/osm-data" + +mkdir -p "$DATA_DIR" + +# Download Jordan PBF if not present or corrupt +if [ ! -s "${DATA_DIR}/jordan-latest.osm.pbf" ]; then + echo "📥 Downloading Jordan OSM data..." + wget -q --show-progress -O "${DATA_DIR}/jordan-latest.osm.pbf" "https://download.geofabrik.de/asia/jordan-latest.osm.pbf" +fi + +if [ ! -s "${DATA_DIR}/syria-latest.osm.pbf" ]; then + echo "📥 Downloading Syria OSM data..." + wget -q --show-progress -O "${DATA_DIR}/syria-latest.osm.pbf" "https://download.geofabrik.de/asia/syria-latest.osm.pbf" +fi + +if [ ! -s "${DATA_DIR}/egypt-latest.osm.pbf" ]; then + echo "📥 Downloading Egypt OSM data..." + wget -q --show-progress -O "${DATA_DIR}/egypt-latest.osm.pbf" "https://download.geofabrik.de/africa/egypt-latest.osm.pbf" || true +fi + +if [ ! -s "${DATA_DIR}/iraq-latest.osm.pbf" ]; then + echo "📥 Downloading Iraq OSM data..." + wget -q --show-progress -O "${DATA_DIR}/iraq-latest.osm.pbf" "https://download.geofabrik.de/asia/iraq-latest.osm.pbf" || true +fi + +echo "🚀 Importing Jordan OSM roads into PostGIS..." +docker compose --profile import run --rm osm-import \ + osm2pgsql --create --slim --cache 1000 \ + --database "$DB_NAME" --host db --user "$DB_USER" \ + /data/jordan-latest.osm.pbf + +echo "🚀 Importing Syria OSM roads into PostGIS (--append)..." +docker compose --profile import run --rm osm-import \ + osm2pgsql --append --slim --cache 1000 \ + --database "$DB_NAME" --host db --user "$DB_USER" \ + /data/syria-latest.osm.pbf + +if [ -s "${DATA_DIR}/egypt-latest.osm.pbf" ]; then + echo "🚀 Importing Egypt OSM data (--append)..." + docker compose --profile import run --rm osm-import \ + osm2pgsql --append --slim --cache 1000 \ + --database "$DB_NAME" --host db --user "$DB_USER" \ + /data/egypt-latest.osm.pbf || true +fi + +if [ -s "${DATA_DIR}/iraq-latest.osm.pbf" ]; then + echo "🚀 Importing Iraq OSM data (--append)..." + docker compose --profile import run --rm osm-import \ + osm2pgsql --append --slim --cache 1000 \ + --database "$DB_NAME" --host db --user "$DB_USER" \ + /data/iraq-latest.osm.pbf || true +fi + +echo "📍 Applying exact straight Jordan-Syria border segment from user coordinates..." +docker exec -i map-db psql -U "$DB_USER" -d "$DB_NAME" << 'EOF' +-- Insert the official straight border line: +-- Point A: (36.839237, 32.311852) -> Point B: (38.793024, 33.371104) +DELETE FROM planet_osm_line WHERE name = 'Jordan - Syria Official Border'; + +INSERT INTO planet_osm_line (osm_id, boundary, admin_level, name, way) +VALUES ( + -9999991, + 'administrative', + '2', + 'Jordan - Syria Official Border', + ST_Transform( + ST_Segmentize( + ST_GeomFromText('LINESTRING(36.839237 32.311852, 38.793024 33.371104)', 4326), + 1000 + ), + 3857 + ) +); +EOF + +echo "🔄 Restarting Martin to refresh vector tiles..." +docker compose restart martin + +echo "=================================================================" +echo "✅ All OSM Roads restored and official border applied perfectly!" +echo "=================================================================" diff --git a/revert_boundaries.sh b/revert_boundaries.sh new file mode 100755 index 0000000..8afccac --- /dev/null +++ b/revert_boundaries.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -e + +# ============================================================================== +# Script: revert_boundaries.sh +# Purpose: Completely remove custom inserted lines and restore clean original boundaries +# ============================================================================== + +echo "=================================================================" +echo "🔄 Reverting all boundary changes to original clean OSM state..." +echo "=================================================================" + +if [ -f .env ]; then + export $(grep -v '^#' .env | xargs) +fi + +DB_USER=${POSTGRES_USER:-postgres} +DB_NAME=${POSTGRES_DB:-gis} + +docker exec -i map-db psql -U "$DB_USER" -d "$DB_NAME" << 'EOF' +BEGIN; + +-- 1. Remove all custom lines and polygons added +DELETE FROM planet_osm_line WHERE osm_id >= 999000; +DELETE FROM planet_osm_polygon WHERE osm_id >= 999000; + +-- 2. Restore Jordan & Syria national boundary line directly from the relation polygons +INSERT INTO planet_osm_line (osm_id, boundary, admin_level, name, way) +SELECT + 900001, + 'administrative', + '2', + p.name, + ST_Boundary(p.way) +FROM planet_osm_polygon p +WHERE p.boundary = 'administrative' + AND p.admin_level = '2' + AND (p.name ILIKE '%Jordan%' OR p.name ILIKE '%الأردن%' OR p.name ILIKE '%Syria%' OR p.name ILIKE '%سوريا%') +ON CONFLICT DO NOTHING; + +COMMIT; +EOF + +echo "Restarting Martin..." +docker compose restart martin + +echo "=================================================================" +echo "✅ Reverted successfully to original clean map boundaries!" +echo "=================================================================" diff --git a/style.json b/style.json index d11c30a..75967a3 100644 --- a/style.json +++ b/style.json @@ -148,17 +148,17 @@ "type": "line", "source": "local-osm-polygons", "source-layer": "planet_osm_polygon", - "minzoom": 5, + "minzoom": 6, "filter": [ "all", ["==", "boundary", "administrative"], ["in", "admin_level", "4", 4, "5", 5] ], "paint": { - "line-color": "#4f46e5", - "line-width": 2.2, - "line-dasharray": [4, 2], - "line-opacity": 0.9 + "line-color": "#6366f1", + "line-width": 1.4, + "line-dasharray": [4, 3], + "line-opacity": 0.7 } }, { @@ -166,16 +166,17 @@ "type": "line", "source": "local-osm-lines", "source-layer": "planet_osm_line", - "minzoom": 5, + "minzoom": 6, "filter": [ "all", ["==", "boundary", "administrative"], ["in", "admin_level", "4", 4, "5", 5] ], "paint": { - "line-color": "#4f46e5", - "line-width": 2.2, - "line-dasharray": [4, 2] + "line-color": "#6366f1", + "line-width": 1.4, + "line-dasharray": [4, 3], + "line-opacity": 0.7 } }, { diff --git a/sync_to_server.sh b/sync_to_server.sh index 531640f..d187848 100755 --- a/sync_to_server.sh +++ b/sync_to_server.sh @@ -29,6 +29,10 @@ rsync -avz --progress -e "ssh -o StrictHostKeyChecking=no" $KEY_FLAG \ docker-compose.yml \ docker-compose.map2.yml \ setup_map2.sh \ + import_official_boundaries.sh \ + revert_boundaries.sh \ + fix_exact_border.sh \ + restore_osm_roads.sh \ style.json \ style-dark.json \ apps \