kml/kml.py
changeset 0 bb616224c02a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kml/kml.py	Mon May 18 08:48:51 2020 +0200
@@ -0,0 +1,263 @@
+import sys
+import xml.sax.saxutils
+from math import *
+
+class Kml():
+    def __init__(self):
+        self.out = sys.stdout
+        self.placemark = Placemark(self)
+        self.tour = Tour(self)
+        self.playlist = Playlist(self)
+        self.flyto = FlyTo(self)
+        self.lookat = LookAt(self)
+        self.camera = Camera(self)
+        self.document = Document(self)
+        self.folder = Folder(self)
+        self.xml = Xml(self)
+
+    def documentProlog(self, fn):
+        self.xml.head()
+        self.document.head(fn)
+
+    def documentEpilog(self):
+        self.document.tail()
+        self.xml.tail()
+
+    def folderProlog(self, fn):
+        self.folder.head(fn)
+
+    def folderEpilog(self):
+        self.folder.tail()
+
+    def tourProlog(self, fn):
+        self.tour.head(fn)
+        self.playlist.head()
+
+    def tourEpilog(self):
+        self.playlist.tail()
+        self.tour.tail()
+
+    def placemarkProlog(self, fn):
+        self.xml.head()
+        self.placemark.head(fn)
+
+    def placemarkEpilog(self):
+        self.placemark.tail()
+        self.xml.tail()
+
+    def urlPlacemark(self, url, path):
+        # ref = '<a href="http://{}/index.py">{}</a>'.format(qualname, qualname)
+        ref = '<a href="{}">{}</a>'.format(url, path)
+        p = self.pr
+        p('<Placemark>')
+        p('<name>{ref}</name>'.format(ref = xml.sax.saxutils.escape(ref)))
+        p('</Placemark>')
+
+    def wait(self, dur):
+        self.pr('\n<gx:Wait><gx:duration>{}</gx:duration></gx:Wait>'.format(dur))
+
+    def comm(self, c):
+        self.pr('\n<!-- {} -->'.format(c))
+
+    def pr(self, s):
+        print(s, file=self.out)
+
+class Xml():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def head(self):
+        self.kml.pr('<?xml version="1.0" encoding="UTF-8"?>')
+        self.kml.pr('<kml')
+        self.kml.pr('xmlns="http://www.opengis.net/kml/2.2"')
+        self.kml.pr('xmlns:gx="http://www.google.com/kml/ext/2.2"')
+        self.kml.pr('>')
+
+    def tail(self):
+        self.kml.pr('\n</kml>')
+
+class Document():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def head(self, fn):
+        self.kml.pr('<Document>')
+        self.kml.pr('<name>{}</name>'.format(fn))
+        self.kml.pr('<open>1</open>')
+
+    def tail(self):
+        self.kml.pr('\n</Document>')
+
+
+class Folder():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def head(self, fn):
+        self.kml.pr('<Folder>')
+        self.kml.pr('<name>{}</name>'.format(fn))
+        self.kml.pr('<open>1</open>')
+
+    def tail(self):
+        self.kml.pr('\n</Folder>')
+
+class Tour():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def head(self, fn):
+        self.kml.pr('\n<gx:Tour>')
+        self.kml.pr('<name>{}</name>'.format(fn))
+
+    def tail(self):
+        self.kml.pr('\n</gx:Tour>')
+
+class Playlist():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def head(self):
+        self.kml.pr('\n<gx:Playlist>')
+
+    def tail(self):
+        self.kml.wait(1)
+        self.kml.pr('\n</gx:Playlist>')
+
+class FlyTo():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def head(self, dur, smooth):
+        self.kml.pr('<gx:FlyTo>')
+        self.kml.pr('<gx:duration>{}</gx:duration>'.format(dur))
+        self.kml.pr('<gx:flyToMode>{}</gx:flyToMode>'.format('smooth' if smooth else 'bounce'))
+
+    def tail(self):
+        self.kml.pr('\n</gx:FlyTo>')
+
+class LookAt():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def run(self, long,lat,alt,head,tilt,range):
+        self.kml.pr('\n<LookAt>')
+        self.kml.pr('<latitude>{}</latitude>'.format(lat))
+        self.kml.pr('<longitude>{}</longitude>'.format(long))
+        self.kml.pr('<altitude>{}</altitude>'.format(alt))
+        self.kml.pr('<heading>{}</heading>'.format(head))
+        self.kml.pr('<tilt>{}</tilt>'.format(tilt))
+        self.kml.pr('<range>{}</range>'.format(range))
+        self.kml.pr('<altitudeMode>relativeToGround</altitudeMode>')
+        self.kml.pr('</LookAt>')
+
+class Camera():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def run(self,long,lat,alt,head,tilt,roll):
+        self.kml.pr('<Camera>')
+        self.kml.pr('<latitude>{}</latitude>'.format(lat))
+        self.kml.pr('<longitude>{}</longitude>'.format(long))
+        self.kml.pr('<altitude>{}</altitude>'.format(alt))
+        self.kml.pr('<heading>{}</heading>'.format(head))
+        self.kml.pr('<tilt>{}</tilt>'.format(tilt))
+        self.kml.pr('<roll>{}</roll>'.format(roll))
+        self.kml.pr('<altitudeMode>relativeToSeaFloor</altitudeMode>')
+        self.kml.pr('</Camera>')
+
+    def runL(self, long, lat, alt, head, tilt, range, roll):
+        # dostává parametry LookAt, které konvertuje na parametry Camera tak, aby pohled byl stejný
+        dLO, dLA, Z = l2c(lat, head, tilt, range)
+        self.run(long + dLO, lat + dLA, Z, head, tilt, roll)
+
+class Placemark():
+    def __init__(self, kml):
+        self.kml = kml
+
+    def head(self, fn):
+        self.kml.pr('<Placemark>')
+        self.kml.pr('<name>{}</name>'.format(fn))
+        self.kml.pr('<visibility>0</visibility>')
+        self.kml.pr('<styleUrl>#PIN_YELLOW</styleUrl>')
+
+    def tail(self):
+        self.kml.pr('\n</Placemark>')
+
+class SpeedAdjust():
+    keys = ['none', 'linear', 'parabolic', 'tangential', 'exponential']
+    abrv = {'none':'none', 'linear':'lin', 'parabolic':'par', 'tangential':'tang', 'exponential':'exp'}
+
+    def __init__(self, const, koef, steps, config):
+        self.slowdowns = {'none':self.Const, 'linear':self.Linear, 'parabolic':self.Parabolic, 'tangential':self.Tangent, 'exponential':self.Exponential}
+        self.const = const
+        self.koef = koef
+        self.steps = steps
+        self.c = config
+
+    def phase(self):
+        return 1 - self.c.xi / self.c.x0.val
+
+    class Const():
+        p = 1					# empirická konstanta
+        def __init__(self, sa):
+            self.sa = sa
+        def koef(self):
+            return self.p / self.sa.const
+
+    class Linear():
+        p = 2					# empirická konstanta
+        def __init__(self, sa):
+            self.sa = sa
+        def koef(self):
+            return self.p * self.sa.koef * self.sa.phase() / self.sa.const
+
+    class Parabolic():
+        p = 2					# empirická konstanta
+        def __init__(self, sa):
+            self.sa = sa
+        def koef(self):
+            return self.p * pow(self.sa.koef * self.sa.phase(), 2) / self.sa.const
+
+    class Tangent():
+        p = 1					# empirická konstanta
+        def __init__(self, sa):
+            self.sa = sa
+        def koef(self):
+            margin = atan(self.sa.koef)		# < pi/2
+            return (1 + self.p * tan(self.sa.phase() * margin)) / self.sa.const
+
+    class Exponential():
+        p = 1					# empirická konstanta
+        def __init__(self, sa):
+            self.sa = sa
+        def koef(self):
+            return pow(e, self.p * self.sa.koef * self.sa.phase()) / self.sa.const
+
+def canonGeodetic(a):
+    if(a > 360 or a < -360): a = a % 360
+    if(a > 180): a = a - 360
+    if(a < -180): a = a + 360
+    return a
+
+def can360(a360):
+    if(a360 < 0): a360 = a360 + 360
+    elif(a360 > 360): a360 = a360 - 360
+    return a360
+
+def can180(a180):
+    if(a180 < -180): a180 = a180 + 360
+    elif(a180 > 180): a180 = a180 - 360
+    return a180
+
+def l2c(lat, head, tilt, range):
+    RZ = 6378000
+    RL = RZ * cos(radians(lat))
+    Hc = can360(head + 180)
+    Z = range * cos(radians(tilt))
+    d = sqrt(pow(range,2) - pow(Z,2))
+    dLA = degrees(atan(d * cos(radians(Hc)) / RZ))
+    dLO = degrees(atan(d * sin(radians(Hc)) / RL))
+    return dLO, dLA, Z
+
+def deb(s):
+    print('+++ {}'.format(s), file=sys.stderr)