def make_photos_folder(self, globals): if not len(self.photos): return kmz.kmz() folder = kml.Folder(name='Photos', open=0) for photo in sorted(self.photos, key=operator.attrgetter('dt')): if photo.coord: coord = photo.coord if photo.elevation_data: altitude_mode = 'absolute' else: altitude_mode = 'clampToGround' else: coord = self.track.coord_at(photo.dt - globals.tz_offset) altitude_mode = self.altitude_mode point = kml.Point(coordinates=[coord], altitudeMode=altitude_mode) if photo.description: title = '%s: %s' % (photo.name, photo.description) else: title = photo.name description = '<h3>%s</h3>%s' % (title, photo.to_html_img()) style_url = globals.stock.photo_style.url() placemark = kml.Placemark(point, name=photo.name, description=kml.CDATA(description), Snippet=kml.CDATA(description), styleUrl=style_url) folder.add(placemark) return kmz.kmz(folder)
def make_shadow_folder(self, globals): if not self.track.elevation_data: return kmz.kmz() style_url = globals.stock.radio_folder_style.url() folder = kmz.kmz(kml.Folder(name='Shadow', open=0, styleUrl=style_url)) folder.add(globals.stock.invisible_none_folder) style = kml.Style(kml.LineStyle(color='ff000000', width=1)) folder.add( self.make_solid_track(globals, style, 'clampToGround', name='Normal')) line_style = kml.LineStyle(color='00000000', width=1) poly_style = kml.PolyStyle(color='80000000') style = kml.Style(line_style, poly_style) folder.add( self.make_solid_track(globals, style, 'absolute', True, name='Extrude', visibility=0)) style = kml.Style(kml.LineStyle(color=self.color, width=self.width)) folder.add( self.make_solid_track(globals, style, 'clampToGround', name='Solid color', visibility=0)) return folder
def to_kmz(self, globals): self.time_positions = [globals.graph_width * (t - globals.scales.time.range[0]) / (globals.scales.time.range[1] - globals.scales.time.range[0]) for t in self.track.t] folder = kmz.kmz(kml.Folder(name=self.track.filename, open=1)) folder.add(self.make_description(globals)) folder.add(self.make_snippet(globals)) folder.add(self.make_track_folder(globals)) folder.add(self.make_shadow_folder(globals)) folder.add(self.make_photos_folder(globals)) folder.add(self.make_xc_folder(globals)) folder.add(self.make_altitude_marks_folder(globals)) if self.track.elevation_data: eles = [c.ele for c in self.track.coords] folder.add(self.make_graph(globals, eles, globals.scales.altitude)) folder.add(self.make_analysis_folder(globals, 'thermal', self.track.thermals, globals.stock.thermal_style.url())) folder.add(self.make_analysis_folder(globals, 'glide', self.track.glides, globals.stock.glide_style.url())) folder.add(self.make_analysis_folder(globals, 'dive', self.track.dives, globals.stock.dive_style.url())) folder.add(self.make_time_marks_folder(globals)) return folder
def to_kmz(self, globals): self.time_positions = [ globals.graph_width * (t - globals.scales.time.range[0]) / (globals.scales.time.range[1] - globals.scales.time.range[0]) for t in self.track.t ] folder = kmz.kmz(kml.Folder(name=self.track.filename, open=1)) folder.add(self.make_description(globals)) folder.add(self.make_snippet(globals)) if self.track.declaration: folder.add(make_task_folder(globals, self.track.declaration)) folder.add(self.make_track_folder(globals)) folder.add(self.make_shadow_folder(globals)) folder.add(self.make_animation(globals)) folder.add(self.make_photos_folder(globals)) folder.add(self.make_xc_folder(globals)) folder.add(self.make_altitude_marks_folder(globals)) if self.track.elevation_data: eles = [c.ele for c in self.track.coords] folder.add(self.make_graph(globals, eles, globals.scales.altitude)) folder.add( self.make_analysis_folder(globals, 'thermal', self.track.thermals, globals.stock.thermal_style.url())) folder.add( self.make_analysis_folder(globals, 'glide', self.track.glides, globals.stock.glide_style.url())) folder.add( self.make_analysis_folder(globals, 'dive', self.track.dives, globals.stock.dive_style.url())) folder.add(self.make_time_marks_folder(globals)) return folder
def make_altitude_marks_folder(self, globals): if not self.track.elevation_data: return kmz.kmz() style_url = globals.stock.check_hide_children_style.url() folder = kml.Folder(name='Altitude marks', styleUrl=style_url, visibility=0) for index, j in util.salient2([c.ele for c in self.track.coords], [100, 50, 10]): coord = self.track.coords[index] i = globals.scales.altitude.discretize(coord.ele) style_url = globals.altitude_styles[j][i].url() folder.add(self.make_placemark(globals, coord, altitudeMode='absolute', name='%dm' % coord.ele, style_url=style_url)) return kmz.kmz(folder)
def make_colored_track(self, globals, values, scale, altitude_mode, scale_chart=True, **folder_options): style_url = globals.stock.check_hide_children_style.url() folder = kml.Folder(name='Colored by %s' % scale.title, styleUrl=style_url, **folder_options) styles = [kml.Style(kml.LineStyle(color=color, width=self.width)) for color in scale.colors()] discrete_values = map(scale.discretize, values) for sl in util.runs(discrete_values): coordinates = self.track.coords[sl.start:sl.stop + 1] line_string = kml.LineString(coordinates=coordinates, altitudeMode=self.altitude_mode) style_url = kml.styleUrl(styles[discrete_values[sl.start]].url()) placemark = kml.Placemark(style_url, line_string) folder.add(placemark) if scale_chart: href = self.make_scale_chart(globals, scale).get_url() icon = kml.Icon(href=kml.CDATA(href)) overlay_xy = kml.overlayXY(x=0, xunits='fraction', y=1, yunits='fraction') screen_xy = kml.screenXY(x=0, xunits='fraction', y=1, yunits='fraction') size = kml.size(x=0, xunits='fraction', y=0, yunits='fraction') screen_overlay = kml.ScreenOverlay(icon, overlay_xy, screen_xy, size) folder.add(screen_overlay) return kmz.kmz(folder).add_roots(*styles)
def make_animation(self, globals): icon_style = kml.IconStyle(globals.stock.animation_icon, color=self.color, scale=globals.stock.icon_scales[0]) list_style = kml.ListStyle(listItemType='checkHideChildren') style = kml.Style(icon_style, list_style) folder = kml.Folder(style, name='Animation', visibility=0) point = kml.Point(coordinates=[self.track.coords[0]], altitudeMode=self.altitude_mode) timespan = kml.TimeSpan(end=kml.dateTime(self.track.coords[0].dt)) placemark = kml.Placemark(point, timespan, styleUrl=style.url()) folder.add(placemark) for i in xrange(1, len(self.track.coords)): coord = self.track.coords[i - 1].halfway_to(self.track.coords[i]) point = kml.Point(coordinates=[coord], altitudeMode=self.altitude_mode) begin = kml.dateTime(self.track.coords[i - 1].dt) end = kml.dateTime(self.track.coords[i].dt) timespan = kml.TimeSpan(begin=begin, end=end) placemark = kml.Placemark(point, timespan, styleUrl=style.url()) folder.add(placemark) point = kml.Point(coordinates=[self.track.coords[-1]], altitudeMode=self.altitude_mode) timespan = kml.TimeSpan(begin=kml.dateTime(self.track.coords[-1].dt)) placemark = kml.Placemark(point, timespan, styleUrl=style.url()) folder.add(placemark) return kmz.kmz(folder)
def flights2kmz(flights, roots=[], tz_offset=0, task=None): stock = Stock() globals = util.OpenStruct() globals.stock = stock globals.bounds = util.BoundsSet() for flight in flights: globals.bounds.update(flight.track.bounds) if globals.bounds.climb.min < -5.0: globals.bounds.climb.min = -5.0 if globals.bounds.climb.max > 5.0: globals.bounds.climb.max = 5.0 globals.tz_offset = datetime.timedelta(0, 3600 * tz_offset) globals.task = task globals.scales = util.OpenStruct() globals.scales.altitude = Scale(globals.bounds.ele.tuple(), title='altitude', gradient=default_gradient) globals.altitude_styles = [] for i in xrange(0, 3): altitude_styles = [] for c in globals.scales.altitude.colors(): balloon_style = kml.BalloonStyle(text='$[description]') icon_style = kml.IconStyle(globals.stock.icons[i], color=c, scale=globals.stock.icon_scales[i]) label_style = kml.LabelStyle(color=c, scale=globals.stock.label_scales[i]) style = kml.Style(balloon_style, icon_style, label_style) altitude_styles.append(style) stock.kmz.add_roots(*altitude_styles) globals.altitude_styles.append(altitude_styles) gradient = bilinear_gradient globals.scales.climb = ZeroCenteredScale(globals.bounds.climb.tuple(), title='climb', step=0.1, gradient=gradient) globals.scales.speed = Scale(globals.bounds.speed.tuple(), title='ground speed', gradient=default_gradient) globals.scales.time = TimeScale(globals.bounds.time.tuple(), tz_offset=globals.tz_offset) globals.scales.t = Scale(globals.bounds.t.tuple(), title='time', gradient=default_gradient) if hasattr(globals.bounds, 'tas'): globals.scales.tas = Scale(globals.bounds.tas.tuple(), title='air speed', gradient=default_gradient) globals.graph_width = 600 globals.graph_height = 300 globals.default_track = 'solid_color' if len(flights) == 1: if flights[0].track.elevation_data: globals.default_track = 'climb' else: globals.default_track = 'speed' result = kmz.kmz() result.add_siblings(stock.kmz) result.add_roots(kml.open(1), *roots) if globals.task: result.add_siblings(make_task_folder(globals, globals.task)) for flight in flights: result.add_siblings(flight.to_kmz(globals)) return result
def make_track_folder(self, globals): style_url = globals.stock.radio_folder_style.url() folder = kmz.kmz(kml.Folder(name='Track', open=1, styleUrl=style_url)) folder.add(globals.stock.invisible_none_folder) if self.track.elevation_data: visibility = globals.default_track == 'climb' folder.add( self.make_colored_track(globals, self.track.climb, globals.scales.climb, 'absolute', visibility=visibility)) visibility = globals.default_track == 'altitude' folder.add( self.make_colored_track(globals, self.track.ele, globals.scales.altitude, 'absolute', visibility=visibility)) visibility = globals.default_track == 'tec' folder.add( self.make_colored_track(globals, self.track.tec, globals.scales.tec, 'absolute', visibility=visibility)) visibility = globals.default_track == 'speed' folder.add( self.make_colored_track(globals, self.track.speed, globals.scales.speed, self.altitude_mode, visibility=visibility)) if hasattr(self.track, 'tas'): visibility = globals.default_track == 'tas' folder.add( self.make_colored_track(globals, self.track.tas, globals.scales.tas, self.altitude_mode, visibility=visibility)) visibility = globals.default_track == 'time' folder.add( self.make_colored_track(globals, self.track.t, globals.scales.t, self.altitude_mode, scale_chart=False, visibility=visibility)) visibility = globals.default_track == 'solid_color' style = kml.Style(kml.LineStyle(color=self.color, width=self.width)) folder.add( self.make_solid_track(globals, style, self.altitude_mode, name='Solid color', visibility=visibility)) return folder
def make_shadow_folder(self, globals): if not self.track.elevation_data: return kmz.kmz() style_url = globals.stock.radio_folder_style.url() folder = kmz.kmz(kml.Folder(name='Shadow', open=0, styleUrl=style_url)) folder.add(globals.stock.invisible_none_folder) style = kml.Style(kml.LineStyle(color='ff000000', width=1)) folder.add(self.make_solid_track(globals, style, 'clampToGround', name='Normal')) line_style = kml.LineStyle(color='00000000', width=1) poly_style = kml.PolyStyle(color='80000000') style = kml.Style(line_style, poly_style) folder.add(self.make_solid_track(globals, style, 'absolute', True, name='Extrude', visibility=0)) style = kml.Style(kml.LineStyle(color=self.color, width=self.width)) folder.add(self.make_solid_track(globals, style, 'clampToGround', name='Solid color', visibility=0)) return folder
def make_solid_track(self, globals, style, altitude_mode, extrude=None, **folder_options): line_string = kml.LineString(coordinates=self.track.coords, altitudeMode=altitude_mode) if extrude: line_string.add(extrude=1) placemark = kml.Placemark(style, line_string) style_url = globals.stock.check_hide_children_style.url() folder_options['styleUrl'] = style_url return kmz.kmz(kml.Folder(placemark, **folder_options))
def make_snippet(self, globals): if self.xc: route = sorted(self.xc.routes, key=operator.attrgetter('score'), reverse=True)[0] xc = '%.1fkm %s' % (route.distance, route.name) else: xc = None date = self.track.bounds.time.min + globals.tz_offset strings = [self.pilot_name, xc, date.strftime('%Y-%m-%d')] snippet = kml.Snippet(', '.join(s for s in strings if s)) return kmz.kmz(snippet)
def make_tour_folder(self, globals): style_url = globals.stock.check_hide_children_style.url() folder = kmz.kmz(kml.Folder(name='Tour', styleUrl=style_url)) dt = self.track.coords[0].dt delta = datetime.timedelta(seconds=15 * 60) coords = [] while dt < self.track.coords[-1].dt: coords.append(self.track.coord_at(dt)) dt += delta for i in xrange(0, len(coords)): j = (i + 1) % len(coords) point = kml.Point(coordinates=[coords[i]], altitudeMode=self.altitude_mode) heading = coords[i].initial_bearing_to_deg(coords[j]) camera = kml.Camera(altitude=coords[i].ele, heading=heading, latitude=coords[i].lat_deg, longitude=coords[i].lon_deg, tilt=75) placemark = kml.Placemark(point, camera) folder.add(placemark) return folder
def make_track_folder(self, globals): style_url = globals.stock.radio_folder_style.url() folder = kmz.kmz(kml.Folder(name='Track', open=1, styleUrl=style_url)) folder.add(globals.stock.invisible_none_folder) if self.track.elevation_data: visibility = globals.default_track == 'climb' folder.add(self.make_colored_track(globals, self.track.climb, globals.scales.climb, 'absolute', visibility=visibility)) visibility = globals.default_track == 'altitude' folder.add(self.make_colored_track(globals, self.track.ele, globals.scales.altitude, 'absolute', visibility=visibility)) visibility = globals.default_track == 'tec' folder.add(self.make_colored_track(globals, self.track.tec, globals.scales.tec, 'absolute', visibility=visibility)) visibility = globals.default_track == 'speed' folder.add(self.make_colored_track(globals, self.track.speed, globals.scales.speed, self.altitude_mode, visibility=visibility)) if hasattr(self.track, 'tas'): visibility = globals.default_track == 'tas' folder.add(self.make_colored_track(globals, self.track.tas, globals.scales.tas, self.altitude_mode, visibility=visibility)) visibility = globals.default_track == 'time' folder.add(self.make_colored_track(globals, self.track.t, globals.scales.t, self.altitude_mode, scale_chart=False, visibility=visibility)) visibility = globals.default_track == 'solid_color' style = kml.Style(kml.LineStyle(color=self.color, width=self.width)) folder.add(self.make_solid_track(globals, style, self.altitude_mode, name='Solid color', visibility=visibility)) return folder
def make_description(self, globals): rows = [] if self.pilot_name: rows.append(('Pilot name', self.pilot_name)) if self.glider_type: rows.append(('Glider type', self.glider_type)) if self.glider_id: rows.append(('Glider ID', self.glider_id)) take_off_time = self.track.bounds.time.min + globals.tz_offset rows.append(('Take-off time', take_off_time.strftime('%H:%M:%S'))) landing_time = self.track.bounds.time.max + globals.tz_offset rows.append(('Landing time', landing_time.strftime('%H:%M:%S'))) duration = (self.track.bounds.time.max - self.track.bounds.time.min).seconds hour, seconds = divmod(duration, 3600) minute, second = divmod(seconds, 60) rows.append(('Duration', '%dh %02dm %02ds' % (hour, minute, second))) if self.track.elevation_data: rows.append( ('Take-off altitude', '%dm' % self.track.coords[0].ele)) rows.append( ('Maximum altitude', '%dm' % self.track.bounds.ele.max)) rows.append( ('Minimum altitude', '%dm' % self.track.bounds.ele.min)) rows.append( ('Landing altitude', '%dm' % self.track.coords[-1].ele)) rows.append( ('Total altitude gain', '%dm' % self.track.total_dz_positive)) rows.append( ('Maximum altitude gain', '%dm' % self.track.max_dz_positive)) rows.append( ('Maximum climb', '%.1fm/s' % self.track.bounds.climb.max)) rows.append( ('Maximum sink', '%.1fm/s' % self.track.bounds.climb.min)) rows.append( ('Maximum speed', '%.1fkm/h' % self.track.bounds.speed.max)) if self.url: components = urlparse.urlparse(self.url) html = '<a href="%s">%s</a>' % (self.url, components.netloc) rows.append(('Flight URL', html)) table = make_table(rows) return kmz.kmz(kml.description(kml.CDATA(table)))
def make_description(self, globals): rows = [] if self.pilot_name: rows.append(('Pilot name', self.pilot_name)) if self.glider_type: rows.append(('Glider type', self.glider_type)) if self.glider_id: rows.append(('Glider ID', self.glider_id)) take_off_time = self.track.bounds.time.min + globals.tz_offset rows.append(('Take-off time', take_off_time.strftime('%H:%M:%S'))) landing_time = self.track.bounds.time.max + globals.tz_offset rows.append(('Landing time', landing_time.strftime('%H:%M:%S'))) duration = (self.track.bounds.time.max - self.track.bounds.time.min).seconds hour, seconds = divmod(duration, 3600) minute, second = divmod(seconds, 60) rows.append(('Duration', '%dh %02dm %02ds' % (hour, minute, second))) if self.track.elevation_data: rows.append(('Take-off altitude', '%dm' % self.track.coords[0].ele)) rows.append(('Maximum altitude', '%dm' % self.track.bounds.ele.max)) rows.append(('Minimum altitude', '%dm' % self.track.bounds.ele.min)) rows.append(('Landing altitude', '%dm' % self.track.coords[-1].ele)) rows.append(('Total altitude gain', '%dm' % self.track.total_dz_positive)) rows.append(('Maximum altitude gain', '%dm' % self.track.max_dz_positive)) rows.append(('Maximum climb', '%.1fm/s' % self.track.bounds.climb.max)) rows.append(('Maximum sink', '%.1fm/s' % self.track.bounds.climb.min)) rows.append(('Maximum speed', '%.1fkm/h' % self.track.bounds.speed.max)) if self.url: components = urlparse.urlparse(self.url) html = '<a href="%s">%s</a>' % (self.url, components.netloc) rows.append(('Flight URL', html)) table = make_table(rows) return kmz.kmz(kml.description(kml.CDATA(table)))
def make_analysis_folder(self, globals, title, slices, style_url): if not self.track.elevation_data or len(slices) == 0: return kmz.kmz() folder_style_url = globals.stock.check_hide_children_style.url() folder = kml.Folder(name=title.capitalize() + "s", styleUrl=folder_style_url, visibility=0) for sl in slices: coord0 = self.track.coords[sl.start] coord1 = self.track.coords[sl.stop] coord = coord0.halfway_to(coord1) point = kml.Point(coordinates=[coord], altitudeMode='absolute') total_dz_positive = total_dz_negative = 0 peak_climb = util.Bounds(0.0) for i in xrange(sl.start, sl.stop): dz = self.track.coords[i + 1].ele - self.track.coords[i].ele dt = self.track.t[i + 1] - self.track.t[i] if dz > 0: total_dz_positive += dz elif dz < 0: total_dz_negative += dz peak_climb.update(float(dz) / dt) climb = util.Bounds(self.track.climb[sl]) dz = float(self.track.coords[sl.stop].ele - self.track.coords[sl.start].ele) dt = self.track.t[sl.stop] - self.track.t[sl.start] dp = coord0.distance_to(coord1) theta = coord0.initial_bearing_to(coord1) dict = {} dict['altitude_change'] = int(round(dz)) dict['average_climb'] = round(dz / dt, 1) dict['maximum_climb'] = round(climb.max, 1) dict['peak_climb'] = round(peak_climb.max, 1) divisor = dt * climb.max if divisor == 0: dict['efficiency'] = UP_TACK else: dict['efficiency'] = int(round(100.0 * dz / divisor)) dict['distance'] = round(dp / 1000.0, 1) average_ld = round(-dp / dz, 1) if dz < 0 else INFINITY dict['average_ld'] = average_ld dict['average_speed'] = round(3.6 * dp / dt, 1) dict['maximum_descent'] = round(climb.min, 1) dict['peak_descent'] = round(peak_climb.min, 1) dict['start_altitude'] = coord0.ele dict['finish_altitude'] = coord1.ele start_time = coord0.dt + globals.tz_offset dict['start_time'] = start_time.strftime('%H:%M:%S') stop_time = coord1.dt + globals.tz_offset dict['finish_time'] = stop_time.strftime('%H:%M:%S') duration = self.track.t[sl.stop] - self.track.t[sl.start] dict['duration'] = '%dm %02ds' % divmod(duration, 60) dict['accumulated_altitude_gain'] = total_dz_positive dict['accumulated_altitude_loss'] = total_dz_negative dict['drift_direction'] = rad_to_cardinal(theta + pi) extended_data = kml.ExtendedData.dict(dict) if title == 'thermal': name = '%dm at %.1fm/s' % (dz, dz / dt) elif title == 'glide': name = '%.1fkm at %s:1, %dkm/h' \ % (dp / 1000.0, average_ld, round(3.6 * dp / dt)) elif title == 'dive': name = '%dm at %.1fm/s' % (-dz, dz / dt) placemark = kml.Placemark(point, extended_data, name=name, Snippet=None, styleUrl=style_url) folder.add(placemark) line_string = kml.LineString(coordinates=[coord0, coord1], altitudeMode='absolute') placemark = kml.Placemark(line_string, styleUrl=style_url) folder.add(placemark) return kmz.kmz(folder)
def make_xc_folder(self, globals): def make_row(route, i, j, percentage=False): distance = route.tps[i].coord.distance_to(route.tps[j].coord) th = '%s %s %s' \ % (route.tps[i].name, RIGHTWARDS_ARROW, route.tps[j].name) if percentage: td = '%.1fkm (%.1f%%)' \ % (distance / 1000.0, 0.1 * distance / route.distance) else: td = '%.1fkm' % (distance / 1000.0) return (th, td) def make_leg(route, i, j, name=True, arrow=False, style_url=None): coord0 = route.tps[i].coord coord1 = route.tps[j].coord line_string = kml.LineString(coordinates=[coord0, coord1], altitudeMode='clampToGround', tessellate=1) multi_geometry = kml.MultiGeometry(line_string) if name: point = kml.Point(coordinates=[coord0.halfway_to(coord1)]) multi_geometry.add(point) distance = coord0.distance_to(coord1) name = kml.name('%.1fkm' % (distance / 1000.0)) if arrow: bearing = coord1.initial_bearing_to(coord0) coordinates = [ coord1.coord_at(bearing - pi / 12.0, 400.0), coord1, coord1.coord_at(bearing + pi / 12.0, 400.0) ] line_string = kml.LineString(coordinates=coordinates, altitudeMode='clampToGround', tessellate=1) multi_geometry.add(line_string) if style_url is None: style_url = globals.stock.xc_style.url() return kml.Placemark(name, multi_geometry, styleUrl=style_url) if not self.xc: return kmz.kmz() style_url = globals.stock.radio_folder_style.url() folder = kml.Folder(name='Cross country', open=0, styleUrl=style_url) folder.add(globals.stock.invisible_none_folder) for rank, route in enumerate( sorted(self.xc.routes, key=operator.attrgetter('score'), reverse=True)): rows = [] rows.append(('League', route.league)) rows.append(('Type', route.name[0].upper() + route.name[1:])) if route.circuit: if len(route.tps) == 4: rows.append(make_row(route, 1, 2)) rows.append(make_row(route, 2, 1)) else: for i in xrange(1, len(route.tps) - 2): rows.append(make_row(route, i, i + 1, percentage=True)) rows.append(make_row(route, -2, 1, percentage=True)) else: for i in xrange(0, len(route.tps) - 1): rows.append(make_row(route, i, i + 1)) rows.append(('Distance', '%.1fkm' % route.distance)) rows.append(('Multiplier', '%s %.2f points/km' % (MULTIPLICATION_SIGN, route.multiplier))) rows.append(('Score', '<b>%.2f points</b>' % route.score)) speed = 3600.0 * route.distance \ / (route.tps[-1].coord.dt - route.tps[0].coord.dt).seconds rows.append(('Average speed', '%.1fkm/h' % speed)) if route.circuit: rows.append(make_row(route, -1, 0)) table = make_table(rows) name = '%.1fkm %s (%.2f points)' \ % (route.distance, route.name, route.score) visibility = 1 if rank == 0 else 0 style_url = globals.stock.check_hide_children_style.url() route_folder = kml.Folder(name=name, description=kml.CDATA(table), Snippet=None, styleUrl=style_url, visibility=visibility) for tp in route.tps: coord = self.track.coord_at(tp.coord.dt) point = kml.Point(coordinates=[coord], altitudeMode=self.altitude_mode, extrude=1) style_url = globals.stock.xc_style.url() placemark = kml.Placemark(point, name=tp.name, styleUrl=style_url) route_folder.add(placemark) if route.circuit: route_folder.add(make_leg(route, 0, 1, name=None, arrow=True)) if len(route.tps) == 4: route_folder.add(make_leg(route, 1, 2)) else: for i in xrange(1, len(route.tps) - 2): route_folder.add(make_leg(route, i, i + 1, arrow=True)) style_url = globals.stock.xc_style2.url() route_folder.add( make_leg(route, -2, 1, style_url=style_url)) route_folder.add(make_leg(route, -2, -1, name=None, arrow=True)) else: for i in xrange(0, len(route.tps) - 1): route_folder.add(make_leg(route, i, i + 1, arrow=True)) folder.add(route_folder) return kmz.kmz(folder)
def __init__(self): self.kmz = kmz.kmz() # self.icon_scales = [sqrt(x) for x in [0.6, 0.5, 0.4, 0.3]] self.icons = [kml.Icon.palette(4, i) for i in [25, 25, 24, 24]] self.label_scales = [sqrt(x) for x in [0.6, 0.5, 0.4, 0.3]] # list_style = kml.ListStyle(listItemType='radioFolder') self.radio_folder_style = kml.Style(list_style) self.kmz.add_roots(self.radio_folder_style) # list_style = kml.ListStyle(listItemType='checkHideChildren') self.check_hide_children_style = kml.Style(list_style) self.kmz.add_roots(self.check_hide_children_style) # bgcolors = '#ffcccc #ffdddd'.split() rows = [ ['Altitude gain', '$[altitude_change]m'], ['Average climb', '$[average_climb]m/s'], ['Maximum climb', '$[maximum_climb]m/s'], ['Peak climb', '$[peak_climb]m/s'], ['Efficiency', '$[efficiency]%'], ['Start altitude', '$[start_altitude]m'], ['Finish altitude', '$[finish_altitude]m'], ['Start time', '$[start_time]'], ['Finish time', '$[finish_time]'], ['Duration', '$[duration]'], ['Accumulated altitude gain', '$[accumulated_altitude_gain]m'], ['Accumulated altitude loss', '$[accumulated_altitude_loss]m'], ['Drift', '$[average_speed]km/h $[drift_direction]'], ] self.thermal_style = self.make_analysis_style('cc3333ff', bgcolors, rows) self.kmz.add_roots(self.thermal_style) bgcolors = '#ccccff #ddddff'.split() rows = [ ['Altitude change', '$[altitude_change]m'], ['Average descent', '$[average_climb]m/s'], ['Maximum descent', '$[maximum_descent]m/s'], ['Peak descent', '$[peak_descent]m/s'], ['Start altitude', '$[start_altitude]m'], ['Finish altitude', '$[finish_altitude]m'], ['Start time', '$[start_time]'], ['Finish time', '$[finish_time]'], ['Duration', '$[duration]'], ['Accumulated altitude gain', '$[accumulated_altitude_gain]m'], ['Accumulated altitude loss', '$[accumulated_altitude_loss]m'], ] self.dive_style = self.make_analysis_style('ccff3333', bgcolors, rows) bgcolors = '#ccffcc #ddffdd'.split() rows = [ ['Altitude change', '$[altitude_change]m'], ['Average descent', '$[average_climb]m/s'], ['Distance', '$[distance]km'], ['Average glide ratio', '$[average_ld]:1'], ['Average speed', '$[average_speed]km/h'], ['Start altitude', '$[start_altitude]m'], ['Finish altitude', '$[finish_altitude]m'], ['Start time', '$[start_time]'], ['Finish time', '$[finish_time]'], ['Duration', '$[duration]'], ['Accumulated altitude gain', '$[accumulated_altitude_gain]m'], ['Accumulated altitude loss', '$[accumulated_altitude_loss]m'], ] self.kmz.add_roots(self.dive_style) self.glide_style = self.make_analysis_style('cc33ff33', bgcolors, rows) self.kmz.add_roots(self.glide_style) # self.time_mark_styles = [] for i in xrange(0, len(self.icons)): icon_style = kml.IconStyle(self.icons[i], scale=self.icon_scales[i]) label_style = kml.LabelStyle(color='cc33ffff', scale=self.label_scales[i]) self.time_mark_styles.append(kml.Style(icon_style, label_style)) self.kmz.add_roots(*self.time_mark_styles) # balloon_style = kml.BalloonStyle(text=kml.CDATA('$[description]')) icon_style = kml.IconStyle(kml.Icon.palette(4, 46), scale=self.icon_scales[0]) label_style = kml.LabelStyle(scale=self.label_scales[0]) self.photo_style = kml.Style(balloon_style, icon_style, label_style) self.kmz.add_roots(self.photo_style) # text = kml.text(kml.CDATA('<h3>$[name]</h3>$[description]')) balloon_style = kml.BalloonStyle(text) icon_style = kml.IconStyle(self.icons[0], color='ccff33ff', scale=self.icon_scales[0]) label_style = kml.LabelStyle(color='ccff33ff', scale=self.label_scales[0]) line_style = kml.LineStyle(color='ccff33ff', width=2) self.xc_style = kml.Style(balloon_style, icon_style, label_style, line_style) self.kmz.add_roots(self.xc_style) # text = kml.text(kml.CDATA('<h3>$[name]</h3>$[description]')) balloon_style = kml.BalloonStyle(text) icon_style = kml.IconStyle(self.icons[0], color='ccff33ff', scale=self.icon_scales[0]) label_style = kml.LabelStyle(color='ccff33ff', scale=self.label_scales[0]) line_style = kml.LineStyle(color='ccff33ff') self.xc_style2 = kml.Style(balloon_style, icon_style, label_style, line_style) self.kmz.add_roots(self.xc_style2) # self.pixel_url = os.path.join('images', 'pixel.png') pixel = open(os.path.join(BASE_DIR, self.pixel_url)).read() self.kmz.add_files({self.pixel_url: pixel}) # self.visible_none_folder = self.make_none_folder(1) self.invisible_none_folder = self.make_none_folder(0)
def make_xc_folder(self, globals): def make_row(route, i, j, percentage=False): distance = route.tps[i].coord.distance_to(route.tps[j].coord) th = '%s %s %s' \ % (route.tps[i].name, RIGHTWARDS_ARROW, route.tps[j].name) if percentage: td = '%.1fkm (%.1f%%)' \ % (distance / 1000.0, 0.1 * distance / route.distance) else: td = '%.1fkm' % (distance / 1000.0) return (th, td) def make_leg(route, i, j, name=True, arrow=False, style_url=None): coord0 = route.tps[i].coord coord1 = route.tps[j].coord line_string = kml.LineString(coordinates=[coord0, coord1], altitudeMode='clampToGround', tessellate=1) multi_geometry = kml.MultiGeometry(line_string) if name: point = kml.Point(coordinates=[coord0.halfway_to(coord1)]) multi_geometry.add(point) distance = coord0.distance_to(coord1) name = kml.name('%.1fkm' % (distance / 1000.0)) if arrow: bearing = coord1.initial_bearing_to(coord0) coordinates = [coord1.coord_at(bearing - pi / 12.0, 400.0), coord1, coord1.coord_at(bearing + pi / 12.0, 400.0)] line_string = kml.LineString(coordinates=coordinates, altitudeMode='clampToGround', tessellate=1) multi_geometry.add(line_string) if style_url is None: style_url = globals.stock.xc_style.url() return kml.Placemark(name, multi_geometry, styleUrl=style_url) if not self.xc: return kmz.kmz() style_url = globals.stock.radio_folder_style.url() folder = kml.Folder(name='Cross country', open=0, styleUrl=style_url) folder.add(globals.stock.invisible_none_folder) for rank, route in enumerate(sorted(self.xc.routes, key=operator.attrgetter('score'), reverse=True)): rows = [] rows.append(('League', route.league)) rows.append(('Type', route.name[0].upper() + route.name[1:])) if route.circuit: if len(route.tps) == 4: rows.append(make_row(route, 1, 2)) rows.append(make_row(route, 2, 1)) else: for i in xrange(1, len(route.tps) - 2): rows.append(make_row(route, i, i + 1, percentage=True)) rows.append(make_row(route, -2, 1, percentage=True)) else: for i in xrange(0, len(route.tps) - 1): rows.append(make_row(route, i, i + 1)) rows.append(('Distance', '%.1fkm' % route.distance)) rows.append(('Multiplier', '%s %.2f points/km' % (MULTIPLICATION_SIGN, route.multiplier))) rows.append(('Score', '<b>%.2f points</b>' % route.score)) speed = 3600.0 * route.distance \ / (route.tps[-1].coord.dt - route.tps[0].coord.dt).seconds rows.append(('Average speed', '%.1fkm/h' % speed)) if route.circuit: rows.append(make_row(route, -1, 0)) table = make_table(rows) name = '%.1fkm %s (%.2f points)' \ % (route.distance, route.name, route.score) visibility = 1 if rank == 0 else 0 style_url = globals.stock.check_hide_children_style.url() route_folder = kml.Folder(name=name, description=kml.CDATA(table), Snippet=None, styleUrl=style_url, visibility=visibility) for tp in route.tps: coord = self.track.coord_at(tp.coord.dt) point = kml.Point(coordinates=[coord], altitudeMode=self.altitude_mode, extrude=1) style_url = globals.stock.xc_style.url() placemark = kml.Placemark(point, name=tp.name, styleUrl=style_url) route_folder.add(placemark) if route.circuit: route_folder.add(make_leg(route, 0, 1, name=None, arrow=True)) if len(route.tps) == 4: route_folder.add(make_leg(route, 1, 2)) else: for i in xrange(1, len(route.tps) - 2): route_folder.add(make_leg(route, i, i + 1, arrow=True)) style_url = globals.stock.xc_style2.url() route_folder.add(make_leg(route, -2, 1, style_url=style_url)) route_folder.add(make_leg(route, -2, -1, name=None, arrow=True)) else: for i in xrange(0, len(route.tps) - 1): route_folder.add(make_leg(route, i, i + 1, arrow=True)) folder.add(route_folder) return kmz.kmz(folder)
def make_task_folder(globals, task): name = task.name or 'Task' rows = [] tp0 = None total = 0.0 count = -1 for sl in util.runs([tp.name for tp in task.tps]): if tp0 is None: tp0 = task.tps[sl.start] continue tp1 = task.tps[sl.stop - 1] distance = tp0.coord.distance_to(tp1.coord) th = '%s %s %s' % (tp0.name, RIGHTWARDS_ARROW, tp1.name) td = '%.1fkm' % (distance / 1000.0) rows.append((th, td)) total += distance count += 1 tp0 = tp1 rows.append(('Total', '%.1fkm' % (total / 1000.0))) table = make_table(rows) snippet = '%.1fkm via %d turnpoints' % (total / 1000.0, count) style_url = globals.stock.check_hide_children_style.url() folder = kml.Folder(name=name, description=kml.CDATA(table), Snippet=snippet, styleUrl=style_url) style_url = globals.stock.xc_style.url() done = set() for tp in task.tps: key = tp.name if key in done: continue else: done.add(key) point = kml.Point(coordinates=[tp.coord]) folder.add(kml.Placemark(point, name=tp.name, styleUrl=style_url)) done = set() for tp in task.tps: if tp.radius == 0: continue key = (tp.name, tp.radius) if key in done: continue else: done.add(key) coordinates = kml.coordinates.circle(tp.coord, tp.radius) line_string = kml.LineString(coordinates, tessellate=1) folder.add(kml.Placemark(line_string, styleUrl=style_url)) tp0 = None for sl in util.runs([tp.name for tp in task.tps]): if tp0 is None: tp0 = task.tps[sl.start] continue tp1 = task.tps[sl.stop - 1] coord0 = tp0.coord.coord_at(tp0.coord.initial_bearing_to(tp1.coord), tp0.radius) theta = tp1.coord.initial_bearing_to(tp0.coord) coord1 = tp1.coord.coord_at(theta, tp1.radius) line_string1 = kml.LineString(coordinates=[coord0, coord1], tessellate=1) coords = [ coord1.coord_at(theta - pi / 12.0, 400.0), coord1, coord1.coord_at(theta + pi / 12.0, 400.0) ] line_string2 = kml.LineString(coordinates=coords, tessellate=1) multi_geometry = kml.MultiGeometry(line_string1, line_string2) folder.add(kml.Placemark(multi_geometry, styleUrl=style_url)) tp0 = tp1 return kmz.kmz(folder)
def __init__(self): self.kmz = kmz.kmz() # self.icon_scales = [sqrt(x) for x in [0.6, 0.5, 0.4, 0.3]] self.icons = [kml.Icon.palette(4, i) for i in [25, 25, 24, 24]] self.label_scales = [sqrt(x) for x in [0.6, 0.5, 0.4, 0.3]] # list_style = kml.ListStyle(listItemType='radioFolder') self.radio_folder_style = kml.Style(list_style) self.kmz.add_roots(self.radio_folder_style) # list_style = kml.ListStyle(listItemType='checkHideChildren') self.check_hide_children_style = kml.Style(list_style) self.kmz.add_roots(self.check_hide_children_style) # bgcolors = '#ffcccc #ffdddd'.split() rows = [ ['Altitude gain', '$[altitude_change]m'], ['Average climb', '$[average_climb]m/s'], ['Maximum climb', '$[maximum_climb]m/s'], ['Peak climb', '$[peak_climb]m/s'], ['Efficiency', '$[efficiency]%'], ['Start altitude', '$[start_altitude]m'], ['Finish altitude', '$[finish_altitude]m'], ['Start time', '$[start_time]'], ['Finish time', '$[finish_time]'], ['Duration', '$[duration]'], ['Accumulated altitude gain', '$[accumulated_altitude_gain]m'], ['Accumulated altitude loss', '$[accumulated_altitude_loss]m'], ['Drift', '$[average_speed]km/h $[drift_direction]'], ] self.thermal_style = self.make_analysis_style('cc3333ff', bgcolors, rows) self.kmz.add_roots(self.thermal_style) bgcolors = '#ccccff #ddddff'.split() rows = [ ['Altitude change', '$[altitude_change]m'], ['Average descent', '$[average_climb]m/s'], ['Maximum descent', '$[maximum_descent]m/s'], ['Peak descent', '$[peak_descent]m/s'], ['Start altitude', '$[start_altitude]m'], ['Finish altitude', '$[finish_altitude]m'], ['Start time', '$[start_time]'], ['Finish time', '$[finish_time]'], ['Duration', '$[duration]'], ['Accumulated altitude gain', '$[accumulated_altitude_gain]m'], ['Accumulated altitude loss', '$[accumulated_altitude_loss]m'], ] self.dive_style = self.make_analysis_style('ccff3333', bgcolors, rows) bgcolors = '#ccffcc #ddffdd'.split() rows = [ ['Altitude change', '$[altitude_change]m'], ['Average descent', '$[average_climb]m/s'], ['Distance', '$[distance]km'], ['Average glide ratio', '$[average_ld]:1'], ['Average speed', '$[average_speed]km/h'], ['Start altitude', '$[start_altitude]m'], ['Finish altitude', '$[finish_altitude]m'], ['Start time', '$[start_time]'], ['Finish time', '$[finish_time]'], ['Duration', '$[duration]'], ['Accumulated altitude gain', '$[accumulated_altitude_gain]m'], ['Accumulated altitude loss', '$[accumulated_altitude_loss]m'], ] self.kmz.add_roots(self.dive_style) self.glide_style = self.make_analysis_style('cc33ff33', bgcolors, rows) self.kmz.add_roots(self.glide_style) # self.time_mark_styles = [] for i in xrange(0, len(self.icons)): icon_style = kml.IconStyle(self.icons[i], scale=self.icon_scales[i]) label_style = kml.LabelStyle(color='cc33ffff', scale=self.label_scales[i]) self.time_mark_styles.append(kml.Style(icon_style, label_style)) self.kmz.add_roots(*self.time_mark_styles) # balloon_style = kml.BalloonStyle(text=kml.CDATA('$[description]')) icon_style = kml.IconStyle(kml.Icon.palette(4, 46), scale=self.icon_scales[0]) label_style = kml.LabelStyle(scale=self.label_scales[0]) self.photo_style = kml.Style(balloon_style, icon_style, label_style) self.kmz.add_roots(self.photo_style) # text = kml.text(kml.CDATA('<h3>$[name]</h3>$[description]')) balloon_style = kml.BalloonStyle(text) icon_style = kml.IconStyle(self.icons[0], color='ccff33ff', scale=self.icon_scales[0]) label_style = kml.LabelStyle(color='ccff33ff', scale=self.label_scales[0]) line_style = kml.LineStyle(color='ccff33ff', width=2) self.xc_style = kml.Style(balloon_style, icon_style, label_style, line_style) self.kmz.add_roots(self.xc_style) # text = kml.text(kml.CDATA('<h3>$[name]</h3>$[description]')) balloon_style = kml.BalloonStyle(text) icon_style = kml.IconStyle(self.icons[0], color='ccff33ff', scale=self.icon_scales[0]) label_style = kml.LabelStyle(color='ccff33ff', scale=self.label_scales[0]) line_style = kml.LineStyle(color='ccff33ff') self.xc_style2 = kml.Style(balloon_style, icon_style, label_style, line_style) self.kmz.add_roots(self.xc_style2) # self.pixel_url = os.path.join('images', 'pixel.png') pixel = open(os.path.join(BASE_DIR, self.pixel_url)).read() self.kmz.add_files({self.pixel_url: pixel}) # self.visible_none_folder = self.make_none_folder(1) self.invisible_none_folder = self.make_none_folder(0) # animation_icon_url = os.path.join('images', 'paraglider.png') self.animation_icon = kml.Icon(href=animation_icon_url) animation_icon = open(os.path.join(BASE_DIR, animation_icon_url)).read() files = {animation_icon_url: animation_icon} self.kmz.add_files(files)
def make_task_folder(globals, task): name = task.name or 'Task' rows = [] tp0 = None total = 0.0 count = -1 for sl in util.runs([tp.name for tp in task.tps]): if tp0 is None: tp0 = task.tps[sl.start] continue tp1 = task.tps[sl.stop - 1] distance = tp0.coord.distance_to(tp1.coord) th = '%s %s %s' % (tp0.name, RIGHTWARDS_ARROW, tp1.name) td = '%.1fkm' % (distance / 1000.0) rows.append((th, td)) total += distance count += 1 tp0 = tp1 rows.append(('Total', '%.1fkm' % (total / 1000.0))) table = make_table(rows) snippet = '%.1fkm via %d turnpoints' % (total / 1000.0, count) style_url = globals.stock.check_hide_children_style.url() folder = kml.Folder(name=name, description=kml.CDATA(table), Snippet=snippet, styleUrl=style_url) style_url = globals.stock.xc_style.url() done = set() for tp in task.tps: key = tp.name if key in done: continue else: done.add(key) point = kml.Point(coordinates=[tp.coord]) folder.add(kml.Placemark(point, name=tp.name, styleUrl=style_url)) done = set() for tp in task.tps: key = (tp.name, tp.radius) if key in done: continue else: done.add(key) coordinates = kml.coordinates.circle(tp.coord, tp.radius) line_string = kml.LineString(coordinates, tessellate=1) folder.add(kml.Placemark(line_string, styleUrl=style_url)) tp0 = None for sl in util.runs([tp.name for tp in task.tps]): if tp0 is None: tp0 = task.tps[sl.start] continue tp1 = task.tps[sl.stop - 1] coord0 = tp0.coord.coord_at(tp0.coord.initial_bearing_to(tp1.coord), tp0.radius) theta = tp1.coord.initial_bearing_to(tp0.coord) coord1 = tp1.coord.coord_at(theta, tp1.radius) line_string1 = kml.LineString(coordinates=[coord0, coord1], tessellate=1) coords = [coord1.coord_at(theta - pi / 12.0, 400.0), coord1, coord1.coord_at(theta + pi / 12.0, 400.0)] line_string2 = kml.LineString(coordinates=coords, tessellate=1) multi_geometry = kml.MultiGeometry(line_string1, line_string2) folder.add(kml.Placemark(multi_geometry, styleUrl=style_url)) tp0 = tp1 return kmz.kmz(folder)