def predictions(points, hazards = [], hazard_decrease = .5): count = 0 prev_point = None speeds = [] next_locations = [] for point in points: if prev_point != None: l1 = (point.latitude, point.longitude) l2 = (prev_point.latitude, prev_point.longitude) distance = geo.calculate_distance(l1,l2) time = point.timestamp - prev_point.timestamp speed = geo.speed(distance, time) predict = geo.predict_next_location(l2, l1, time, time) error = geo.error(l2,predict) speeds.append(speed * 1000) next_locations.append(predict) print(error) prev_point = point count += 1 return speeds, next_locations
def _add_new_car(self, car_index: int, location: Location) -> None: # Initialize data store for new car index. self.car_positions.append(car_index) self.car_telemetry[car_index] = { 'locations': deque([location], maxlen=MAX_TELEMETRY_LIST_LENGTH), 'velocities': deque([None], maxlen=MAX_TELEMETRY_LIST_LENGTH), 'accelerations': deque([None], maxlen=MAX_TELEMETRY_LIST_LENGTH), 'distances_from_lap_start': deque( [None, calculate_distance(location, self.lap_start_location)], maxlen=MAX_TELEMETRY_LIST_LENGTH), 'current_lap': 0, 'lap_start_timestamp': location.timestamp, 'lap_distance': 0.0, 'total_distance': 0.0, 'last_timestamp': location.timestamp } if location.timestamp > self.last_timestamp: self.last_timestamp = location.timestamp
def test_calculate_distance(self): location_1 = Location(timestamp=0, latitude=0.0, longitude=0.0) location_2 = Location(timestamp=0, latitude=0.0, longitude=0.0) self.assertAlmostEqual(calculate_distance(location_1, location_2), 0.0) # at equator each degree of latitude is ~ 111 km apart location_2 = Location(timestamp=0, latitude=1.0, longitude=0.0) self.assertAlmostEqual(calculate_distance(location_1, location_2) / 1000.0, 111.0, places=0) # at equator each degree of longitude is ~ 111 km apart location_2 = Location(timestamp=0, latitude=0.0, longitude=1.0) self.assertAlmostEqual(calculate_distance(location_1, location_2) / 1000.0, 111.0, places=0)
def comparison_function(car_1: int, car_2: int) -> int: # return 1 if car 1 is behind car 2 # return -1 if car 2 is behind car 1 # return 0 if we cannot tell distance = calculate_distance(extrapolated_car_locations[car_1], extrapolated_car_locations[car_2]) if distance < CAR_POSITION_DETECTION_THRESHOLD: # for cars inside car position detection threshold, we calculate bearing from car 1 to car 2 distance_bearing = calculate_bearing( extrapolated_car_locations[car_1], extrapolated_car_locations[car_2]) # and velocity bearing of car 1 if self.car_telemetry[car_1]['velocities'][-1] is not None: car_1_velocity_bearing = self.car_telemetry[car_1][ 'velocities'][-1].bearing # and finally we compare bearing of distance between cars with velocity bearing if 135.0 < ( (360.0 + distance_bearing - car_1_velocity_bearing) % 360) < 225.0: # car 2 is behind car 1 return -1 elif 315.0 > ((360.0 + distance_bearing - car_1_velocity_bearing) % 360) \ or ((360.0 + distance_bearing - car_1_velocity_bearing) % 360) < 45.0: # car 2 is ahead of car 1 return 1 else: return 0 else: return 0 else: # for cars outside car position detection threshold, first compare current lap car_1_current_lap = self.car_telemetry[car_1]['current_lap'] car_2_current_lap = self.car_telemetry[car_2]['current_lap'] if car_1_current_lap > car_2_current_lap: return -1 elif car_2_current_lap > car_1_current_lap: return 1 else: # if current lap is the same, we then compare lap distance car_1_lap_distance = self.car_telemetry[car_1][ 'lap_distance'] car_2_lap_distance = self.car_telemetry[car_2][ 'lap_distance'] if car_1_lap_distance > car_2_lap_distance: return -1 elif car_2_lap_distance > car_1_lap_distance: return 1 else: return 0
def __calc_distance_from_obj(obj): lng = obj['longitude'] lat = obj['latitude'] return calculate_distance(lng, lat, ref_longitude, ref_latitude)
def add_new_car_coordinate(self, car_index: int, location: Location) -> List[Tuple[str, dict]]: # Add new car coordinate to data store and return list of new topic and message tuples that should be published. if car_index not in self.car_telemetry: self._add_new_car(car_index, location) return [] else: # initialize list of new topic and message tuples messages = [] # calculate velocity and acceleration previous_location = self.car_telemetry[car_index]['locations'][-1] previous_velocity = self.car_telemetry[car_index]['velocities'][-1] self.car_telemetry[car_index]['locations'].append(location) distance, velocity = calculate_distance_and_velocity( previous_location, location) self.car_telemetry[car_index]['velocities'].append(velocity) acceleration = None if previous_velocity is None else calculate_acceleration( previous_velocity, velocity) self.car_telemetry[car_index]['accelerations'].append(acceleration) # publish car speed status messages.append( ('carStatus', { 'timestamp': location.timestamp, 'carIndex': car_index, 'type': 'SPEED', 'value': 2.23693629205 * velocity.magnitude }) ) # we convert velocity from meters per second to miles per hour here # check whether car crossed lap start line distance_from_lap_start = calculate_distance( location, self.lap_start_location) if self._crossed_lap_start_line( self.car_telemetry[car_index]['distances_from_lap_start'] [-2], self.car_telemetry[car_index]['distances_from_lap_start'] [-1], distance_from_lap_start): # note, we detected that previous location was nearest to lap start line, so we use previous location timestamp to calculate lap time lap_time = 0.001 * float( previous_location.timestamp - self.car_telemetry[car_index]['lap_start_timestamp']) # publish car completing lap event messages.append(('events', { 'timestamp': previous_location.timestamp, 'text': f"Car {car_index} completes lap {self.car_telemetry[car_index]['current_lap']}" + f" in {int(lap_time / 60)}m{(lap_time % 60):.3f}s." })) self.car_telemetry[car_index]['current_lap'] += 1 self.car_telemetry[car_index][ 'lap_start_timestamp'] = previous_location.timestamp self.car_telemetry[car_index]['lap_distance'] = distance else: self.car_telemetry[car_index]['lap_distance'] += distance self.car_telemetry[car_index]['distances_from_lap_start'].append( distance_from_lap_start) self.car_telemetry[car_index]['total_distance'] += distance self.car_telemetry[car_index][ 'last_timestamp'] = location.timestamp if location.timestamp > self.last_timestamp: self.last_timestamp = location.timestamp # calculate updated car positions new_car_positions = self._calculate_car_positions() existing_car_positions = self.car_positions if new_car_positions != existing_car_positions: for new_car_positions_index, new_car_positions_car_index in enumerate( new_car_positions): if new_car_positions_car_index != existing_car_positions[ new_car_positions_index]: # car position changed - publish car position status messages.append(('carStatus', { 'timestamp': location.timestamp, 'carIndex': new_car_positions_car_index, 'type': 'POSITION', 'value': new_car_positions_index + 1 })) # now detect overtakes cars_behind = new_car_positions[new_car_positions_index + 1:] cars_previously_behind = existing_car_positions[ existing_car_positions. index(new_car_positions_car_index) + 1:] overtaken_cars = set(cars_behind) - set( cars_previously_behind) for overtaken_car in overtaken_cars: # publish car overtake event if (0.001 * float(location.timestamp - self.last_overtake_event_timestamp) ) > OVERTAKE_EVENTS_TIME_CONSTANTS: self.last_overtake_event_timestamp = location.timestamp messages.append(('events', { 'timestamp': location.timestamp, 'text': f"Car {new_car_positions_car_index} overtakes Car {overtaken_car}!" })) self.car_positions = new_car_positions return messages