Source code for turf.boolean_point_in_polygon._boolean_point_in_polygon

from typing import Sequence, Union, Dict

from turf.helpers import Feature
from turf.invariant import get_coords_from_features, get_geometry_from_features
from turf.bbox import bbox as bounding_box
from turf.utils.error_codes import error_code_messages
from turf.utils.exceptions import InvalidInput

valid_polygons = ["Polygon", "MultiPolygon"]


[docs]def boolean_point_in_polygon( point: Union[Sequence, Dict, Feature], polygon: Union[Dict, Feature], options: Dict = None, ): """ Takes a {@link Point} and a Polygon or MultiPolygon and determines if the point resides inside the polygon. The polygon can be convex or concave. The function accounts for holes. reference: http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule modified from: https://github.com/substack/point-in-polygon/blob/master/index.js which was modified from http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html :param point: input Point Feature :param polygon: input Polygon or MultiPolygon Feature :param options: optional parameters [options["ignoreBoundary"]] True if polygon boundary should be ignored when determining if the point is inside the polygon otherwise False. :return: True if the Point is inside the Polygon; False otherwise """ if not isinstance(options, dict): options = {} ignore_boundary = options.get("ignoreBoundary", False) point_coords = get_coords_from_features(point, ["Point"]) polygon_coords = get_coords_from_features(polygon, valid_polygons) try: polygon_geom_type = get_geometry_from_features(polygon, valid_polygons).get( "type" ) if not polygon_geom_type: raise AttributeError except AttributeError: raise InvalidInput(error_code_messages["InvalidGeometry"](valid_polygons)) bbox = bounding_box(polygon) if not in_bbox(point_coords, bbox): return False if polygon_geom_type == "Polygon": polygon_coords = [polygon_coords] inside_polygon = False for polygon in polygon_coords: # check if it is in the outer ring first if in_ring(point_coords, polygon[0], ignore_boundary): in_hole = False for ring in polygon[1:]: if in_ring(point_coords, ring, not ignore_boundary): in_hole = True if not in_hole: inside_polygon = True if inside_polygon: break return inside_polygon
def in_ring(point: Sequence, ring: Sequence, ignore_boundary: bool): """ Checks if point is inside a ring :param point: point coordinates [x, y] :param ring: ring [[x, y], [x, y], ...] :param ignore_boundary: True if polygon boundary should be ignored when determining if the point is inside the polygon otherwise False. :return: True if point is inside, False otherwise """ is_inside = False if ring[0][0] == ring[-1][0] and ring[0][1] == ring[-1][1]: ring = ring[:-1] i = 0 j = len(ring) - 1 while i < len(ring): xi = ring[i][0] yi = ring[i][1] xj = ring[j][0] yj = ring[j][1] on_boundary = ( point[1] * (xi - xj) + yi * (xj - point[0]) + yj * (point[0] - xi) == 0 and ((xi - point[0]) * (xj - point[0]) <= 0) and ((yi - point[1]) * (yj - point[1]) <= 0) ) if on_boundary: return not ignore_boundary intersect = ((yi > point[1]) != (yj > point[1])) and ( point[0] < (xj - xi) * (point[1] - yi) / (yj - yi) + xi ) if intersect: is_inside = not is_inside j = i i += 1 return is_inside def in_bbox(point: Sequence, bbox: Sequence): """ Checks if point is inside bbox :param point: point coordinates [lng, lat] :param bbox: bbox [west, south, east, north] :return: True if point is inside, False otherwise """ return bbox[0] <= point[0] <= bbox[2] and bbox[1] <= point[1] <= bbox[3]