Skip to content
cccskills
FreePublished on GitHub

geospatial-routing-data

Geospatial routing data handling for depot and station coordinates, route node IDs, internal index mappings, great-circle distance matrices, and route-distance reconstruction. Use when optimization or reporting tasks involve latitude/longitude, station IDs, depots, distance metrics, vehicle routes, or validating travel distance from reported paths.

The English summary is being prepared. Showing the original description.

See how to install

Files included (1)

  • SKILL.md5.7 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Geospatial Routing Data

Use this skill before building a routing model or validating a routing report that contains coordinates, depots, station IDs, and route sequences.

The main risk is mixing user-facing IDs with internal array indices or using a different distance metric from the task.

Parse Data Safely

Load structured data with a parser and build explicit mappings:

import json
from pathlib import Path

data = json.loads(Path("/root/data.json").read_text())
stations_data = data["stations"]

station_ids = [int(s["id"]) for s in stations_data]
if len(station_ids) != len(set(station_ids)):
    raise ValueError("duplicate station ids")

id_to_idx = {sid: idx for idx, sid in enumerate(station_ids)}
idx_to_id = {idx: sid for sid, idx in id_to_idx.items()}

Use internal indices in optimization variables. Use original station IDs in final reports.

Coordinate Validation

Check coordinates before building distances:

def parse_location(record, label):
    lat = float(record["latitude"])
    lon = float(record["longitude"])
    if not (-90.0 <= lat <= 90.0):
        raise ValueError(f"{label} latitude out of range: {lat}")
    if not (-180.0 <= lon <= 180.0):
        raise ValueError(f"{label} longitude out of range: {lon}")
    return {"latitude": lat, "longitude": lon}

depot = parse_location(data["depot"], "depot")
station_locations = [parse_location(s, f"station {s['id']}") for s in stations_data]

Latitude and longitude are degrees. Convert to radians only inside the distance function.

Great-Circle Distance

Match the task's declared distance metric. If the task specifies an Earth radius, use that exact value.

For great-circle miles with Earth radius 3960.0, use:

import math

def great_circle_miles(a, b, radius=3960.0):
    lat1 = float(a["latitude"])
    lon1 = float(a["longitude"])
    lat2 = float(b["latitude"])
    lon2 = float(b["longitude"])

    deg_to_rad = math.pi / 180.0
    phi1 = (90.0 - lat1) * deg_to_rad
    phi2 = (90.0 - lat2) * deg_to_rad
    theta1 = lon1 * deg_to_rad
    theta2 = lon2 * deg_to_rad

    cos_arc = (
        math.sin(phi1) * math.sin(phi2) * math.cos(theta1 - theta2)
        + math.cos(phi1) * math.cos(phi2)
    )
    cos_arc = max(-1.0, min(1.0, cos_arc))
    return math.acos(cos_arc) * radius

Clamp cos_arc into [-1, 1] to avoid floating-point domain errors.

Do not mix:

  • Euclidean distance on degrees;
  • haversine with a different Earth radius;
  • miles and meters;
  • rounded distances inside the optimization objective.

Build Routing Nodes

Use separate depot labels when the route output must show a start and end depot:

START = "depot_start"
END = "depot_end"

stations = range(len(stations_data))
from_nodes = [START, *stations]
to_nodes = [*stations, END]

def node_location(node):
    if node in (START, END):
        return depot
    return station_locations[int(node)]

Build distances over the same arc set used by the optimization model:

distances = {}
for i in from_nodes:
    for j in to_nodes:
        if i == j:
            continue
        if i == START and j == END:
            continue  # omit if vehicles must visit at least one station
        distances[i, j] = great_circle_miles(node_location(i), node_location(j))

If direct depot-to-depot travel is allowed, keep the (START, END) arc.

Convert Routes Between IDs and Indices

Optimization route using internal indices:

route_nodes = [START, 3, 7, 2, END]

Report route using original station IDs:

report_route = [
    node if isinstance(node, str) else idx_to_id[int(node)]
    for node in route_nodes
]

Parse a reported route back to internal indices:

def parse_report_route(route):
    if route[0] != START or route[-1] != END:
        raise ValueError("route must start at depot_start and end at depot_end")

    parsed = [START]
    for raw in route[1:-1]:
        sid = int(raw)
        if sid not in id_to_idx:
            raise ValueError(f"unknown station id {sid}")
        parsed.append(id_to_idx[sid])
    parsed.append(END)
    return parsed

Never assume station IDs are 0..n-1.

Reconstruct Route Distance

Recompute reported travel distance from route sequences:

def pairwise(items):
    return list(zip(items, items[1:]))

def route_distance_internal(route_nodes):
    total = 0.0
    for i, j in pairwise(route_nodes):
        total += distances[i, j]
    return total

def route_distance_reported_ids(route):
    internal = parse_report_route(route)
    return route_distance_internal(internal)

For multiple vehicles:

travel_distance = sum(
    route_distance_reported_ids(vehicle["route"])
    for vehicle in report["vehicles"]
)

Compare with tolerance, not exact string equality:

def assert_close(actual, expected, tol=1e-6):
    if abs(actual - expected) > max(tol, tol * max(1.0, abs(expected))):
        raise AssertionError(f"{actual} != {expected}")

Route Data Checks

Before trusting a route:

  • first node is the start depot label;
  • last node is the end depot label;
  • every non-depot node is a known station ID;
  • route has at least one station if vehicles cannot stay at the depot;
  • station sequence length equals the stop list length;
  • no repeated station within a route when per-vehicle no-repeat is required;
  • distance is recomputed from coordinates, not copied from model output.

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Perform various data analysis on SEC 13-F and obtain some insights of fund activities such as number of holdings, AUM, and change of holdings between two quarters.

The English summary is being prepared. Showing the original description.

benchflow-ai/skillsbench1.9KUpdated Oct 13, 2026

AC branch pi-model power flow equations (P/Q and |S|) with transformer tap ratio and phase shift, matching `acopf-math-model.md` and MATPOWER branch fields. Use when computing branch flows in either direction, aggregating bus injections for nodal balance, checking MVA (rateA) limits, computing branch loading %, or debugging sign/units issues in AC power flow.

The English summary is being prepared. Showing the original description.

benchflow-ai/skillsbench1.9KUpdated Oct 13, 2026

Redact text from PDF documents for blind review anonymization

The English summary is being prepared. Showing the original description.

benchflow-ai/skillsbench1.9KUpdated Oct 13, 2026

Use when checking simplified ADA-derived plan-view bathroom accessibility constraints such as turning space, door clear width, toilet centerline, grab bars, and lavatory knee/toe clearance.

The English summary is being prepared. Showing the original description.

benchflow-ai/skillsbench1.9KUpdated Oct 13, 2026

Analyze failed GitHub Action jobs for a pull request.

The English summary is being prepared. Showing the original description.

benchflow-ai/skillsbench1.9KUpdated Oct 13, 2026

Use when extracting plan-view architectural geometry from DXF files with semantic CAD layers, especially when outputs must normalize rooms, doors, fixtures, clearances, and grab bars into machine-checkable JSON.

The English summary is being prepared. Showing the original description.

benchflow-ai/skillsbench1.9KUpdated Oct 13, 2026

See all skills by benchflow-ai

Report a problem with this skill