Ola Map SDK

Roads API

Guide to road snapping, nearest roads, and speed limits with Roads API

Roads API

The Roads API allows you to snap GPS coordinates to roads, find nearby roads, and retrieve speed limit information.

Overview

The Roads API provides three main capabilities:

  • Snap to Road - Match GPS coordinates to road segments
  • Nearest Roads - Find the closest roads to coordinates
  • Speed Limits - Get speed limit data for road segments

Snap to Road

Snap GPS coordinates to the nearest road segment. This is useful for cleaning up GPS tracks and matching device locations to actual roads.

Basic Usage

const snapped = await client.roads.snapToRoad(
    '12.999,77.673|12.992,77.658|12.985,77.650'
);

With Path Enhancement

Enable path enhancement to add intermediate points for better road curvature matching:

const snapped = await client.roads.snapToRoad(
    '12.999,77.673|12.992,77.658|12.985,77.650',
    true  // enhancePath
);

Parameters

ParameterTypeRequiredDescription
pointsstringYesPipe-separated lat,lng pairs (max 50 points)
enhancePathbooleanNoAdd intermediate points for curvature (default: false)

Response Example

{
    status: "OK",
    snappedPoints: [
        {
            latitude: 12.999012,
            longitude: 77.673045,
            originalIndex: 0
        },
        {
            latitude: 12.992034,
            longitude: 77.658012,
            originalIndex: 1
        }
    ],
    route: {
        distance: { text: "2.5 km", value: 2500 },
        duration: { text: "8 mins", value: 480 }
    }
}

Use Cases

  • GPS Track Correction: Clean up noisy GPS data from fitness trackers or vehicle telematics
  • Route Reconstruction: Reconstruct actual routes traveled from GPS logs
  • Navigation Accuracy: Improve location accuracy in navigation apps

Example: Clean GPS Track

async function cleanGPSTrack(gpsPoints) {
    // Convert points to pipe-separated string
    const pointsString = gpsPoints
        .map(p => `${p.lat},${p.lng}`)
        .join('|');
    
    // Snap to roads with path enhancement
    const snapped = await client.roads.snapToRoad(pointsString, true);
    
    return snapped.snappedPoints.map((point, index) => ({
        lat: point.latitude,
        lng: point.longitude,
        originalPoint: gpsPoints[point.originalIndex]
    }));
}

// Usage
const rawGPS = [
    { lat: 12.999, lng: 77.673 },
    { lat: 12.992, lng: 77.658 },
    { lat: 12.985, lng: 77.650 }
];

cleanGPSTrack(rawGPS)
    .then(cleaned => console.log('Cleaned track:', cleaned))
    .catch(console.error);

Nearest Roads

Find the nearest road segments to given coordinates. Useful for identifying which road a vehicle or person is on.

Basic Usage

const nearest = await client.roads.nearestRoads(
    '12.999,77.673|12.992,77.658',
    'DRIVING',
    500  // radius in meters
);

Parameters

ParameterTypeRequiredDescription
pointsstringYesPipe-separated lat,lng pairs (max 100 points)
modestringYesTravel mode: DRIVING, WALKING, BICYCLING, TRANSIT
radiusnumberNoSearch radius in meters (default: 500)

Response Example

{
    status: "OK",
    results: [
        {
            latitude: 12.999012,
            longitude: 77.673045,
            road_name: "Outer Ring Road",
            distance: 15.3,  // meters from original point
            confidence: 'high'
        },
        {
            latitude: 12.992034,
            longitude: 77.658012,
            road_name: "Main Road",
            distance: 8.7,
            confidence: 'high'
        }
    ]
}

Use Cases

  • Location Context: Determine which road a user is currently on
  • Proximity Analysis: Find roads near points of interest
  • Fleet Monitoring: Identify roads where vehicles are located

Example: Fleet Vehicle Tracking

async function getVehicleRoadLocation(vehicleLocations) {
    const pointsString = vehicleLocations
        .map(v => `${v.lat},${v.lng}`)
        .join('|');
    
    const nearest = await client.roads.nearestRoads(
        pointsString,
        'DRIVING',
        100  // Look within 100 meters
    );
    
    return vehicleLocations.map((vehicle, index) => ({
        vehicleId: vehicle.id,
        roadName: nearest.results[index]?.road_name || 'Unknown',
        distanceFromRoad: nearest.results[index]?.distance || null,
        snappedLocation: {
            lat: nearest.results[index]?.latitude,
            lng: nearest.results[index]?.longitude
        }
    }));
}

// Usage
const vehicles = [
    { id: 'V001', lat: 12.999, lng: 77.673 },
    { id: 'V002', lat: 12.992, lng: 77.658 }
];

getVehicleRoadLocation(vehicles)
    .then(locations => console.log('Vehicle locations:', locations))
    .catch(console.error);

Speed Limits

Retrieve speed limit information for road segments.

Basic Usage

const speeds = await client.roads.speedLimits(
    '13.063,77.593|13.063,77.593'
);

With Custom Snap Strategy

const speeds = await client.roads.speedLimits(
    '13.063,77.593|13.063,77.593',
    'nearestroad'  // or 'snaptoroad'
);

Parameters

ParameterTypeRequiredDescription
pointsstringYesPipe-separated lat,lng pairs (max 50 points)
snapStrategystringNoSnapping method: snaptoroad, nearestroad (default: snaptoroad)

Response Example

{
    status: "OK",
    speedLimits: [
        {
            latitude: 13.063012,
            longitude: 77.593045,
            speed_limit: 60,
            unit: 'km/h',
            road_name: "NH44",
            confidence: 'high'
        },
        {
            latitude: 13.063015,
            longitude: 77.593050,
            speed_limit: 40,
            unit: 'km/h',
            road_name: "Service Road",
            confidence: 'medium'
        }
    ]
}

Use Cases

  • Fleet Safety: Monitor and enforce speed compliance
  • Navigation: Provide speed limit warnings to drivers
  • Insurance Telematics: Calculate risk scores based on speeding behavior
  • Route Planning: Optimize routes based on speed limits

Example: Fleet Speed Monitoring

async function checkFleetSpeedCompliance(vehicleRoutes) {
    const allSpeeds = [];
    
    for (const route of vehicleRoutes) {
        const pointsString = route.path
            .map(p => `${p.lat},${p.lng}`)
            .join('|');
        
        const speeds = await client.roads.speedLimits(pointsString);
        allSpeeds.push({
            vehicleId: route.vehicleId,
            speedData: speeds.speedLimits
        });
    }
    
    // Analyze compliance
    return allSpeeds.map(vehicle => ({
        vehicleId: vehicle.vehicleId,
        totalPoints: vehicle.speedData.length,
        violations: vehicle.speedData.filter(s => s.speed_limit < 40).length,
        averageSpeedLimit: vehicle.speedData.reduce((sum, s) => sum + s.speed_limit, 0) / vehicle.speedData.length
    }));
}

Advanced Examples

Delivery Route Validation

Validate that delivery drivers followed the expected route:

async function validateDeliveryRoute(expectedRoute, actualGPSPoints) {
    // Snap actual GPS points to roads
    const pointsString = actualGPSPoints
        .map(p => `${p.lat},${p.lng}`)
        .join('|');
    
    const snapped = await client.roads.snapToRoad(pointsString, true);
    
    // Calculate deviation from expected route
    const deviations = snapped.snappedPoints.map((point, idx) => {
        const expected = expectedRoute[idx];
        if (!expected) return null;
        
        const distance = calculateDistance(
            point.latitude, point.longitude,
            expected.lat, expected.lng
        );
        
        return {
            pointIndex: idx,
            deviation: distance
        };
    });
    
    const avgDeviation = deviations
        .filter(d => d !== null)
        .reduce((sum, d) => sum + d.deviation, 0) / deviations.length;
    
    return {
        isValid: avgDeviation < 50,  // Within 50 meters
        averageDeviation: avgDeviation,
        deviations: deviations
    };
}

Running Analysis

Analyze running or cycling routes:

async function analyzeRunningRoute(gpsTrack) {
    // Snap to roads/paths
    const snapped = await client.roads.snapToRoad(
        gpsTrack.map(p => `${p.lat},${p.lng}`).join('|'),
        true
    );
    
    // Get speed limits (for road portions)
    const speeds = await client.roads.speedLimits(
        gpsTrack.map(p => `${p.lat},${p.lng}`).join('|')
    );
    
    return {
        totalDistance: snapped.route.distance.value,
        estimatedTime: snapped.route.duration.value,
        roadSegments: speeds.speedLimits.length,
        path: snapped.snappedPoints
    };
}

Error Handling

Handle common errors:

try {
    const snapped = await client.roads.snapToRoad(pointsString);
    console.log('Snapped successfully:', snapped);
} catch (error) {
    if (error.message.includes('Maximum 50 points')) {
        // Split into multiple requests
        const chunks = splitIntoChunks(points, 50);
        const results = await Promise.all(
            chunks.map(chunk => 
                client.roads.snapToRoad(chunk.map(p => `${p.lat},${p.lng}`).join('|'))
            )
        );
        console.log('Batch processed:', results);
    } else if (error.message.includes('No roads found')) {
        console.warn('No roads near the specified coordinates');
    } else {
        console.error('Roads API error:', error);
    }
}

function splitIntoChunks(array, chunkSize) {
    const chunks = [];
    for (let i = 0; i < array.length; i += chunkSize) {
        chunks.push(array.slice(i, i + chunkSize));
    }
    return chunks;
}

Best Practices

1. Batch Processing

For large datasets, process in batches:

async function processLargeTrack(gpsPoints) {
    const MAX_POINTS = 50;
    const results = [];
    
    for (let i = 0; i < gpsPoints.length; i += MAX_POINTS) {
        const chunk = gpsPoints.slice(i, i + MAX_POINTS);
        const pointsString = chunk.map(p => `${p.lat},${p.lng}`).join('|');
        
        const snapped = await client.roads.snapToRoad(pointsString, true);
        results.push(snapped);
        
        // Add small delay to avoid rate limiting
        await new Promise(resolve => setTimeout(resolve, 100));
    }
    
    // Merge results
    return mergeResults(results);
}

2. Cache Results

Cache frequently accessed road data:

const cache = new Map();

async function getCachedSpeedLimits(locationKey, pointsString) {
    if (cache.has(locationKey)) {
        return cache.get(locationKey);
    }
    
    const speeds = await client.roads.speedLimits(pointsString);
    cache.set(locationKey, speeds);
    
    // Clear cache after 1 hour
    setTimeout(() => cache.delete(locationKey), 3600000);
    
    return speeds;
}

3. Validate Coordinates

Ensure coordinates are valid before making requests:

function isValidCoordinate(lat, lng) {
    return (
        typeof lat === 'number' &&
        typeof lng === 'number' &&
        lat >= -90 && lat <= 90 &&
        lng >= -180 && lng <= 180
    );
}

async function safeSnapToRoad(points) {
    const validPoints = points.filter(p => isValidCoordinate(p.lat, p.lng));
    
    if (validPoints.length === 0) {
        throw new Error('No valid coordinates provided');
    }
    
    const pointsString = validPoints
        .map(p => `${p.lat},${p.lng}`)
        .join('|');
    
    return client.roads.snapToRoad(pointsString);
}

Limitations

  • Snap to Road: Maximum 50 points per request
  • Nearest Roads: Maximum 100 points per request
  • Speed Limits: Maximum 50 points per request
  • Rate Limits: Subject to your API plan's rate limits

Next Steps

On this page