Functional Weave
Code in Python

logistics.route-distance@1.0.0

impl/python.py

1,176 bytes · the Python implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import math
from typing import List, Sequence

from .geo_distance import distance  ← from geo.distance ^1.0.0 · built alongside by fune
from .geo_point_in_polygon import GeoPoint  ← from geo.point-in-polygon ^1.0.0 · built alongside by fune
from .logistics_route_distance_types import RouteDistance


def route_distance(stops: Sequence[GeoPoint], return_to_start: bool) -> RouteDistance:
    """Great-circle length of a route through the stops in order, leg by leg,
    optionally closing back to the first stop."""
    if len(stops) == 0:
        raise ValueError("stops must not be empty")
    leg_metres: List[float] = []
    # Each leg is a whole number of millimetres; adding them as integers and
    # dividing once avoids floating-point drift (and is the same double everywhere).
    total_millimetres = 0

    def add_leg(a: GeoPoint, b: GeoPoint) -> None:
        nonlocal total_millimetres
        metres = distance(a.lat, a.lng, b.lat, b.lng)
        leg_metres.append(metres)
        total_millimetres += math.floor(metres * 1000 + 0.5)

    for i in range(1, len(stops)):
        add_leg(stops[i - 1], stops[i])
    if return_to_start and len(stops) > 1:
        add_leg(stops[-1], stops[0])
    return RouteDistance(total_metres=total_millimetres / 1000, leg_metres=leg_metres)