def centroid(geojson, properties: dict = None) -> Feature: """ Takes one or more features and calculates the centroid using the mean of all vertices. :param geojson: Input features :param properties: Properties to be set to the output Feature point :return: Feature: Point feature which is the centroid of the given features Example: >>> from turfpy.measurement import centroid >>> from geojson import Polygon >>> polygon = Polygon([((-81, 41), (-88, 36), (-84, 31), (-80, 33), (-77, 39), (-81, 41))]) >>> centroid(polygon) """ x_sum = 0 y_sum = 0 length = 0 def _callback_coord_each(coord, coord_index, feature_index, multi_feature_index, geometry_index): nonlocal x_sum, y_sum, length x_sum += coord[0] y_sum += coord[1] length += 1 coord_each(geojson, _callback_coord_each) point = Point((x_sum / length, y_sum / length)) return Feature(geometry=point, properties=properties if properties else {})
def explode(geojson): points = [] if geojson["type"] == "FeatureCollection": def _callback_feature_each(feature, feature_index): def _callback_coord_each( coord, coord_index, feature_index, multi_feature_index, geometry_index, ): nonlocal points point = Point(coord) points.append(Feature(geometry=point, properties=feature["properties"])) coord_each(feature, _callback_coord_each) feature_each(geojson, _callback_feature_each) else: def _callback_coord_each( coord, coord_index, feature_index, multi_feature_index, geometry_index, ): nonlocal points, geojson point = Point(coord) points.append(Feature(geometry=point, properties=geojson["properties"])) coord_each(geojson, _callback_coord_each) return FeatureCollection(points)
def bbox(geojson): """ This function is used to generate bounding box coordinates for given geojson. :param geojson: Geojson object for which bounding box is to be found. :return: bounding box for the given Geojson object. Example : >>> from turfpy.measurement import bbox >>> from geojson import Polygon >>> p = Polygon([(2.38, 57.322), (23.194, -20.28), (-120.43, 19.15),(2.38, 57.322)]) >>> bb = bbox(p) """ result = [float("inf"), float("inf"), float("-inf"), float("-inf")] def _callback_coord_each(coord, coord_index, feature_index, multi_feature_index, geometry_index): nonlocal result if result[0] > coord[0]: result[0] = coord[0] if result[1] > coord[1]: result[1] = coord[1] if result[2] < coord[0]: result[2] = coord[0] if result[3] < coord[1]: result[3] = coord[1] coord_each(geojson, _callback_coord_each) return result
def _callback_feature_each(feature, feature_index): def _callback_coord_each( coord, coord_index, feature_index, multi_feature_index, geometry_index, ): nonlocal points point = Point(coord) points.append(Feature(geometry=point, properties=feature["properties"])) coord_each(feature, _callback_coord_each)
def transform_rotate( feature: Union[List[Feature], FeatureCollection], angle: float, pivot: list = None, mutate: bool = False, ): """ Rotates any geojson Feature or Geometry of a specified angle, around its centroid or a given pivot point; all rotations follow the right-hand rule. :param feature: Geojson to be rotated. :param angle: angle of rotation (along the vertical axis), from North in decimal degrees, negative clockwise :param pivot: point around which the rotation will be performed :param mutate: allows GeoJSON input to be mutated (significant performance increase if True) :return: the rotated GeoJSON Example :- >>> from turfpy.transformation import transform_rotate >>> from geojson import Polygon, Feature >>> f = Feature(geometry=Polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]])) >>> pivot = [0, 25] >>> transform_rotate(f, 10, pivot) """ if not feature: raise Exception("geojson is required") if angle == 0: return feature if not pivot: pivot = centroid(feature)["geometry"]["coordinates"] if not mutate: feature = copy.deepcopy(feature) def _callback_coord_each( coord, coord_index, feature_index, multi_feature_index, geometry_index ): nonlocal pivot, angle initial_angle = rhumb_bearing(GeoPoint(pivot), GeoPoint(coord)) final_angle = initial_angle + angle distance = rhumb_distance(GeoPoint(pivot), GeoPoint(coord)) new_coords = get_coord(rhumb_destination(GeoPoint(pivot), distance, final_angle)) coord[0] = new_coords[0] coord[1] = new_coords[1] coord_each(feature, _callback_coord_each) return feature
def scale(feature, factor, origin): is_point = get_type(feature) == "Point" origin = define_origin(feature, origin) if factor == 1 or is_point: return feature def _callback_coord_each( coord, coord_index, feature_index, multi_feature_index, geometry_index ): nonlocal factor, origin original_distance = rhumb_distance(GeoPoint(origin), GeoPoint(coord)) bearing = rhumb_bearing(GeoPoint(origin), GeoPoint(coord)) new_distance = original_distance * factor new_coord = get_coord(rhumb_destination(GeoPoint(origin), new_distance, bearing)) coord[0] = new_coord[0] coord[1] = new_coord[1] if len(coord) == 3: coord[2] = coord[2] * factor coord_each(feature, _callback_coord_each) return feature
def transform_translate( feature: Union[List[Feature], FeatureCollection], distance: float, direction: float, units: str = "km", z_translation: float = 0, mutate: bool = False, ): """ Moves any geojson Feature or Geometry of a specified distance along a Rhumb Line on the provided direction angle. :param feature: Geojson data that is to be translated :param distance: length of the motion; negative values determine motion in opposite direction :param direction: of the motion; angle from North in decimal degrees, positive clockwise :param units: units for the distance and z_translation :param z_translation: length of the vertical motion, same unit of distance :param mutate: allows GeoJSON input to be mutated (significant performance increase if true) :return: the translated GeoJSON Example :- >>> from turfpy.transformation import transform_translate >>> from geojson import Polygon, Feature >>> f = Feature(geometry=Polygon([[[0,29],[3.5,29],[2.5,32],[0,29]]])) >>> transform_translate(f, 100, 35, mutate=True) """ if not feature: raise Exception("geojson is required") if not distance: raise Exception("distance is required") if distance == 0 and z_translation == 0: return feature if not direction: raise Exception("direction is required") if distance < 0: distance = -distance direction = direction + 180 if not mutate: feature = copy.deepcopy(feature) def _callback_coord_each( coord, coord_index, feature_index, multi_feature_index, geometry_index ): nonlocal distance, direction, units, z_translation new_coords = get_coord( rhumb_destination(GeoPoint(coord), distance, direction, {units: units}) ) coord[0] = new_coords[0] coord[1] = new_coords[1] if z_translation and len(coord) == 3: coord[2] += z_translation coord_each(feature, _callback_coord_each) return feature
def sector(center: Feature, radius: int, bearing1: int, bearing2: int, options: dict = {}) -> Feature: """ Creates a circular sector of a circle of given radius and center Point , between (clockwise) bearing1 and bearing2; 0 bearing is North of center point, positive clockwise. :param center: A `Point` object representing center point of circle. :param radius: An int representing radius of the circle. :param bearing1: Angle, in decimal degrees, of the first radius of the arc. :param bearing2: Angle, in decimal degrees, of the second radius of the arc. :param options: A dict representing additional properties, which can be `steps` which has default values as 64, `units` which has default values of `km`, and `properties` which will be added to resulting Feature as properties. :return: A polygon feature object. Example: >>> from turfpy.misc import sector >>> from geojson import Feature, Point >>> center = Feature(geometry=Point((-75, 40))) >>> radius = 5 >>> bearing1 = 25 >>> bearing2 = 45 >>> sector(center, radius, bearing1, bearing2) """ if not options: options = {} steps = int(options["steps"]) if options.get("steps") else 64 units = str(options.get("units")) if options.get("units") else "km" properties = options.get("properties") if options.get("properties") else {} if not center: raise Exception("center if required") if center.get("type") != "Feature": raise Exception("Invalid Feature value for center parameter") if not radius: raise Exception("Radius is required") if not bearing1: raise Exception("bearing1 is required") if not bearing2: raise Exception("bearing2 is required") if convert_angle_to_360(bearing1) == convert_angle_to_360(bearing2): return circle(center, radius, steps, units) coords = get_coords(center) arc = line_arc(center, radius, bearing1, bearing2, options) sliceCoords = [[coords]] def _callback_coord_each( coord, coord_index, feature_index, multi_feature_index, geometry_index, ): nonlocal sliceCoords sliceCoords[0].append(coord) coord_each(arc, _callback_coord_each) sliceCoords[0].append(coords) return Feature(geometry=Polygon(sliceCoords), properties=properties)