Skip to content

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/core

Quick 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 ​

  1. Create Google Cloud Project

    https://console.cloud.google.com
  2. Enable Route Optimization API

    https://console.cloud.google.com/apis/library/cloudoptimization.googleapis.com
  3. Create Service Account

    • Go to IAM & Admin > Service Accounts
    • Create new service account
    • Grant "Cloud Optimization AI Admin" role
    • Create JSON key
  4. 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 ​

  1. Batch Requests: Optimize multiple routes in single request
  2. Use Fast Mode: For real-time scenarios, use RETURN_FAST
  3. Set Timeouts: Prevent long-running optimizations
  4. Cache Results: Store optimization results when possible
  5. Monitor Costs: Track API usage in Google Cloud Console

Next Steps ​

Released under the MIT License.