UNPKG

@siva-sub/mcp-public-transport

Version:

A Model Context Protocol server for Singapore transport data with real-time information and routing

94 lines (93 loc) 3.05 kB
import polyline from '@mapbox/polyline'; export class PolylineService { /** * Decode a polyline string to coordinates */ decode(encoded) { const decodedCoordinates = polyline.decode(encoded); // Convert to [lng, lat] format for GeoJSON and calculate bounds const coordinates = decodedCoordinates.map(coord => [coord[1], coord[0]]); const bounds = this.calculateBounds(coordinates); return { coordinates, bounds }; } /** * Process polyline data from OneMap response */ processPolylines(response) { const polylines = []; // Handle direct routing polyline if (response.route_geometry) { const decoded = this.decode(response.route_geometry); polylines.push({ encoded: response.route_geometry, decoded, geojson: this.createGeoJSON(decoded.coordinates), coordinateCount: decoded.coordinates.length }); } // Handle transit leg polylines if (response.plan?.itineraries?.[0]?.legs) { response.plan.itineraries[0].legs.forEach((leg, index) => { if (leg.legGeometry?.points) { const decoded = this.decode(leg.legGeometry.points); polylines.push({ encoded: leg.legGeometry.points, decoded, geojson: this.createGeoJSON(decoded.coordinates), coordinateCount: decoded.coordinates.length }); } }); } return polylines; } /** * Create GeoJSON LineString from coordinates */ createGeoJSON(coordinates) { return { type: 'LineString', coordinates }; } /** * Calculate bounding box for coordinates */ calculateBounds(coordinates) { if (coordinates.length === 0) { return { north: 0, south: 0, east: 0, west: 0 }; } let north = coordinates[0][1]; let south = coordinates[0][1]; let east = coordinates[0][0]; let west = coordinates[0][0]; coordinates.forEach(([lng, lat]) => { north = Math.max(north, lat); south = Math.min(south, lat); east = Math.max(east, lng); west = Math.min(west, lng); }); return { north, south, east, west }; } /** * Estimate coordinate count from encoded polyline */ estimateCoordinateCount(encoded) { return Math.floor(encoded.length / 10); } /** * Create step markers for instructions */ createStepMarkers(instructions) { return instructions .filter(inst => inst.coordinates) .map(inst => ({ step: inst.step, coordinates: [inst.coordinates.lng, inst.coordinates.lat], instruction: inst.instruction })); } }