Last active
August 29, 2015 14:12
-
-
Save hgenru/6d8a2354b7831b5167c1 to your computer and use it in GitHub Desktop.
Кладбищепарсер
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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