SpatialParse / utils /geoutil.py
Shunfeng Zheng
Upload 89 files
17e77ea verified
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Aug 2 12:45:21 2022
@author: syed
"""
import math
import re
import regex_spatial
import quantities as pq
from math import radians, cos, sin, asin, sqrt
import quantities as pq
def get_kilometers(d, unit):
q = float(d) * pq.CompoundUnit(unit)
q.units = pq.km
return q.magnitude
def ConvertToRadian(input):
return input * math.pi / 180
def get_level1(ent):
level_1 = re.search(regex_spatial.get_level1_regex(), ent)
if level_1 is not None:
return level_1.group()
return None
def get_level2(ent):
level_2 = re.search(regex_spatial.get_level2_regex(), ent)
if level_2 is not None:
return level_2.group()
return None
def get_level3(ent):
level_3 = re.search(regex_spatial.get_level3_regex(), ent)
if level_3 is not None:
return level_3.group()
return None
def get_ase(ent):
abs_sp = ent.split("_")
return abs_sp[len(abs_sp)-1]
def get_ent(ent):
return get_ase(ent), get_level1(ent), get_level2(ent), get_level3(ent)
def get_centroid(coordinates, centroid, mini, maxi):
average = (mini + maxi)/2
diff = []
ind = 0
for p in coordinates:
diff.append(abs( p[2] - average))
ind = diff.index(min(diff))
return midpoint(centroid[0], centroid[1], coordinates[ind][0], coordinates[ind][1], average)
def calculateArea(coordinates):
area = 0
if (len(coordinates) > 2):
i = 0
for i in range(len(coordinates) - 1):
p1 = coordinates[i]
p2 = coordinates[i + 1]
area += math.radians(p2[0] - p1[0]) * (2 + math.sin(ConvertToRadian(p1[1])) + math.sin(math.radians(p2[0])))
area = area * 6378137 * 6378137 / 1000000
area = abs(round(area, 2)) + 2
return area
def get_midmid_point(centroid, point1, point2, is_midmid):
mid1 = midpoint(centroid[0], centroid[1],
point1[0], point1[1]
, point1[2])
mid2 = midpoint(centroid[0], centroid[1],
point2[0], point2[1],
point2[2])
midmid1 = midpoint(centroid[0], centroid[1],
mid1[0], mid1[1]
, mid1[2])
midmid2 = midpoint(centroid[0], centroid[1],
mid2[0], mid2[1],
mid2[2])
if is_midmid:
return midmid1, midmid2
else:
return mid1, mid2
def getPointByDistanceAngle(lat, ln, angle, distanceInKm):
R = 6378.1 #Radius of the Earth
brng = angle * math.pi /180 #Bearing is 90 degrees converted to radians.
d = distanceInKm #Distance in km
#lat2 52.20444 - the lat result I'm hoping for
#lon2 0.36056 - the long result I'm hoping for.
lat1 = math.radians(lat) #Current lat point converted to radians
lon1 = math.radians(ln) #Current long point converted to radians
lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
math.cos(lat1)*math.sin(d/R)*math.cos(brng))
lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
math.cos(d/R)-math.sin(lat1)*math.sin(lat2))
lat2 = math.degrees(lat2)
lon2 = math.degrees(lon2)
return [lon2, lat2, angle]
def midpoint(x1, y1, x2, y2, angle):
lonA = math.radians(y1)
lonB = math.radians(y2)
latA = math.radians(x1)
latB = math.radians(x2)
dLon = lonB - lonA
Bx = math.cos(latB) * math.cos(dLon)
By = math.cos(latB) * math.sin(dLon)
latC = math.atan2(math.sin(latA) + math.sin(latB),
math.sqrt((math.cos(latA) + Bx) * (math.cos(latA) + Bx) + By * By))
lonC = lonA + math.atan2(By, math.cos(latA) + Bx)
lonC = (lonC + 3 * math.pi) % (2 * math.pi) - math.pi
latitude = round(math.degrees(latC), 8)
longitude = round(math.degrees(lonC),8)
return [latitude, longitude, angle]
def midpoint(y1, x1, y2, x2, angle):
lonA = math.radians(y1)
lonB = math.radians(y2)
latA = math.radians(x1)
latB = math.radians(x2)
dLon = lonB - lonA
Bx = math.cos(latB) * math.cos(dLon)
By = math.cos(latB) * math.sin(dLon)
latC = math.atan2(math.sin(latA) + math.sin(latB),
math.sqrt((math.cos(latA) + Bx) * (math.cos(latA) + Bx) + By * By))
lonC = lonA + math.atan2(By, math.cos(latA) + Bx)
lonC = (lonC + 3 * math.pi) % (2 * math.pi) - math.pi
latitude = round(math.degrees(latC), 8)
longitude = round(math.degrees(lonC) ,8)
print([longitude, latitude, angle], 'midmid')
return [longitude, latitude, angle
]
def calculate_bearing(pointA, pointB):
if (type(pointA) != tuple) or (type(pointB) != tuple):
return 400
if (type(pointB[0]) != float) or (type(pointB[0]) != float):
return 400
lat1 = math.radians(pointA[0])
lat2 = math.radians(pointB[0])
diffLong = math.radians(pointB[1] - pointA[1])
x = math.sin(diffLong) * math.cos(lat2)
y = math.cos(lat1) * math.sin(lat2) - (math.sin(lat1)
* math.cos(lat2) * math.cos(diffLong))
initial_bearing = math.atan2(x, y)
initial_bearing = math.degrees(initial_bearing)
compass_bearing = (initial_bearing + 360) % 360
return compass_bearing
def getPointByDistanceAngle(lat, ln, angle, distance, unit):
#distanceInKm = distance
R = 6378.1 #Radius of the Earth
brng = float(angle) * math.pi /180 #Bearing is 90 degrees converted to radians.
d = get_kilometers(distance, unit) #Distance in km
lat1 = math.radians(lat) #Current lat point converted to radians
lon1 = math.radians(ln) #Current long point converted to radians
lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
math.cos(lat1)*math.sin(d/R)*math.cos(brng))
lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
math.cos(d/R)-math.sin(lat1)*math.sin(lat2))
lat2 = math.degrees(lat2)
lon2 = math.degrees(lon2)
return (round(lon2,8), round(lat2,8), angle)
def calculatePointByDistance(lat, ln, angle, distance, unit):
coff = 100/(6378*1.56)
kms = get_kilometers(distance, unit)
d = kms * coff
angle_x = math.cos( angle ) # * math.pi/180
angle_y = math.sin( angle) # * math.pi/180
lat_new = lat + (d * angle_x)
ln_new = ln + (d * angle_y)
return (round(ln_new,8), round(lat_new,8), angle)
def pointByAngle(lat, ln, angle, distance, unit):
R = 6378.1 #Radius of the Earth
brng = angle * math.pi /180 #Bearing is 90 degrees converted to radians.
d = get_kilometers(distance, unit) #Distance in km
#lat2 52.20444 - the lat result I'm hoping for
#lon2 0.36056 - the long result I'm hoping for.
lat1 = math.radians(lat) #Current lat point converted to radians
lon1 = math.radians(ln) #Current long point converted to radians
lat2 = math.asin( math.sin(lat1)*math.cos(d/R) +
math.cos(lat1)*math.sin(d/R)*math.cos(brng))
lon2 = lon1 + math.atan2(math.sin(brng)*math.sin(d/R)*math.cos(lat1),
math.cos(d/R)-math.sin(lat1)*math.sin(lat2))
lat2 = math.degrees(lat2)
lon2 = math.degrees(lon2)
return (lon2, lat2, angle)
def getPointByDistance(lat, ln, angle, distance, unit):
kms = get_kilometers(distance, unit)
coef = kms / 111.32
new_lat = lat + coef
new_long = ln + coef / math.cos(lat * 0.01745)
return (round(new_lat,8), round(new_long,8), angle)
def haversine(lon1, lat1, lon2, lat2):
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
c = 2 * asin(sqrt(a))
km = 6371* c
return km