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_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 analyse(self, dt): n = len(self.coords) period = (self.coords[-1].dt - self.coords[0].dt).seconds / n if dt < 2 * period: dt = 2 * period self.bounds = util.BoundsSet() self.bounds.ele = util.Bounds([coord.ele for coord in self.coords]) self.bounds.time = util.Bounds((self.coords[0].dt, self.coords[-1].dt)) self.bounds.t = util.Bounds((self.t[0], self.t[-1])) if hasattr(self, 'tas'): self.bounds.tas = util.Bounds(self.tas) if self.bounds.ele.min != 0 or self.bounds.ele.max != 0: self.elevation_data = True else: self.elevation_data = False self.s = [0.0] for i in xrange(1, n): self.s.append(self.s[i - 1] + self.coords[i - 1].distance_to(self.coords[i])) self.ele = [(self.coords[i - 1].ele + self.coords[i].ele) / 2.0 for i in xrange(1, n)] self.total_dz_positive = self.max_dz_positive = 0 min_ele = self.coords[0].ele for i in xrange(1, n): dz = self.coords[i].ele - self.coords[i - 1].ele if dz > 0: self.total_dz_positive += dz if self.coords[i].ele < min_ele: min_ele = self.coords[i].ele elif self.coords[i].ele - min_ele > self.max_dz_positive: self.max_dz_positive = self.coords[i].ele - min_ele self.speed, self.climb, self.tec, self.progress = [], [], [], [] i0 = i1 = 0 for i in xrange(1, n): t0 = (self.t[i - 1] + self.t[i]) / 2 - dt / 2 while self.t[i0] <= t0: i0 += 1 if i0 == 0: coord0 = self.coords[0] s0 = self.s[0] else: delta0 = float(t0 - self.t[i0 - 1]) \ / (self.t[i0] - self.t[i0 - 1]) coord0 = self.coords[i0 - 1].interpolate( self.coords[i0], delta0) s0 = (1.0 - delta0) * self.s[i0 - 1] + delta0 * self.s[i0] t1 = t0 + dt while i1 < n and self.t[i1] < t1: i1 += 1 if i1 == n: coord1 = self.coords[n - 1] s1 = self.s[n - 1] else: delta1 = float(t1 - self.t[i1 - 1]) \ / (self.t[i1] - self.t[i1 - 1]) coord1 = self.coords[i1 - 1].interpolate( self.coords[i1], delta1) s1 = (1.0 - delta1) * self.s[i1 - 1] + delta1 * self.s[i1] ds = s1 - s0 ds2 = s1 * s1 - s0 * s0 dz = coord1.ele - coord0.ele dp = coord0.distance_to(coord1) if ds == 0.0: progress = 0.0 elif dp > ds: progress = 1.0 else: progress = dp / ds self.speed.append(3.6 * ds / dt) self.climb.append(dz / dt) self.tec.append(dz / dt + ds2 / (2 * 9.80665)) self.progress.append(progress) self.bounds.speed = util.Bounds(self.speed) self.bounds.climb = util.Bounds(self.climb) self.bounds.tec = util.Bounds(self.tec) state = [UNKNOWN] * (n - 1) glide = (self.progress[i] >= 0.9 for i in xrange(0, n - 1)) for sl in util.condense(util.runs_where(glide), self.t, 60): state[sl] = [GLIDE] * (sl.stop - sl.start) dive = (self.progress[i] < 0.9 and self.climb[i] < 1.0 for i in xrange(0, n - 1)) for sl in util.condense(util.runs_where(dive), self.t, 30): if self.coords[sl.stop].ele - self.coords[sl.start].ele < -100: state[sl] = [DIVE] * (sl.stop - sl.start) thermal = ((self.progress[i] < 0.9 and self.climb[i] > 0.0) or (self.speed[i] < 10.0 and self.climb[i] > 0.0) or (self.climb[i] > 1.0) for i in xrange(0, n - 1)) for sl in util.condense(util.runs_where(thermal), self.t, 60): state[sl] = [THERMAL] * (sl.stop - sl.start) self.thermals, self.glides, self.dives = [], [], [] for sl in util.runs(state): dt = self.t[sl.stop] - self.t[sl.start] dz = self.coords[sl.stop].ele - self.coords[sl.start].ele if state[sl.start] == THERMAL: if dt >= 60 and dz > 50: self.thermals.append(sl) elif state[sl.start] == DIVE: if dt >= 30 and dz / dt < -2: self.dives.append(sl) elif state[sl.start] == GLIDE: if dt >= 120: self.glides.append(sl)
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)
def analyse(self, dt): n = len(self.coords) period = (self.coords[-1].dt - self.coords[0].dt).seconds / n if dt < 2 * period: dt = 2 * period self.bounds = util.BoundsSet() self.bounds.ele = util.Bounds([coord.ele for coord in self.coords]) self.bounds.time = util.Bounds((self.coords[0].dt, self.coords[-1].dt)) self.bounds.t = util.Bounds((self.t[0], self.t[-1])) if hasattr(self, 'tas'): self.bounds.tas = util.Bounds(self.tas) if self.bounds.ele.min != 0 or self.bounds.ele.max != 0: self.elevation_data = True else: self.elevation_data = False self.s = [0.0] for i in xrange(1, n): self.s.append(self.s[i - 1] + self.coords[i - 1].distance_to(self.coords[i])) self.ele = [(self.coords[i - 1].ele + self.coords[i].ele) / 2.0 for i in xrange(1, n)] self.total_dz_positive = self.max_dz_positive = 0 min_ele = self.coords[0].ele for i in xrange(1, n): dz = self.coords[i].ele - self.coords[i - 1].ele if dz > 0: self.total_dz_positive += dz if self.coords[i].ele < min_ele: min_ele = self.coords[i].ele elif self.coords[i].ele - min_ele > self.max_dz_positive: self.max_dz_positive = self.coords[i].ele - min_ele self.speed, self.climb, self.tec, self.progress = [], [], [], [] i0 = i1 = 0 for i in xrange(1, n): t0 = (self.t[i - 1] + self.t[i]) / 2 - dt / 2 while self.t[i0] <= t0: i0 += 1 if i0 == 0: coord0 = self.coords[0] s0 = self.s[0] else: delta0 = float(t0 - self.t[i0 - 1]) \ / (self.t[i0] - self.t[i0 - 1]) coord0 = self.coords[i0 - 1].interpolate(self.coords[i0], delta0) s0 = (1.0 - delta0) * self.s[i0 - 1] + delta0 * self.s[i0] t1 = t0 + dt while i1 < n and self.t[i1] < t1: i1 += 1 if i1 == n: coord1 = self.coords[n - 1] s1 = self.s[n - 1] else: delta1 = float(t1 - self.t[i1 - 1]) \ / (self.t[i1] - self.t[i1 - 1]) coord1 = self.coords[i1 - 1].interpolate(self.coords[i1], delta1) s1 = (1.0 - delta1) * self.s[i1 - 1] + delta1 * self.s[i1] ds = s1 - s0 ds2 = s1 * s1 - s0 * s0 dz = coord1.ele - coord0.ele dp = coord0.distance_to(coord1) if ds == 0.0: progress = 0.0 elif dp > ds: progress = 1.0 else: progress = dp / ds self.speed.append(3.6 * ds / dt) self.climb.append(dz / dt) self.tec.append(dz / dt + ds2 / (2 * 9.80665)) self.progress.append(progress) self.bounds.speed = util.Bounds(self.speed) self.bounds.climb = util.Bounds(self.climb) self.bounds.tec = util.Bounds(self.tec) state = [UNKNOWN] * (n - 1) glide = (self.progress[i] >= 0.9 for i in xrange(0, n - 1)) for sl in util.condense(util.runs_where(glide), self.t, 60): state[sl] = [GLIDE] * (sl.stop - sl.start) dive = (self.progress[i] < 0.9 and self.climb[i] < 1.0 for i in xrange(0, n - 1)) for sl in util.condense(util.runs_where(dive), self.t, 30): if self.coords[sl.stop].ele - self.coords[sl.start].ele < -100: state[sl] = [DIVE] * (sl.stop - sl.start) thermal = ((self.progress[i] < 0.9 and self.climb[i] > 0.0) or (self.speed[i] < 10.0 and self.climb[i] > 0.0) or (self.climb[i] > 1.0) for i in xrange(0, n - 1)) for sl in util.condense(util.runs_where(thermal), self.t, 60): state[sl] = [THERMAL] * (sl.stop - sl.start) self.thermals, self.glides, self.dives = [], [], [] for sl in util.runs(state): dt = self.t[sl.stop] - self.t[sl.start] dz = self.coords[sl.stop].ele - self.coords[sl.start].ele if state[sl.start] == THERMAL: if dt >= 60 and dz > 50: self.thermals.append(sl) elif state[sl.start] == DIVE: if dt >= 30 and dz / dt < -2: self.dives.append(sl) elif state[sl.start] == GLIDE: if dt >= 120: self.glides.append(sl)