diff --git a/core/models/caves.py b/core/models/caves.py index 91453fc..0c8fdad 100644 --- a/core/models/caves.py +++ b/core/models/caves.py @@ -420,6 +420,26 @@ class Entrance(TroggleModel): return cavelist[0].url_parent() else: return "" + + def latlong(self): + station = None + if self.other_station: + try: + station = SurvexStation.objects.get(name = self.other_station) + except: + pass + if self.tag_station: + try: + station = SurvexStation.objects.get(name = self.tag_station) + except: + pass + if self.exact_station: + try: + station = SurvexStation.objects.get(name = self.exact_station) + except: + pass + if station: + return station.latlong() def GetCaveLookup(): diff --git a/core/models/survex.py b/core/models/survex.py index cdc8a80..f62d93b 100644 --- a/core/models/survex.py +++ b/core/models/survex.py @@ -108,6 +108,62 @@ class SurvexStation(models.Model): def __str__(self): return self.name and str(self.name) or "no name" + + def latlong(self): + return utmToLatLng(33, self.x, self.y, northernHemisphere=True) + +import math + +def utmToLatLng(zone, easting, northing, northernHemisphere=True): + if not northernHemisphere: + northing = 10000000 - northing + + a = 6378137 + e = 0.081819191 + e1sq = 0.006739497 + k0 = 0.9996 + + arc = northing / k0 + mu = arc / (a * (1 - math.pow(e, 2) / 4.0 - 3 * math.pow(e, 4) / 64.0 - 5 * math.pow(e, 6) / 256.0)) + + ei = (1 - math.pow((1 - e * e), (1 / 2.0))) / (1 + math.pow((1 - e * e), (1 / 2.0))) + + ca = 3 * ei / 2 - 27 * math.pow(ei, 3) / 32.0 + + cb = 21 * math.pow(ei, 2) / 16 - 55 * math.pow(ei, 4) / 32 + cc = 151 * math.pow(ei, 3) / 96 + cd = 1097 * math.pow(ei, 4) / 512 + phi1 = mu + ca * math.sin(2 * mu) + cb * math.sin(4 * mu) + cc * math.sin(6 * mu) + cd * math.sin(8 * mu) + + n0 = a / math.pow((1 - math.pow((e * math.sin(phi1)), 2)), (1 / 2.0)) + + r0 = a * (1 - e * e) / math.pow((1 - math.pow((e * math.sin(phi1)), 2)), (3 / 2.0)) + fact1 = n0 * math.tan(phi1) / r0 + + _a1 = 500000 - easting + dd0 = _a1 / (n0 * k0) + fact2 = dd0 * dd0 / 2 + + t0 = math.pow(math.tan(phi1), 2) + Q0 = e1sq * math.pow(math.cos(phi1), 2) + fact3 = (5 + 3 * t0 + 10 * Q0 - 4 * Q0 * Q0 - 9 * e1sq) * math.pow(dd0, 4) / 24 + + fact4 = (61 + 90 * t0 + 298 * Q0 + 45 * t0 * t0 - 252 * e1sq - 3 * Q0 * Q0) * math.pow(dd0, 6) / 720 + + lof1 = _a1 / (n0 * k0) + lof2 = (1 + 2 * t0 + Q0) * math.pow(dd0, 3) / 6.0 + lof3 = (5 - 2 * Q0 + 28 * t0 - 3 * math.pow(Q0, 2) + 8 * e1sq + 24 * math.pow(t0, 2)) * math.pow(dd0, 5) / 120 + _a2 = (lof1 - lof2 + lof3) / math.cos(phi1) + _a3 = _a2 * 180 / math.pi + + latitude = 180 * (phi1 - fact1 * (fact2 + fact3 + fact4)) / math.pi + + if not northernHemisphere: + latitude = -latitude + + longitude = ((zone > 0) and (6 * zone - 183.0) or 3.0) - _a3 + + return (latitude, longitude) # # Single SurvexBlock diff --git a/core/views/caves.py b/core/views/caves.py index 2fad12c..1ad8dcf 100644 --- a/core/views/caves.py +++ b/core/views/caves.py @@ -615,3 +615,13 @@ def qm(request, cave_id, qm_id, year, grade=None, blockname=None): "badslug": f"QM.DoesNotExist blockname is not empty string {cave_id=} {year=} {qm_id=} {grade=} {blockname=}" }, ) + +def expo_kml(request): + return render( + request, + "expo.kml", + { + "entrances": Entrance.objects.all() + }, + content_type = "application/vnd.google-earth.kml+xml" + ) diff --git a/urls.py b/urls.py index a5d6c47..1fca988 100644 --- a/urls.py +++ b/urls.py @@ -8,7 +8,7 @@ from troggle.core.views import statistics, survex from troggle.core.views.auth import expologin, expologout from troggle.core.views.caves import (cave3d, caveEntrance, caveindex, cavepage, caveQMs, edit_cave, cave_debug, - edit_entrance, get_entrances, qm) + edit_entrance, get_entrances, qm, expo_kml) from troggle.core.views.drawings import dwgallfiles, dwgfilesingle from troggle.core.views.editor_helpers import image_selector, new_image_form from troggle.core.views.expo import (editexpopage, expofiles_redirect, @@ -230,6 +230,8 @@ trogglepatterns = [ # Helpers to edit HTML re_path(r'^image_selector/(?P.*)', image_selector, name = 'image_selector'), re_path(r'^new_image_form/(?P.*)', new_image_form, name = 'new_image_form'), + + re_path(r'^expo.kml', expo_kml, name = 'expo.kml'), # Final catchall which also serves expoweb handbook pages and imagestiny re_path(r'^(.*)$', expopage, name="expopage"), # CATCHALL assumed relative to EXPOWEB