Skip to content

Instantly share code, notes, and snippets.

@hgenru
Last active August 29, 2015 14:12
Show Gist options
  • Save hgenru/6d8a2354b7831b5167c1 to your computer and use it in GitHub Desktop.
Save hgenru/6d8a2354b7831b5167c1 to your computer and use it in GitHub Desktop.
Кладбищепарсер
import math
import json
from glob import glob
from lxml import etree
import geopy
from geopy.distance import VincentyDistance
def calculate_initial_compass_bearing(pointA, pointB):
"""
Calculates the bearing between two points.
The formulae used is the following:
θ = atan2(sin(Δlong).cos(lat2),
cos(lat1).sin(lat2) − sin(lat1).cos(lat2).cos(Δlong))
:Parameters:
- `pointA: The tuple representing the latitude/longitude for the
first point. Latitude and longitude must be in decimal degrees
- `pointB: The tuple representing the latitude/longitude for the
second point. Latitude and longitude must be in decimal degrees
:Returns:
The bearing in degrees
:Returns Type:
float
"""
if (type(pointA) != tuple) or (type(pointB) != tuple):
raise TypeError("Only tuples are supported as arguments")
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)
# Now we have the initial bearing but math.atan2 return values
# from -180° to + 180° which is not what we want for a compass bearing
# The solution is to normalize the initial bearing as shown below
initial_bearing = math.degrees(initial_bearing)
compass_bearing = (initial_bearing + 360) % 360
return compass_bearing
def calculate_intersection(p1, p2, brg1, brg2):
"""calculate intersection of 2 points given start points and bearings"""
lat1 = math.radians(p1.latitude)
lng1 = math.radians(p1.longitude)
brg13 = math.radians(brg1)
lat2 = math.radians(p2.latitude)
lng2 = math.radians(p2.longitude)
brg23 = math.radians(brg2)
dlat = lat2 - lat1
dlng = lng2 - lng1
sqrt1 = math.sqrt(
math.sin(dlat / 2) * math.sin(dlat / 2) +
math.cos(lat1) * math.cos(lat2)
* math.sin(dlng / 2) * math.sin(dlng / 2))
dist12 = 2 * math.asin(sqrt1)
if dist12 == 0:
return None
brgA = math.acos((math.sin(lat2) - math.sin(lat1) * math.cos(dist12)) /
(math.sin(dist12) * math.cos(lat1)))
brgB = math.acos((math.sin(lat1) - math.sin(lat2) * math.cos(dist12)) /
(math.sin(dist12) * math.cos(lat2)))
if math.sin(dlng) > 0:
brg12 = brgA
brg21 = 2 * math.pi - brgB
else:
brg12 = 2 * math.pi - brgA
brg21 = brgB
alpha1 = (brg13 - brg12 + math.pi) % (2 * math.pi) - math.pi
alpha2 = (brg21 - brg23 + math.pi) % (2 * math.pi) - math.pi
if math.sin(alpha1) == 0 and math.sin(alpha2) == 0:
return None
if math.sin(alpha1) * math.sin(alpha2) < 0:
return None
alpha3 = math.acos(-math.cos(alpha1) * math.cos(alpha2) +
math.sin(alpha1) * math.sin(alpha2) * math.cos(dist12))
dist13 = math.atan2(math.sin(dist12) * math.sin(alpha1) * math.sin(alpha2),
math.cos(alpha2) + math.cos(alpha1) * math.cos(alpha3))
lat3 = math.asin(math.sin(lat1) * math.cos(dist13) +
math.cos(lat1) * math.sin(dist13) * math.cos(brg13))
dlng13 = math.atan2(math.sin(brg13) * math.sin(dist13) * math.cos(lat1),
math.cos(dist13) - math.sin(lat1) * math.sin(lat3))
lng3 = (lng1 + dlng13 + math.pi) % (2 * math.pi) - math.pi
return geopy.Point(math.degrees(lat3), math.degrees(lng3))
def process_entry(entry, features):
name_deceased = entry.attrib.get('TranslatedName', None)
birth_date = entry.attrib.get('Producer', None)
birth_date = birth_date if birth_date != '?' else None
dead_date = entry.attrib.get('Director', None)
dead_date = dead_date if dead_date != '?' else None
row = float(entry.attrib.get(
'Size', '0').replace('/', '.'))
col = float(entry.attrib.get(
'Disks', '0').replace('/', '.'))
picture = entry.attrib.get('Picture', None)
if picture:
# выбрасываем ненужное
picture = picture[9:].replace('\\', '/')
frame = int(entry.attrib.get('Framerate', 0))
# Разбор для второй секции
if frame == 2:
# Хардкодим параметры отступов
ROW = 0.003
COL = 0.0017
row_height = ROW * row
col_width = COL * col
# Хардкодим начальные точки
latitude0, longitude0 = 51.5424084, 45.9893999
latitude1, longitude1 = 51.5430606, 45.9873131
latitude2, longitude2 = 51.5429205, 45.9898531
bearing_row = calculate_initial_compass_bearing(
(latitude0, longitude0),
(latitude1, longitude1)
)
bearing_col = calculate_initial_compass_bearing(
(latitude0, longitude0),
(latitude2, longitude2)
)
row_destination = VincentyDistance(
kilometers=row_height).destination(
geopy.Point(latitude0, longitude0), bearing_row)
col_destination = VincentyDistance(
kilometers=col_width).destination(
geopy.Point(latitude0, longitude0), bearing_col)
intersection = calculate_intersection(
row_destination, col_destination, bearing_col, bearing_row)
if not intersection:
# print('Can\'t process not valid entry')
return
feature = {
'type': 'Feature',
'geometry': {
'type': 'Point',
'coordinates': [
intersection.longitude,
intersection.latitude
]
},
'properties': {
'nameDeceased': name_deceased,
'birthDate': birth_date,
'deadDate': dead_date,
'row': row,
'col': col,
'picture': picture
}
}
features.append(feature)
if __name__ == '__main__':
xmlfiles = glob('*.xml')
features = list()
for xmlfile in xmlfiles:
tree = etree.parse(xmlfile)
for entry in tree.xpath('/AntMovieCatalog/Catalog/Contents/Movie'):
process_entry(entry, features)
to_dump = {
'type': 'FeatureCollection',
'features': features
}
dumped = json.dumps(to_dump)
with open('saratov-celemetry.json', 'w') as f:
f.write(dumped)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment