def _draw_current_map(self): left = self.pos[0] bottom = self.pos[1] self.canvas.clear() heat_width_step = sp(self.HEAT_MAP_WIDTH_STEP) path_count = len(self._scaled_paths.keys()) heat_width = sp(self.heat_width_scale * self.height) + ((path_count - 1) * heat_width_step) with self.canvas: Color(*self.track_color) Line(points=self._scaled_map_points, width=sp(self.track_width_scale * self.height), closed=True, cap='round', joint='round') color_gradient = HeatColorGradient() # draw all of the traces for key, path_points in self._scaled_paths.iteritems(): heat_path = self._heat_map_values.get(key) if heat_path: # draw heat map point_count = len(path_points) heat_min = self.heat_min heat_range = self.heat_max - heat_min value_index = 0 current_heat_pct = 0 i = 0 line_points = [] try: line_points.extend([path_points[i], path_points[i + 1]]) current_heat_pct = int(((heat_path[value_index] - heat_min) / heat_range) * 100.0) while i < point_count - 2: heat_value = heat_path[value_index] heat_pct = int(((heat_value - heat_min) / heat_range) * 100.0) if heat_pct != current_heat_pct: heat_color = color_gradient.get_color_value(heat_pct / 100.0) Color(*heat_color) Line(points=line_points, width=heat_width, closed=False, joint='miter', cap='round') line_points = [path_points[i - 2], path_points[i - 1]] current_heat_pct = heat_pct line_points.extend([path_points[i], path_points[i + 1]]) value_index += 1 i += 2 heat_width -= heat_width_step except IndexError: # if the number of heat values mismatch the heat map points, terminate early pass else: # draw regular map trace Color(*self._paths[key].color) Line(points=path_points, width=sp(self.path_width_scale * self.height), closed=True, cap='square', joint='miter') # draw the markers marker_size = (self.marker_width_scale * self.height) * self.marker_scale for key, marker_point in self._marker_points.iteritems(): scaled_point = self._scale_point(marker_point, self.height, left, bottom) Color(*marker_point.color) self._marker_locations[key] = Line(circle=(scaled_point.x, scaled_point.y, marker_size), width=marker_size, closed=True)
class BrakeCorner(BoxLayout): Builder.load_string(BRAKE_CORNER_KV) zones = NumericProperty() minval = NumericProperty() maxval = NumericProperty() bar_gauge_orientation = StringProperty() LABEL_COLOR = [0.5, 0.5, 0.5, 1.0] def __init__(self, **kwargs): super(BrakeCorner, self).__init__(**kwargs) self.brake_value_widgets = [] self.heat_gradient = HeatColorGradient() def on_zones(self, instance, value): self.ids.brake.zones = value top_values = self.ids.brake_values_top bottom_values = self.ids.brake_values_bottom top_values.clear_widgets() bottom_values.clear_widgets() del(self.brake_value_widgets[:]) for i in range(0, value): if value <= 2: # if zones are 2 or less zones go above and below current_grid = top_values if i % 2 == 0 else bottom_values else: # if zones > 2 then go top to bottom current_grid = top_values if i < 2 else bottom_values gauge = BarGraphGauge(orientation=self.bar_gauge_orientation, label_color=BrakeCorner.LABEL_COLOR) gauge.minval = self.minval gauge.maxval = self.maxval current_grid.add_widget(gauge) self.brake_value_widgets.append(gauge) size_hint_y = 0.5 if value <= 2 else 1.0 top_values.size_hint_y = size_hint_y bottom_values.size_hint_y = size_hint_y def set_value(self, zone, value): value = min(self.maxval, value) value = max(self.minval, value) scaled = value / self.maxval if self.maxval > 0 else 0 self.ids.brake.set_value(zone, scaled) try: value_widget = self.brake_value_widgets[zone] value_widget.value = value value_widget.color = self.heat_gradient.get_color_value(scaled) except IndexError: pass def on_minval(self, instance, value): for gauge in self.brake_value_widgets: gauge.minval = value def on_maxval(self, instance, value): for gauge in self.brake_value_widgets: gauge.maxval = value
class BrakeCorner(BoxLayout): Builder.load_string(BRAKE_CORNER_KV) zones = NumericProperty() minval = NumericProperty() maxval = NumericProperty() bar_gauge_orientation = StringProperty() LABEL_COLOR = [0.5, 0.5, 0.5, 1.0] def __init__(self, **kwargs): super(BrakeCorner, self).__init__(**kwargs) self.brake_value_widgets = [] self.heat_gradient = HeatColorGradient() def on_zones(self, instance, value): self.ids.brake.zones = value top_values = self.ids.brake_values_top bottom_values = self.ids.brake_values_bottom top_values.clear_widgets() bottom_values.clear_widgets() del (self.brake_value_widgets[:]) for i in range(0, value): if value <= 2: # if zones are 2 or less zones go above and below current_grid = top_values if i % 2 == 0 else bottom_values else: # if zones > 2 then go top to bottom current_grid = top_values if i < 2 else bottom_values gauge = BarGraphGauge(orientation=self.bar_gauge_orientation, label_color=BrakeCorner.LABEL_COLOR) gauge.minval = self.minval gauge.maxval = self.maxval current_grid.add_widget(gauge) self.brake_value_widgets.append(gauge) size_hint_y = 0.5 if value <= 2 else 1.0 top_values.size_hint_y = size_hint_y bottom_values.size_hint_y = size_hint_y def set_value(self, zone, value): value = min(self.maxval, value) value = max(self.minval, value) scaled = value / self.maxval if self.maxval > 0 else 0 self.ids.brake.set_value(zone, scaled) try: value_widget = self.brake_value_widgets[zone] value_widget.value = value value_widget.color = self.heat_gradient.get_color_value(scaled) except IndexError: pass def on_minval(self, instance, value): for gauge in self.brake_value_widgets: gauge.minval = value def on_maxval(self, instance, value): for gauge in self.brake_value_widgets: gauge.maxval = value
def _update_gradient(self, *args): ''' Actually draws the gradient ''' color_gradient = HeatColorGradient() if self.color is None else SimpleColorGradient(max_color=self.color) self.canvas.clear() step = GradientBox.GRADIENT_STEP pct = step with self.canvas: while pct < 1.0: color = color_gradient.get_color_value(pct) Color(*color) slice_width = self.width * step pos = (self.x + (self.width * pct), self.y) size = (slice_width, self.height) Rectangle(pos=pos, size=size) pct += step
class BrakeHeatGauge(AnchorLayout): Builder.load_string(HEAT_GAUGE_KV) zones = NumericProperty(None) CENTER_SIZE_PCT = 0.5 ROTOR_IMAGE = CoreImage('autosportlabs/racecapture/widgets/heat/rotor.png') TIRE_IMAGE = CoreImage('autosportlabs/racecapture/widgets/heat/tire.png') def __init__(self, **kwargs): super(BrakeHeatGauge, self).__init__(**kwargs) self.heat_gradient = HeatColorGradient() self.colors = [] self.values = [] self._init_view() self.bind(pos=self._update_gauge) self.bind(size=self._update_gauge) self.bind(zones=self._update_gauge) def on_zones(self, instance, value): self._sync_zones() def _init_view(self): self._sync_zones() def _sync_zones(self): zones = self.zones if zones is None: return values = self.values values.extend([0] * (zones - len(values))) colors = self.colors colors.extend([Color()] * (zones - len(colors))) self._update_gauge() def set_value(self, zone, value): try: rgba = self.heat_gradient.get_color_value(value) self.colors[zone].rgba = rgba self.values[zone] = value except IndexError: pass def _update_gauge(self, *args): self.canvas.clear() zones = self.zones if zones is None or zones == 0: return x = self.pos[0] y = self.pos[1] width = self.size[0] height = self.size[1] min_size = min(width, height) center_size = min_size * BrakeHeatGauge.CENTER_SIZE_PCT rw = ((min_size - center_size) / float(zones)) center_x = x + (width / 2) center_y = y + (height / 2) index = zones with self.canvas: for i in range(0, zones): color = self.heat_gradient.get_color_value(self.values[index - 1]) c = Color(rgba=color) self.colors[index - 1] = c segment_size = (index * (rw)) + center_size c_x = center_x - segment_size / 2 c_y = center_y - segment_size / 2 Ellipse(pos=(c_x, c_y), size=(segment_size, segment_size)) index -= 1 Color(1.0, 1.0, 1.0, 1.0) r_x = center_x - (center_size / 2) r_y = center_y - (center_size / 2) Rectangle(texture=BrakeHeatGauge.ROTOR_IMAGE.texture, pos=(r_x, r_y), size=(center_size, center_size)) def on_values(self, instance, value): pass
class TireHeatGauge(AnchorLayout): Builder.load_string(HEAT_GAUGE_KV) zones = NumericProperty(None) direction = StringProperty('left-right') def __init__(self, **kwargs): super(TireHeatGauge, self).__init__(**kwargs) self.heat_gradient = HeatColorGradient() self.colors = [] self.values = [] self._init_view() self.bind(pos=self._update_gauge) self.bind(size=self._update_gauge) self.bind(zones=self._update_gauge) self.bind(direction=self._update_gauge) def on_zones(self, instance, value): self._sync_zones() def _init_view(self): self._sync_zones() def _sync_zones(self): zones = self.zones if zones is None: return values = self.values values.extend([0] * (zones - len(values))) colors = self.colors colors.extend([Color()] * (zones - len(colors))) self._update_gauge() def set_value(self, zone, value): try: rgba = self.heat_gradient.get_color_value(value) self.colors[zone].rgba = rgba self.values[zone] = value except IndexError: pass def _update_gauge(self, *args): self.canvas.clear() zones = self.zones if zones is None or zones == 0: return x = self.pos[0] y = self.pos[1] width = self.size[0] height = self.size[1] rw = width / float(zones) if self.direction == 'left-right': index = 0 index_dir = 1 elif self.direction == 'right-left': index = zones - 1 index_dir = -1 else: raise Exception('Invalid direction {}'.self.dir) with self.canvas: for i in range(0, zones): xp = x + (rw * i) color = self.heat_gradient.get_color_value(self.values[index]) c = Color(rgba=color) self.colors[index] = c Rectangle(pos=(xp, y), size=(rw, height)) index += index_dir Color(rgba=(0.0, 0.0, 0.0, 1.0)) Rectangle(texture=BrakeHeatGauge.TIRE_IMAGE.texture, pos=(x, y), size=(width, height)) def on_values(self, instance, value): pass
def _draw_current_map(self): left = self.pos[0] bottom = self.pos[1] self.canvas.clear() heat_width_step = sp(self.HEAT_MAP_WIDTH_STEP) path_count = len(self._scaled_paths.keys()) heat_width = sp(self.heat_width_scale * self.height) + ( (path_count - 1) * heat_width_step) with self.canvas: Color(*self.track_color) Line(points=self._scaled_map_points, width=sp(self.track_width_scale * self.height), closed=True, cap='round', joint='round') color_gradient = HeatColorGradient() # draw all of the traces for key, path_points in self._scaled_paths.iteritems(): heat_path = self._heat_map_values.get(key) if heat_path: # draw heat map point_count = len(path_points) heat_min = self.heat_min heat_range = self.heat_max - heat_min value_index = 0 current_heat_pct = 0 i = 0 line_points = [] try: line_points.extend( [path_points[i], path_points[i + 1]]) current_heat_pct = int(( (heat_path[value_index] - heat_min) / heat_range) * 100.0) while i < point_count - 2: heat_value = heat_path[value_index] heat_pct = int( ((heat_value - heat_min) / heat_range) * 100.0) if heat_pct != current_heat_pct: heat_color = color_gradient.get_color_value( heat_pct / 100.0) Color(*heat_color) Line(points=line_points, width=heat_width, closed=False, joint='miter', cap='round') line_points = [ path_points[i - 2], path_points[i - 1] ] current_heat_pct = heat_pct line_points.extend( [path_points[i], path_points[i + 1]]) value_index += 1 i += 2 heat_width -= heat_width_step except IndexError: # if the number of heat values mismatch the heat map points, terminate early pass else: # draw regular map trace Color(*self._paths[key].color) Line(points=path_points, width=sp(self.path_width_scale * self.height), closed=True, cap='square', joint='miter') # draw the markers marker_size = (self.marker_width_scale * self.height) * self.marker_scale for key, marker_point in self._marker_points.iteritems(): scaled_point = self._scale_point(marker_point, self.height, left, bottom) Color(*marker_point.color) self._marker_locations[key] = Line(circle=(scaled_point.x, scaled_point.y, marker_size), width=marker_size, closed=True)
def _draw_current_map(self): def _calc_heat_pct(heat_value, heat_min, heat_range): if heat_value is not None and heat_range > 0: return int(((heat_value - heat_min) / heat_range) * 100.0) else: return 0 left = self.pos[0] bottom = self.pos[1] self.canvas.clear() heat_width_step = dp(self.HEAT_MAP_WIDTH_STEP) path_count = len(self._scaled_paths.keys()) heat_width = dp(self.heat_width_scale * self.height) + ( (path_count - 1) * heat_width_step) with self.canvas: Color(*self.track_color) Line(points=self._scaled_map_points, width=dp(self.track_width_scale * self.height), closed=True, cap='round', joint='round') color_gradient = HeatColorGradient() # draw all of the traces for key, path_points in self._scaled_paths.iteritems(): heat_path = self._heat_map_values.get(key) if heat_path: # draw heat map point_count = len(path_points) heat_min = self.heat_min heat_range = self.heat_max - heat_min value_index = 0 current_heat_pct = 0 i = 0 line_points = [] try: line_points.extend( [path_points[i], path_points[i + 1]]) current_heat_pct = _calc_heat_pct( heat_path[value_index], heat_min, heat_range) while i < point_count - 2: heat_pct = _calc_heat_pct(heat_path[value_index], heat_min, heat_range) if heat_pct != current_heat_pct: heat_color = color_gradient.get_color_value( heat_pct / 100.0) Color(*heat_color) Line(points=line_points, width=heat_width, closed=False, joint='miter', cap='round') line_points = [ path_points[i - 2], path_points[i - 1] ] current_heat_pct = heat_pct line_points.extend( [path_points[i], path_points[i + 1]]) value_index += 1 i += 2 heat_width -= heat_width_step except IndexError: # if the number of heat values mismatch the heat map points, terminate early pass else: # draw regular map trace Color(*self._paths[key].color) Line(points=path_points, width=dp(self.path_width_scale * self.height), closed=True, cap='square', joint='miter') target_size = (self.target_width_scale * self.height) * self.target_scale # draw start point if GeoPoint.is_valid(self.start_point): Color(*self.start_point_color) scaled_point = self._scale_geopoint(self.start_point) Rectangle(texture=TrackMapView.start_image.texture, pos=self._center_point(scaled_point, (target_size, target_size)), size=[target_size, target_size]) # draw finish point if GeoPoint.is_valid(self.finish_point): Color(*self.finish_point_color) scaled_point = self._scale_geopoint(self.finish_point) Rectangle(texture=TrackMapView.finish_image.texture, pos=self._center_point(scaled_point, (target_size, target_size)), size=[target_size, target_size]) # draw the sector points sector_count = 0 for sector_point in self.sector_points: sector_count += 1 scaled_point = self._scale_geopoint(sector_point) label = CoreLabel(text='{:>2}'.format(sector_count), font_size=target_size * 0.8, font_name='resource/fonts/ASL_regular.ttf') label.refresh() texture = label.texture centered_point = self._center_point(scaled_point, texture.size) Color(*self.sector_point_color) Rectangle(source='resource/trackmap/sector_64px.png', pos=self._center_point(scaled_point, texture.size), size=[target_size, target_size]) Color(0.0, 0.0, 0.0, 1.0) # Tweak font position to improve centering. SHould be a better way to do this trim_x = texture.size[0] * 0.1 trim_y = -texture.size[1] * 0.05 Rectangle(size=texture.size, pos=(centered_point[0] + trim_x, centered_point[1] + trim_y), texture=texture) # draw the dynamic markers marker_size = (self.marker_width_scale * self.height) * self.marker_scale for key, marker_point in self._marker_points.iteritems(): scaled_point = self._scale_point(marker_point, self.height, left, bottom) Color(*marker_point.color) self._marker_locations[key] = Line(circle=(scaled_point.x, scaled_point.y, marker_size), width=marker_size, closed=True) Color(1.0, 1.0, 1.0, 1.0)
class TireCorner(BoxLayout): LABEL_COLOR = [0.5, 0.5, 0.5, 1.0] zones = NumericProperty() minval = NumericProperty() maxval = NumericProperty() def __init__(self, **kwargs): super(TireCorner, self).__init__(**kwargs) self.tire_value_widgets = [] self.heat_gradient = HeatColorGradient() def _init_view(self): self.tire_zones = TireCorner.DEFAULT_TIRE_ZONES self.minval = TireCorner.DEFAULT_TIRE_MIN self.maxval = TireCorner.DEFAULT_TIRE_MAX def on_minval(self, instance, value): for gauge in self.tire_value_widgets: gauge.minval = value def on_maxval(self, instance, value): for gauge in self.tire_value_widgets: gauge.maxval = value def on_zones(self, instance, value): self.ids.tire.zones = value self.ids.tire_values_top.clear_widgets() self.ids.tire_values_bottom.clear_widgets() self.ids.tire_values.clear_widgets() if value > 2: tv = self.ids.tire_values value_containers = [tv] orientation = 'right-left' if self.children.index(tv) == 1 else 'left-right' else: value_containers = [self.ids.tire_values_top, self.ids.tire_values_bottom] orientation = 'center' if len(value_containers) == 2: for c in value_containers: c.size_hint_y = 0.1 self.ids.tire.size_hint_y = 0.6 del(self.tire_value_widgets[:]) for i in range(0, value): tire_values = value_containers[0] if i % len(value_containers) == 0 else value_containers[1] gauge = BarGraphGauge(orientation=orientation, label_color=TireCorner.LABEL_COLOR) tire_values.add_widget(gauge) self.tire_value_widgets.append(gauge) gauge.minval = self.minval gauge.maxval = self.maxval def set_value(self, zone, value): value = min(self.maxval, value) value = max(self.minval, value) scaled = value / self.maxval if self.maxval > 0 else 0 self.ids.tire.set_value(zone, scaled) try: value_widget = self.tire_value_widgets[zone] value_widget.value = value value_widget.color = self.heat_gradient.get_color_value(scaled) except IndexError: pass
def _draw_current_map(self): def _calc_heat_pct(heat_value, heat_min, heat_range): if heat_value is not None and heat_range > 0: return int(((heat_value - heat_min) / heat_range) * 100.0) else: return 0 left = self.pos[0] bottom = self.pos[1] self.canvas.clear() heat_width_step = self.HEAT_MAP_WIDTH_STEP path_count = len(self._scaled_paths.keys()) heat_width = (self.heat_width_scale * self.height) + ((path_count - 1) * heat_width_step) with self.canvas: Color(*self.track_color) Line(points=self._scaled_map_points, width=self.track_width_scale * self.height, closed=True, cap='round', joint='round') color_gradient = HeatColorGradient() # draw all of the traces for key, path_points in self._scaled_paths.iteritems(): heat_path = self._heat_map_values.get(key) if heat_path: # draw heat map point_count = len(path_points) heat_min = self.heat_min heat_range = self.heat_max - heat_min value_index = 0 current_heat_pct = 0 i = 0 line_points = [] try: line_points.extend([path_points[i], path_points[i + 1]]) current_heat_pct = _calc_heat_pct(heat_path[value_index], heat_min, heat_range) while i < point_count - 2: heat_pct = _calc_heat_pct(heat_path[value_index], heat_min, heat_range) if heat_pct != current_heat_pct: heat_color = color_gradient.get_color_value(heat_pct / 100.0) Color(*heat_color) Line(points=line_points, width=heat_width, closed=False, joint='miter', cap='round') line_points = [path_points[i - 2], path_points[i - 1]] current_heat_pct = heat_pct line_points.extend([path_points[i], path_points[i + 1]]) value_index += 1 i += 2 heat_width -= heat_width_step except IndexError: # if the number of heat values mismatch the heat map points, terminate early pass else: # draw regular map trace Color(*self._paths[key].color) Line(points=path_points, width=self.path_width_scale * self.height, closed=True, cap='square', joint='miter') target_size = (self.target_width_scale * self.height) * self.target_scale # draw start point if GeoPoint.is_valid(self.start_point): Color(*self.start_point_color) scaled_point = self._scale_geopoint(self.start_point) Rectangle(texture=TrackMapView.start_image.texture, pos=self._center_point(scaled_point, (target_size, target_size)), size=[target_size, target_size]) # draw finish point if GeoPoint.is_valid(self.finish_point): Color(*self.finish_point_color) scaled_point = self._scale_geopoint(self.finish_point) Rectangle(texture=TrackMapView.finish_image.texture, pos=self._center_point(scaled_point, (target_size, target_size)), size=[target_size, target_size]) # draw the sector points sector_count = 0 for sector_point in self.sector_points: sector_count += 1 scaled_point = self._scale_geopoint(sector_point) label = CoreLabel(text='{:>2}'.format(sector_count), font_size=target_size * 0.8, font_name='resource/fonts/ASL_regular.ttf') label.refresh() texture = label.texture centered_point = self._center_point(scaled_point, texture.size) Color(*self.sector_point_color) Rectangle(source='resource/trackmap/sector_64px.png', pos=self._center_point(scaled_point, texture.size), size=[target_size, target_size]) Color(0.0, 0.0, 0.0, 1.0) # Tweak font position to improve centering. SHould be a better way to do this trim_x = texture.size[0] * 0.1 trim_y = -texture.size[1] * 0.05 Rectangle(size=texture.size, pos=(centered_point[0] + trim_x, centered_point[1] + trim_y), texture=texture) # draw the dynamic markers marker_size = (self.marker_width_scale * self.height) * self.marker_scale for key, marker_point in self._marker_points.iteritems(): scaled_point = self._scale_point(marker_point, self.height, left, bottom) Color(*marker_point.color) self._marker_locations[key] = Line(circle=(scaled_point.x, scaled_point.y, marker_size), width=marker_size, closed=True) Color(1.0, 1.0, 1.0, 1.0)
class TireCorner(BoxLayout): LABEL_COLOR = [0.5, 0.5, 0.5, 1.0] zones = NumericProperty() minval = NumericProperty() maxval = NumericProperty() def __init__(self, **kwargs): super(TireCorner, self).__init__(**kwargs) self.tire_value_widgets = [] self.heat_gradient = HeatColorGradient() def _init_view(self): self.tire_zones = TireCorner.DEFAULT_TIRE_ZONES self.minval = TireCorner.DEFAULT_TIRE_MIN self.maxval = TireCorner.DEFAULT_TIRE_MAX def on_minval(self, instance, value): for gauge in self.tire_value_widgets: gauge.minval = value def on_maxval(self, instance, value): for gauge in self.tire_value_widgets: gauge.maxval = value def on_zones(self, instance, value): self.ids.tire.zones = value self.ids.tire_values_top.clear_widgets() self.ids.tire_values_bottom.clear_widgets() self.ids.tire_values.clear_widgets() if value > 2: tv = self.ids.tire_values value_containers = [tv] orientation = 'right-left' if self.children.index( tv) == 1 else 'left-right' else: value_containers = [ self.ids.tire_values_top, self.ids.tire_values_bottom ] orientation = 'center' if len(value_containers) == 2: for c in value_containers: c.size_hint_y = 0.1 self.ids.tire.size_hint_y = 0.6 del (self.tire_value_widgets[:]) for i in range(0, value): tire_values = value_containers[0] if i % len( value_containers) == 0 else value_containers[1] gauge = BarGraphGauge(orientation=orientation, label_color=TireCorner.LABEL_COLOR) tire_values.add_widget(gauge) self.tire_value_widgets.append(gauge) gauge.minval = self.minval gauge.maxval = self.maxval def set_value(self, zone, value): value = min(self.maxval, value) value = max(self.minval, value) scaled = value / self.maxval if self.maxval > 0 else 0 self.ids.tire.set_value(zone, scaled) try: value_widget = self.tire_value_widgets[zone] value_widget.value = value value_widget.color = self.heat_gradient.get_color_value(scaled) except IndexError: pass