Esempio n. 1
0
def rhumb_distance(origin, destination, options: Dict = None) -> float:
    """
    Calculates the rhumb distance between two Points. Units are defined in helpers._units

    # https://en.wikipedia.org/wiki/Rhumb_line

    :param start: starting point [lng, lat] or Point feature
    :param end: ending point [lng, lat] or Point feature
    :param options: dictionary with units as an attribute.
                    Units are defined in helpers._units

    :return: distance between the 2 points

    """
    if not isinstance(options, dict):
        options = {}

    origin = get_coords_from_features(origin, ["Point"])
    destination = get_coords_from_features(destination, ["Point"])

    # compensate the crossing of the 180th meridian (https://macwright.org/2016/09/26/the-180th-meridian.html)
    # solution from https://github.com/mapbox/mapbox-gl-js/issues/3250#issuecomment-294887678
    if (destination[0] - origin[0]) > 180:
        destination[0] -= 360
    elif (origin[0] - destination[0]) > 180:
        destination[0] += 360

    distance_in_meters = calculate_rhumb_distance(origin, destination)

    distance = convert_length(
        distance_in_meters, "meters", options.get("units", "kilometers")
    )

    return distance
Esempio n. 2
0
def rhumb_destination(features: Dict, options: Dict = None) -> Point:
    """
    Returns the destination {Point} having travelled the given distance along a
    Rhumb line from the origin Point with the (varant) given bearing.

    # https://en.wikipedia.org/wiki/Rhumb_line

    :param features: any GeoJSON feature or feature collection
    :param properties: specification to calculate the rhumb line
        [options["distance"]=100] distance from the starting point
        [options["bearing"]=180] varant bearing angle ranging from -180 to 180 degrees from north
        [options["units"]=kilometers] units: specifies distance (can be degrees, radians, miles, or kilometers)

    :param options: optional parameters also be part of features["properties"]
        [options["units"]={}] can be degrees, radians, miles, or kilometers
        [options["properties"]={}] Translate GeoJSON Properties to Point
        [options["id"]={}] Translate GeoJSON Id to Point

    :return: a FeatureDestination point.
    """
    if not options:
        options = features.get("properties", {})

    coords = get_coords_from_features(features, ["Point"])

    bearing = options.get("bearing", 180)
    distance = options.get("dist", 100)
    units = options.get("units", "kilometers")

    distance_in_meters = convert_length(abs(distance),
                                        original_unit=units,
                                        final_unit="meters")

    if distance < 0:
        distance_in_meters *= -1

    destination = calculate_rhumb_destination(coords, distance_in_meters,
                                              bearing)

    # compensate the crossing of the 180th meridian:
    #  (https://macwright.org/2016/09/26/the-180th-meridian.html)
    # solution from:
    # https://github.com/mapbox/mapbox-gl-js/issues/3250#issuecomment-294887678

    if (destination[0] - coords[0]) > 180:
        destination[0] -= 360
    elif (coords[0] - destination[0]) > 180:
        destination[0] += 360

    return point(destination, options.get("properties", None))
Esempio n. 3
0
def point_to_line_distance(
    point: Union[Sequence, Dict, Feature],
    line: Union[Sequence, Dict, Feature],
    options: Dict = None,
) -> float:
    """
    Returns the minimum distance between a {Point} and a {LineString},
    being the distance from a line the minimum distance between the point and
    any segment of the `LineString`

    http://geomalgorithms.com/a02-_lines.html

    :param point: Point GeoJSON Feature or Geometry
    :param line: LineString GeoJSON Feature or Geometry
    :param options: Optional parameters
        [options["units"]]: any supported unit (e.g. degrees, radians, miles...)
        [options["method"]]: geodesic or 'planar for distance calculation

    :return: distance between point and line
    """
    dist = []
    if not isinstance(options, dict):
        options = {"method": "geodesic", "units": "kilometers"}

    point = get_coords_from_features(point, ["Point"])
    line = get_coords_from_features(line, ["LineString"])

    for i in range(1, len(line)):
        dist.append(
            get_distance_to_segment(point, line[i - 1], line[i],
                                    options.get("method", "geodesic")))

    dist = convert_length(min(dist), "degrees",
                          options.get("units", "kilometers"))

    return dist
Esempio n. 4
0
def test_convert_length(value, original_unit, final_unit, result):

    assert convert_length(value, original_unit, final_unit) == result