diff --git a/route_planning_readme.md b/route_planning_readme.md new file mode 100644 index 0000000..9b4191b --- /dev/null +++ b/route_planning_readme.md @@ -0,0 +1,308 @@ +# 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 && ( +