Skip to content

Instantly share code, notes, and snippets.

@precious
Created September 23, 2019 20:26
Show Gist options
  • Save precious/1bdb58533284631f0daf3489686d4e6d to your computer and use it in GitHub Desktop.
Save precious/1bdb58533284631f0daf3489686d4e6d to your computer and use it in GitHub Desktop.
import math
def get_distance_in_meters(lat1, lon1, lat2, lon2):
earth_radius = 6371007.2 # meters
lat1, lon1, lat2, lon2 = map(math.radians, (lat1, lon1, lat2, lon2))
dlon = lon2 - lon1
dlat = lat2 - lat1
a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
return earth_radius * c
def is_line_segment_intersecting_circle(ax, ay, bx, by, cx, cy, r_in_meters):
"""
https://gis.stackexchange.com/questions/36841/line-intersection-with-circle-on-a-sphere-globe-or-earth
"""
earth_radius = 6371007.2 # meters
def make_projection(x, y):
return math.radians(x) * earth_radius, math.radians(y) * earth_radius * math.cos(math.radians(cx))
Ax, Ay = make_projection(ax, ay)
Bx, By = make_projection(bx, by)
Cx, Cy = make_projection(cx, cy)
# Compute coefficients of the quadratic equation
vx, vy = Ax - Cx, Ay - Cy
ux, uy = Bx - Ax, By - Ay
alpha = ux ** 2 + uy ** 2
beta = ux * vx + uy * vy
gamma = vx ** 2 + vy ** 2 - r_in_meters ** 2
# Solve the equation.
d = beta ** 2 - alpha * gamma
if d < 0:
return False
t1 = (-beta + math.sqrt(d)) / alpha
t2 = (-beta - math.sqrt(d)) / alpha
return 0 <= t1 <= 1 or 0 <= t2 <= 1
def is_line_segment_intersecting_circle_or_inside_circle(ax, ay, bx, by, cx, cy, r_in_meters):
return (get_distance_in_meters(ax, ay, cx, cy) <= r_in_meters or
get_distance_in_meters(bx, by, cx, cy) <= r_in_meters or
is_line_segment_intersecting_circle(ax, ay, bx, by, cx, cy, r_in_meters))
# in dnipro, must be true
is_line_segment_intersecting_circle(48.3884145, 35.497376, 48.5301052, 34.6690791, 48.4658508, 35.0759286, 10_000)
# large radius - must be false, segment is inside circle
is_line_segment_intersecting_circle(48.3884145, 35.497376, 48.5301052, 34.6690791, 48.4658508, 35.0759286, 200_000)
# large radius - must be true, segment is inside circle
is_line_segment_intersecting_circle_or_inside_circle(48.3884145, 35.497376, 48.5301052, 34.6690791, 48.4658508,
35.0759286, 200_000)
# line segment in kiev, circle in iran, must be false
is_line_segment_intersecting_circle(50.4498503, 30.5238646, 50.452297, 30.5271611, 35.046183, 48.464717, 50_000)
is_line_segment_intersecting_circle_or_inside_circle(50.4498503, 30.5238646, 50.452297, 30.5271611, 35.046183,
48.464717, 500_000)
# from example on stackexchange, must be true
is_line_segment_intersecting_circle(48.139115, 11.578081, 48.146303, 11.593102, 48.137024, 11.575249, 1000)
# with bigger radius must be false, segment is inside circle
is_line_segment_intersecting_circle(48.139115, 11.578081, 48.146303, 11.593102, 48.137024, 11.575249, 10_000)
# same parameters, different function - must be true, segment is inside circle
is_line_segment_intersecting_circle_or_inside_circle(48.139115, 11.578081, 48.146303, 11.593102, 48.137024, 11.575249,
10_000)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment