# Route Planning Feature with Optimization This feature allows you to plan routes between multiple project locations using OpenRouteService, with automatic optimization to find the fastest route regardless of point addition order. ## Setup 1. **Get an API Key**: - Visit [OpenRouteService](https://openrouteservice.org/) - Sign up for a free account - Generate an API key 2. **Configure Environment**: - Copy `.env.example` to `.env.local` - Add your API key: `NEXT_PUBLIC_ORS_API_KEY=your_actual_api_key` 3. **Install Dependencies**: ```bash npm install @mapbox/polyline ``` 4. **Restart Development Server**: ```bash npm run dev ``` ## How to Use ### Basic Routing (2 Points) 1. **Select Route Tool**: Click the route icon in the tool panel (looks like a path) 2. **Add Projects**: Click on project markers to add them to your route 3. **Calculate Route**: Click "Calculate Route" to get directions 4. **View Results**: See distance, duration, and route path on the map ### Optimized Routing (3+ Points) 1. **Select Route Tool**: Click the route icon in the tool panel 2. **Add Projects**: Click on project markers (order doesn't matter) 3. **Find Optimal Route**: Click "Find Optimal Route" - system automatically finds fastest path 4. **View Optimization Results**: See which route order was selected and performance stats ## Features ### Core Features - **Multi-point routing**: Plan routes through multiple project locations - **Visual route display**: Blue dashed line shows the calculated route - **Route markers**: Green start marker, red end marker - **Route information**: Distance and estimated travel time - **Interactive management**: Add/remove projects from route - **Map auto-fit**: Automatically adjusts map view to show entire route ### Optimization Features ✨ - **Hybrid Optimization**: Uses ORS Optimization API first, falls back to permutation testing - **Smart Fallback**: Automatically switches to proven permutation method if ORS fails - **Order Detection**: Clearly shows when route order was actually optimized vs unchanged - **Large Point Support**: Can handle up to 50+ points with ORS API - **Performance Monitoring**: Detailed logging of optimization approach and results - **Real-time Progress**: Shows "Finding Optimal Route..." during calculation ## Technical Implementation ### Core Functions #### `calculateRoute()` Main function that handles both basic and optimized routing with hybrid approach: ```javascript const calculateRoute = async () => { // For 2 points: direct calculation if (coordinates.length === 2) { const routeData = await calculateRouteForCoordinates(coordinates); setRouteData({...routeData, optimized: false}); return; } // For 3+ points: try ORS Optimization API first let optimizationRequest = { jobs: coordinates.map((coord, index) => ({ id: index, location: coord, service: 0 })), vehicles: [{ id: 0, profile: 'driving-car', // No fixed start/end for true optimization capacity: [coordinates.length] }], options: { g: true } }; try { const optimizationResponse = await fetch('https://api.openrouteservice.org/optimization', { method: 'POST', headers: { 'Authorization': process.env.NEXT_PUBLIC_ORS_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify(optimizationRequest) }); const optimizationData = await optimizationResponse.json(); // Extract optimized order from ORS response const optimizedCoordinates = extractOptimizedOrder(optimizationData, coordinates); // Check if order actually changed const orderChanged = detectOrderChange(coordinates, optimizedCoordinates); if (orderChanged) { // Use optimized order const routeData = await calculateRouteForCoordinates(optimizedCoordinates); setRouteData({...routeData, optimized: true, optimizationStats: { method: 'ORS_Optimization_API', totalJobs: coordinates.length, duration: optimizationData.routes[0].duration, distance: optimizationData.routes[0].distance }}); } else { // Fallback to permutation testing console.log('ORS optimization did not change order, trying permutations...'); const bestRoute = await findOptimalRouteByPermutations(coordinates); const routeData = await calculateRouteForCoordinates(bestRoute); setRouteData({...routeData, optimized: true, optimizationStats: { method: 'Permutation_Testing', totalJobs: coordinates.length, duration: routeData.summary.total_duration, distance: routeData.summary.total_distance }}); } } catch (error) { // Complete fallback to permutations console.log('ORS optimization failed, using permutation fallback...'); const bestRoute = await findOptimalRouteByPermutations(coordinates); const routeData = await calculateRouteForCoordinates(bestRoute); setRouteData({...routeData, optimized: true, optimizationStats: { method: 'Permutation_Testing', totalJobs: coordinates.length, duration: routeData.summary.total_duration, distance: routeData.summary.total_distance }}); } }; ``` #### `calculateRouteForCoordinates(coordinates)` Handles individual OpenRouteService Directions API calls: ```javascript const calculateRouteForCoordinates = async (coordinates) => { const requestBody = { coordinates: coordinates, format: 'geojson', instructions: true, geometry_simplify: false, continue_straight: false, roundabout_exits: true, attributes: ['avgspeed', 'percentage'] }; const response = await fetch('https://api.openrouteservice.org/v2/directions/driving-car', { method: 'POST', headers: { 'Authorization': process.env.NEXT_PUBLIC_ORS_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify(requestBody) }); return await response.json(); }; ``` ### UI Components #### Dynamic Button Text ```javascript {routeProjects.length > 2 ? 'Find Optimal Route' : 'Calculate Route'} ``` #### Optimization Status Display ```javascript {routeData.optimized && (