Skip to content

Commit

Permalink
Add boolean disjoint (#42)
Browse files Browse the repository at this point in the history
Add boolean disjoint
  • Loading branch information
SteffenHaeussler committed Jul 23, 2020
1 parent 96a7492 commit 622fc0a
Show file tree
Hide file tree
Showing 47 changed files with 1,601 additions and 31 deletions.
61 changes: 31 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

Read the [docs](https://pyturf.readthedocs.io/en/latest/)

![build_badge](https://github.com/diogomatoschaves/pyturf/workflows/build/badge.svg)
[![codecov](https://codecov.io/gh/diogomatoschaves/pyturf/branch/master/graph/badge.svg)](https://codecov.io/gh/diogomatoschaves/pyturf)
![build_badge](https://github.com/pyturf/pyturf/workflows/build/badge.svg)
[![codecov](https://codecov.io/gh/pyturf/pyturf/branch/master/graph/badge.svg)](https://codecov.io/gh/pyturf/pyturf)
[![PyPI version](https://badge.fury.io/py/pyturf.svg)](https://badge.fury.io/py/pyturf)
[![Documentation Status](https://readthedocs.org/projects/ansicolortags/badge/?version=latest)](https://pyturf.readthedocs.io/?badge=latest)

Expand Down Expand Up @@ -69,36 +69,37 @@ dist = distance(point1, point2, {"units": "miles"})

Currently, the following modules have been implemented:

- [along](https://github.com/diogomatoschaves/pyturf/tree/master/turf/along)
- [area](https://github.com/diogomatoschaves/pyturf/tree/master/turf/area)
- [bbox](https://github.com/diogomatoschaves/pyturf/tree/master/turf/bbox)
- [bbox-polygon](https://github.com/diogomatoschaves/pyturf/tree/master/turf/bbox_polygon)
- [bearing](https://github.com/diogomatoschaves/pyturf/tree/master/turf/bearing)
- [boolean-point-in-polygon](https://github.com/diogomatoschaves/pyturf/tree/master/turf/boolean_point_in_polygon)
- [boolean-point-on-line](https://github.com/diogomatoschaves/pyturf/tree/master/turf/boolean_point_on_line)
- [center](https://github.com/diogomatoschaves/pyturf/tree/master/turf/center)
- [centroid](https://github.com/diogomatoschaves/pyturf/tree/master/turf/centroid)
- [destination](https://github.com/diogomatoschaves/pyturf/tree/master/turf/destination)
- [distance](https://github.com/diogomatoschaves/pyturf/tree/master/turf/distance)
- [envelope](https://github.com/diogomatoschaves/pyturf/tree/master/turf/envelope)
- [explode](https://github.com/diogomatoschaves/pyturf/tree/master/turf/explode)
- [great circle](https://github.com/diogomatoschaves/pyturf/tree/master/turf/great_circle)
- [helpers](https://github.com/diogomatoschaves/pyturf/tree/master/turf/helpers)
- [length](https://github.com/diogomatoschaves/pyturf/tree/master/turf/length)
- [line-intersect](https://github.com/diogomatoschaves/pyturf/tree/master/turf/line_intersect)
- [midpoint](https://github.com/diogomatoschaves/pyturf/tree/master/turf/midpoint)
- [nearest-point](https://github.com/diogomatoschaves/pyturf/tree/master/turf/nearest_point)
- [point-on-feature](https://github.com/diogomatoschaves/pyturf/tree/master/turf/point_on_feature)
- [point-to-line-distance](https://github.com/diogomatoschaves/pyturf/tree/master/turf/point_to_line_distance)
- [polygon-tangents](https://github.com/diogomatoschaves/pyturf/tree/master/turf/polygon_tangents)
- [polygon-to-line](https://github.com/diogomatoschaves/pyturf/tree/master/turf/polygon_to_line)
- [rhumb-bearing](https://github.com/diogomatoschaves/pyturf/tree/master/turf/rhumb_bearing)
- [rhumb-destination](https://github.com/diogomatoschaves/pyturf/tree/master/turf/rhumb_destination)
- [rhumb-distance](https://github.com/diogomatoschaves/pyturf/tree/master/turf/rhumb_distance)
- [square](https://github.com/diogomatoschaves/pyturf/tree/master/turf/square)
- [along](https://github.com/pyturf/pyturf/tree/master/turf/along)
- [area](https://github.com/pyturf/pyturf/tree/master/turf/area)
- [bbox](https://github.com/pyturf/pyturf/tree/master/turf/bbox)
- [bbox-polygon](https://github.com/pyturf/pyturf/tree/master/turf/bbox_polygon)
- [bearing](https://github.com/pyturf/pyturf/tree/master/turf/bearing)
- [boolean-disjoint](https://github.com/pyturf/pyturf/tree/master/turf/boolean_disjoint)
- [boolean-point-in-polygon](https://github.com/pyturf/pyturf/tree/master/turf/boolean_point_in_polygon)
- [boolean-point-on-line](https://github.com/pyturf/pyturf/tree/master/turf/boolean_point_on_line)
- [center](https://github.com/pyturf/pyturf/tree/master/turf/center)
- [centroid](https://github.com/pyturf/pyturf/tree/master/turf/centroid)
- [destination](https://github.com/pyturf/pyturf/tree/master/turf/destination)
- [distance](https://github.com/pyturf/pyturf/tree/master/turf/distance)
- [envelope](https://github.com/pyturf/pyturf/tree/master/turf/envelope)
- [explode](https://github.com/pyturf/pyturf/tree/master/turf/explode)
- [great circle](https://github.com/pyturf/pyturf/tree/master/turf/great_circle)
- [helpers](https://github.com/pyturf/pyturf/tree/master/turf/helpers)
- [length](https://github.com/pyturf/pyturf/tree/master/turf/length)
- [line-intersect](https://github.com/pyturf/pyturf/tree/master/turf/line_intersect)
- [midpoint](https://github.com/pyturf/pyturf/tree/master/turf/midpoint)
- [nearest-point](https://github.com/pyturf/pyturf/tree/master/turf/nearest_point)
- [point-on-feature](https://github.com/pyturf/pyturf/tree/master/turf/point_on_feature)
- [point-to-line-distance](https://github.com/pyturf/pyturf/tree/master/turf/point_to_line_distance)
- [polygon-tangents](https://github.com/pyturf/pyturf/tree/master/turf/polygon_tangents)
- [polygon-to-line](https://github.com/pyturf/pyturf/tree/master/turf/polygon_to_line)
- [rhumb-bearing](https://github.com/pyturf/pyturf/tree/master/turf/rhumb_bearing)
- [rhumb-destination](https://github.com/pyturf/pyturf/tree/master/turf/rhumb_destination)
- [rhumb-distance](https://github.com/pyturf/pyturf/tree/master/turf/rhumb_distance)
- [square](https://github.com/pyturf/pyturf/tree/master/turf/square)

## Contributing

This library is a work in progress, so pull requests from the community are welcome!

Check out [CONTRIBUTING.md](https://github.com/diogomatoschaves/pyturf/blob/master/CONTRIBUTING.md) for a detailed explanation on how to contribute.
Check out [CONTRIBUTING.md](https://github.com/pyturf/pyturf/blob/master/CONTRIBUTING.md) for a detailed explanation on how to contribute.
1 change: 1 addition & 0 deletions turf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from turf.bbox import bbox
from turf.bbox_polygon import bbox_polygon
from turf.bearing import bearing
from turf.boolean_disjoint import boolean_disjoint
from turf.boolean_point_in_polygon import boolean_point_in_polygon
from turf.boolean_point_on_line import boolean_point_on_line
from turf.center import center
Expand Down
1 change: 1 addition & 0 deletions turf/boolean_disjoint/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from turf.boolean_disjoint._boolean_disjoint import boolean_disjoint
200 changes: 200 additions & 0 deletions turf/boolean_disjoint/_boolean_disjoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
from typing import Any, List, Sequence, Union

from turf.helpers import (
Feature,
LineString,
MultiLineString,
MultiPolygon,
Point,
Polygon,
)

from turf.helpers import line_string, point, polygon

from turf.boolean_point_in_polygon import boolean_point_in_polygon
from turf.boolean_point_on_line import boolean_point_on_line
from turf.invariant import get_coords_from_features, get_geometry_type
from turf.polygon_to_line import polygon_to_line
from turf.line_intersect import line_intersect

from turf.utils.error_codes import error_code_messages
from turf.utils.exceptions import InvalidInput


def boolean_disjoint(feature_1: Any, feature_2: Any) -> bool:
"""
Returns true if the intersection of the two geometries is an empty set.
:param feature_1: {GeoJSON} feature_1 any Feature or Geometry
:param feature_2: {GeoJSON} feature_2 any Feature or Geometry
:return: boolean True/False if features are disjoint
"""
is_disjoint = True

flat_feature_1 = flatten_feature(feature_1)
flat_feature_2 = flatten_feature(feature_2)

for flat_1 in flat_feature_1:
for flat_2 in flat_feature_2:

is_disjoint = disjoint(flat_1, flat_2)

if not is_disjoint:
break

return is_disjoint


def disjoint(
feature_1: List[Union[str, Sequence]], feature_2: List[Union[str, Sequence]]
) -> bool:
"""
Returns true if the intersection of the two geometries is an empty set.
:param feature_1: {List} a List with geometry type and coordinates
:param feature_2: {List} a List with geometry type and coordinates
:return: boolean True/False if features are disjoint
"""

is_disjoint = True

if feature_1[0] in ["Point"]:

if feature_2[0] in ["Point"]:
is_disjoint = feature_1[1] != feature_2[1]

elif feature_2[0] in ["LineString"]:
is_disjoint = not boolean_point_on_line(feature_1[1], feature_2[1])

elif feature_2[0] in ["Polygon"]:
is_disjoint = not boolean_point_in_polygon(feature_1[1], feature_2[1])

elif feature_1[0] in ["LineString"]:

if feature_2[0] in ["Point"]:
is_disjoint = not boolean_point_on_line(feature_2[1], feature_1[1])

elif feature_2[0] in ["LineString"]:
is_disjoint = not is_line_on_line(feature_1[1], feature_2[1])

elif feature_2[0] in ["Polygon"]:
is_disjoint = not is_line_in_poly(feature_2[1], feature_1[1])

elif feature_1[0] in ["Polygon"]:

if feature_2[0] in ["Point"]:
is_disjoint = not boolean_point_in_polygon(feature_2[1], feature_1[1])

elif feature_2[0] in ["LineString"]:
is_disjoint = not is_line_in_poly(feature_1[1], feature_2[1])

elif feature_2[0] in ["Polygon"]:
is_disjoint = not is_poly_in_poly(feature_2[1], feature_1[1])

return is_disjoint


def is_line_on_line(feature_1: Sequence, feature_2: Sequence) -> bool:
"""
Checks if two linestring feature intersects each other
:param feature_1: Coordinates of linestring feature 1
:param feature_2: Coordinates of linestring feature 2
:return: bool if there is an intersection
"""
if isinstance(feature_1, list):
feature_1 = line_string(feature_1)

if isinstance(feature_2, list):
feature_2 = line_string(feature_2)

intersects = line_intersect(feature_1, feature_2)

if len(intersects["features"]) >= 1:
return True

return False


def is_line_in_poly(feature_1: Sequence, feature_2: Sequence) -> bool:
"""
Checks if a linestring feature is inside or intersects a polygon feature
:param feature_1: Coordinates of polygon feature
:param feature_2: Coordinates of linestring feature
:return: bool if there is an intersection
"""
feature_1_line = polygon_to_line(polygon(feature_1))

if is_line_on_line(feature_2, feature_1_line):
return True

for coord in feature_2:
if boolean_point_in_polygon(coord, feature_1):
return True

return False


def is_poly_in_poly(feature_1: Sequence, feature_2: Sequence) -> bool:
"""
Checks if polygon feature_1 is inside polygon feature_2 and either way
See http://stackoverflow.com/a/4833823/1979085
:param feature: Coordinates of polygon feature 1
:param feature: Coordinates of polygon feature 1
:return: bool if there is an intersection
"""
feature_1_line = polygon_to_line(polygon(feature_1))
feature_2_line = polygon_to_line(polygon(feature_2))

for coord1 in feature_1_line["geometry"]["coordinates"]:
if boolean_point_in_polygon(coord1, feature_2):
return True

for coord2 in feature_2_line["geometry"]["coordinates"]:
if boolean_point_in_polygon(coord2, feature_1):
return True

if is_line_on_line(feature_1_line, feature_2_line):
return True

return False


def flatten_feature(feature: Any) -> List[Union[str, Sequence]]:
"""
Takes any feature and return the simple geometry type with coordinates.
A MultiPoint will be flatten to Point, MultiLineString to LineString and
MultiPolygon to Polygon
:param feature: {GeoJSON} feature any Feature or Geometry
:return: List of geometry type and coordinate sequence
"""
feature_coords = get_coords_from_features(feature)
feature_geometry = get_geometry_type(feature)

if isinstance(feature_geometry, (list, tuple)):
feature_geometry = feature_geometry[0]

if feature_geometry in ["MultiPoint", "MultiLineString", "MultiPolygon"]:

if feature_geometry == "MultiPoint":

feature_geometry = "Point"

elif feature_geometry == "MultiLineString":

feature_geometry = "LineString"

elif feature_geometry == "MultiPolygon":

feature_geometry = "Polygon"

flat_feature = [[feature_geometry, coords] for coords in feature_coords]

else:

flat_feature = [[feature_geometry, feature_coords]]

return flat_feature
74 changes: 74 additions & 0 deletions turf/boolean_disjoint/tests/false/Large-Inside-Small.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
19.6875,
34.016241889667015
],
[
14.765625,
26.745610382199022
],
[
19.6875,
23.563987128451217
],
[
23.203125,
26.43122806450644
],
[
22.148437499999996,
30.44867367928756
],
[
19.6875,
34.016241889667015
]
]
]
}
}, {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[
18.984375,
40.44694705960048
],
[
7.03125,
25.48295117535531
],
[
19.335937499999996,
18.979025953255267
],
[
31.640625,
24.206889622398023
],
[
24.960937499999996,
34.88593094075317
],
[
18.984375,
40.44694705960048
]
]
]
}
}
]
}
21 changes: 21 additions & 0 deletions turf/boolean_disjoint/tests/false/LineString-In-Polygon.geojson
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "LineString",
"coordinates": [[1,2.5], [2,2.5]]
}
},
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [[[-1, 2], [3, 2], [3, 3], [-1, 3], [-1, 2]]]
}
}
]
}

0 comments on commit 622fc0a

Please sign in to comment.