def get_coords_from_geometry(geometry: Any, allowed_types: Sequence = None, raise_exception: bool = True) -> List: """ Retrieves coords from a given Geometry. Geometry must be a GeoJSON, a Geometry object or a list of coordinates, otherwise it raises an exception. :param geometry: Any input value(s) :param allowed_types: allowed Feature types :param raise_exception: if an exception should be raised or if it should be silent :return: list with extracted coords """ if not allowed_types: allowed_types = allowed_types_default if isinstance(geometry, (list, tuple)): return _process_list_input(allowed_types, geometry, get_coords_from_geometry, raise_exception) if isinstance(geometry, (Feature, dict)): if geometry.get("type") == "Feature": return get_coords_from_geometry(geometry.get("geometry", {}), allowed_types) allowed_class_types = [ *[eval(allowed_type) for allowed_type in allowed_types], dict, ] if any( isinstance(geometry, allowed_type_class) and geometry.get("type", "") in allowed_types for allowed_type_class in allowed_class_types): return geometry.get("coordinates", []) if raise_exception: raise InvalidInput( error_code_messages["InvalidGeometry"](allowed_types)) else: return []
def square(bbox): """ Takes a bounding box and calculates the minimum square bounding box that would contain the input. :param bbox: bounding box extent in [minX, minY, maxX, maxY] order :return: a square surrounding bbox """ if not isinstance(bbox, list) or len(bbox) != 4: raise InvalidInput(error_code_messages["InvalidBoundingBox"]) west = float(bbox[0]) south = float(bbox[1]) east = float(bbox[2]) north = float(bbox[3]) horizontal_distance = distance([west, south], [east, south]) vertical_distance = distance([west, south], [west, north]) if horizontal_distance >= vertical_distance: vertical_midpoint = (south + north) / 2 bounding_box = [ west, vertical_midpoint - ((east - west) / 2), east, vertical_midpoint + ((east - west) / 2), ] else: horizontal_midpoint = (west + east) / 2 bounding_box = [ horizontal_midpoint - ((north - south) / 2), south, horizontal_midpoint + ((north - south) / 2), north, ] return bounding_box
def get_geometry_from_features(features: Any, allowed_types: Sequence = None) -> List: """ Retrieves Geometries from Features. Features must be a GeoJSON, a Feature object or a list of coordinates, otherwise it raises an exception. :param features: Any input value(s) :param allowed_types: allowed Feature types :return: list with extracted coords """ if not allowed_types: allowed_types = allowed_types_default if isinstance(features, (list, tuple)): return _process_list_input([*allowed_types, "Feature"], features, get_geometry_from_features) if isinstance(features, (FeatureCollection, dict)): if features.get("type") == "FeatureCollection": return list( map( lambda feature: feature.get("geometry", {}), features.get("features", []), )) if isinstance(features, (Feature, dict)): if features.get("type", "") == "Feature": if features.get("geometry", {}).get("type", "") in allowed_types: return features.get("geometry", {}) if isinstance(features, (*[eval(allowed_type) for allowed_type in allowed_types], dict)): if features.get("type", "") in allowed_types: return features raise InvalidInput(error_code_messages["InvalidGeometry"](allowed_types))
def along(line, dist, options=None): """ Takes a LineString and returns a Point at a specified distance along the line :param line: input LineString :param dist: distance along the line :param options: optional parameters [options["units"]="kilometers"] can be degrees, radians, miles, or kilometers :return: Point `dist` `units` along the line """ if not options or not isinstance(options, dict): options = {} if not isinstance(dist, (float, int)) or dist < 0: raise InvalidInput(error_code_messages["InvalidDistance"]) coords = get_coords_from_features(line, ["LineString"]) travelled = 0 for i in range(len(coords)): if dist >= travelled and i == len(coords) - 1: break elif travelled >= dist: overshot = dist - travelled if not overshot: return point([truncate(coord, 6) for coord in coords[i]]) else: direction = bearing(coords[i], coords[i - 1]) - 180 interpolated = destination(coords[i], overshot, direction, options) return interpolated else: travelled += distance(coords[i], coords[i + 1]) return point([truncate(coord, 6) for coord in coords[-1]])