57 lines
1.9 KiB
Python
57 lines
1.9 KiB
Python
from dataclasses import dataclass
|
|
from typing import List, Dict, Any
|
|
|
|
import numpy as np
|
|
|
|
|
|
@dataclass
|
|
class GeoJSONGeometry:
|
|
type: str
|
|
coordinates: List[tuple[float, float]]
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: Dict[str, Any]) -> 'GeoJSONGeometry':
|
|
return cls(
|
|
type=data['type'],
|
|
coordinates=data['coordinates']
|
|
)
|
|
|
|
def find_longest_straight(self, window_size=5) -> (List[float], List[float]):
|
|
"""Find the longest approximately straight section of the track, including wrap-around."""
|
|
max_distance = 0
|
|
best_start_idx = 0
|
|
n = len(self.coordinates)
|
|
|
|
# Helper function to check straightness
|
|
def is_straight(points, start, end, length):
|
|
direction = (end - start) / length
|
|
distances = []
|
|
for point in points:
|
|
projection = start + np.dot(point - start, direction) * direction
|
|
distance = np.linalg.norm(point - projection)
|
|
distances.append(distance)
|
|
return max(distances) < length * 0.05 # 5% tolerance
|
|
|
|
# Check all possible segments, including wrap-around
|
|
for i in range(n):
|
|
# Get window_size points, handling wrap-around
|
|
segment = []
|
|
for j in range(window_size):
|
|
idx = (i + j) % n
|
|
segment.append(np.array(self.coordinates[idx]))
|
|
|
|
start = np.array(segment[0])
|
|
end = np.array(segment[-1])
|
|
length = np.linalg.norm(end - start)
|
|
|
|
if length > max_distance:
|
|
# Check if all points are roughly on the line
|
|
if is_straight(segment, start, end, length):
|
|
max_distance = length
|
|
best_start_idx = i
|
|
|
|
# Return indices that might wrap around
|
|
end_idx = (best_start_idx + window_size) % len(self.coordinates)
|
|
return self.coordinates[best_start_idx], self.coordinates[end_idx]
|
|
|