Route Calculation and Optimization
This guide explains how to use the route calculation and optimization features in the Core package.
Overview
The RouteCalculator service integrates with Google Route Optimization API to solve Vehicle Routing Problems (VRP). It supports:
- ✅ Multi-vehicle route optimization
- ✅ Capacity constraints (soft/hard limits)
- ✅ Cost optimization (distance, duration, penalties)
- ✅ Both old and new Google API formats
- ✅ Mock mode for development/testing
- ✅ Comprehensive error handling
Installation
bash
npm install @route-optimization/coreQuick Start
Basic Usage (Mock Mode)
typescript
import { RouteCalculator } from '@route-optimization/core';
// Create calculator instance (mock mode for testing)
const calculator = new RouteCalculator({
useMockMode: true,
debug: true,
});
// Define optimization request
const request = {
shipments: [
{
id: 'shipment-1',
deliveryLocation: { latitude: 13.7563, longitude: 100.5018 },
},
{
id: 'shipment-2',
deliveryLocation: { latitude: 13.7467, longitude: 100.5342 },
},
],
vehicles: [
{
id: 'vehicle-1',
startLocation: { latitude: 13.7563, longitude: 100.5018 },
},
],
};
// Optimize routes
const response = await calculator.optimizeRoutes(request);
if (response.success) {
console.log('Optimized routes:', response.routes);
console.log('Metrics:', response.metrics);
console.log('Statistics:', response.statistics);
}Production Usage (Google API)
For production use, you need to authenticate with Google Cloud. See the Authentication Guide for detailed setup instructions.
Using API Key (Simpler)
typescript
import { RouteCalculator } from '@route-optimization/core';
const calculator = new RouteCalculator({
projectId: 'your-project-id',
apiKey: 'YOUR_API_KEY',
debug: true,
});
await calculator.initialize();Using Service Account (More Secure)
typescript
import { RouteCalculator } from '@route-optimization/core';
const calculator = new RouteCalculator({
projectId: 'your-project-id',
credentialsPath: './service-account-key.json',
debug: true,
});
await calculator.initialize();
// Optimize routes
const response = await calculator.optimizeRoutes(request);Configuration
RouteCalculatorConfig
typescript
interface RouteCalculatorConfig {
/** Google Cloud project ID */
projectId?: string;
/** Path to service account key file */
credentialsPath?: string;
/** Service account key JSON object */
credentials?: object;
/** Use mock mode (for testing without API calls) */
useMockMode?: boolean;
/** Default search mode */
defaultSearchMode?: 'RETURN_FAST' | 'CONSUME_ALL_AVAILABLE_TIME';
/** Default timeout (e.g., "30s") */
defaultTimeout?: string;
/** Enable debug logging */
debug?: boolean;
}Request Format
Shipments
typescript
// Old Format (Backward Compatible)
const shipment = {
id: 'shipment-1',
pickupLocation: { latitude: 13.7563, longitude: 100.5018 },
deliveryLocation: { latitude: 13.7467, longitude: 100.5342 },
demands: [{ type: 'weight', value: 10 }],
label: 'Package #1',
};
// New Format (Google API Standard)
const shipment = {
id: 'shipment-1',
pickups: [
{
location: { latitude: 13.7563, longitude: 100.5018 },
duration: '300s',
},
],
deliveries: [
{
location: { latitude: 13.7467, longitude: 100.5342 },
duration: '300s',
},
],
demands: [{ type: 'weight', value: 10 }],
};Vehicles
typescript
const vehicle = {
id: 'vehicle-1',
startLocation: { latitude: 13.7563, longitude: 100.5018 },
endLocation: { latitude: 13.7563, longitude: 100.5018 }, // Optional
// Load limits with soft/hard constraints
loadLimits: {
weight: {
softMaxLoad: 100, // Soft limit (generates penalty)
hardMaxLoad: 150, // Hard limit (cannot exceed)
costPerUnitAboveSoftMax: 50, // Penalty cost
},
},
// Cost configuration
fixedCost: 1000, // Fixed cost per vehicle
costPerKilometer: 5, // Cost per km
costPerHour: 50, // Cost per hour
// Travel mode
travelMode: 'DRIVING', // DRIVING, WALKING, BICYCLING, TRANSIT
// Time constraints
maxRouteDuration: '28800s', // 8 hours max
};Optimization Options
typescript
const request = {
shipments: [...],
vehicles: [...],
// Global cost per hour
globalDurationCostPerHour: 10,
// Search mode
searchMode: 'RETURN_FAST', // or 'CONSUME_ALL_AVAILABLE_TIME'
// Timeout
timeout: '30s',
// Traffic consideration
considerTraffic: true,
};Response Format
typescript
interface OptimizationResponse {
success: boolean;
// Optimized routes
routes?: Array<{
vehicleId: string;
shipmentIds: string[];
stops: number;
totalDistance?: number; // meters
totalDuration?: string; // e.g., "3600s"
cost?: number;
}>;
// Overall metrics
metrics?: {
totalCost: number;
totalDistance?: number;
totalDuration?: string;
usedVehicles: number;
skippedShipments: number;
optimizationDuration?: string;
};
// Statistics
statistics?: {
averageStopsPerVehicle: number;
maxStopsInRoute: number;
minStopsInRoute: number;
utilizationRate: number;
};
// Skipped shipments (if any)
skippedShipments?: Array<{
id: string;
reason?: string;
}>;
// Error (if failed)
error?: string;
}Examples
Multi-Vehicle Optimization
typescript
const request = {
shipments: Array.from({ length: 100 }, (_, i) => ({
id: `shipment-${i + 1}`,
deliveryLocation: {
latitude: 13.75 + Math.random() * 0.1,
longitude: 100.5 + Math.random() * 0.1,
},
demands: [{ type: 'stops', value: 1 }],
})),
vehicles: Array.from({ length: 20 }, (_, i) => ({
id: `vehicle-${i + 1}`,
startLocation: { latitude: 13.7563, longitude: 100.5018 },
loadLimits: {
stops: {
softMaxLoad: 5,
hardMaxLoad: 10,
costPerUnitAboveSoftMax: 500,
},
},
})),
globalDurationCostPerHour: 10,
};
const response = await calculator.optimizeRoutes(request);
console.log(`Total cost: ${response.metrics?.totalCost}`);
console.log(`Used vehicles: ${response.metrics?.usedVehicles} / 20`);
console.log(`Average stops per vehicle: ${response.statistics?.averageStopsPerVehicle}`);With Pickup and Delivery
typescript
const request = {
shipments: [
{
id: 'shipment-1',
pickups: [
{
location: { latitude: 13.7563, longitude: 100.5018 },
duration: '300s',
timeWindows: [
{
startTime: '2024-01-01T08:00:00Z',
endTime: '2024-01-01T10:00:00Z',
},
],
},
],
deliveries: [
{
location: { latitude: 13.7467, longitude: 100.5342 },
duration: '300s',
timeWindows: [
{
startTime: '2024-01-01T14:00:00Z',
endTime: '2024-01-01T16:00:00Z',
},
],
},
],
},
],
vehicles: [
{
id: 'vehicle-1',
startLocation: { latitude: 13.7563, longitude: 100.5018 },
},
],
};Custom Search Mode
typescript
// Fast optimization (good for quick results)
const fastRequest = {
...request,
searchMode: 'RETURN_FAST',
timeout: '10s',
};
// Thorough optimization (better quality)
const thoroughRequest = {
...request,
searchMode: 'CONSUME_ALL_AVAILABLE_TIME',
timeout: '120s',
};Error Handling
typescript
const response = await calculator.optimizeRoutes(request);
if (!response.success) {
console.error('Optimization failed:', response.error);
// Check specific error types
if (response.error?.includes('not enabled')) {
console.log('Enable Route Optimization API in Google Cloud Console');
} else if (response.error?.includes('billing')) {
console.log('Enable billing or use mock mode');
} else if (response.error?.includes('UNAUTHENTICATED')) {
console.log('Check your service account credentials');
}
}Mock Mode vs Production
Mock Mode (Development)
✅ Pros:
- No Google Cloud account needed
- No API costs
- Fast testing
- Predictable results
❌ Cons:
- Simple round-robin distribution
- Not optimized routes
- No actual distance/duration calculation
Production Mode (Google API)
✅ Pros:
- Real optimization algorithms
- Accurate distance/duration
- Handles complex constraints
- Traffic consideration
❌ Cons:
- Requires Google Cloud setup
- API usage costs
- Network dependency
Google Cloud Setup
Create Google Cloud Project
https://console.cloud.google.comEnable Route Optimization API
https://console.cloud.google.com/apis/library/cloudoptimization.googleapis.comCreate Service Account
- Go to IAM & Admin > Service Accounts
- Create new service account
- Grant "Cloud Optimization AI Admin" role
- Create JSON key
Enable Billing
- Required for API usage
- Set up billing account
- Monitor usage in Cloud Console
Best Practices
1. Use Mock Mode for Development
typescript
const isDevelopment = process.env.NODE_ENV === 'development';
const calculator = new RouteCalculator({
useMockMode: isDevelopment,
projectId: process.env.GOOGLE_CLOUD_PROJECT_ID,
credentialsPath: process.env.GOOGLE_APPLICATION_CREDENTIALS,
});2. Handle Errors Gracefully
typescript
try {
const response = await calculator.optimizeRoutes(request);
if (response.success) {
// Use optimized routes
} else {
// Fall back to simple routing
console.warn('Optimization failed, using fallback');
}
} catch (error) {
console.error('Unexpected error:', error);
}3. Monitor Skipped Shipments
typescript
if (response.skippedShipments && response.skippedShipments.length > 0) {
console.warn(`${response.skippedShipments.length} shipments could not be assigned`);
response.skippedShipments.forEach((s) => {
console.log(`- ${s.id}: ${s.reason}`);
});
}4. Update Configuration Dynamically
typescript
// Start with mock mode
calculator.updateConfig({ useMockMode: true });
// Switch to production when ready
calculator.updateConfig({
useMockMode: false,
projectId: 'production-project',
});
// Re-initialize for new config
await calculator.initialize();Performance Tips
- Batch Requests: Optimize multiple routes in single request
- Use Fast Mode: For real-time scenarios, use
RETURN_FAST - Set Timeouts: Prevent long-running optimizations
- Cache Results: Store optimization results when possible
- Monitor Costs: Track API usage in Google Cloud Console