@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
JavaScript
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
}));
}
}