First commit of claude's rework in django + vanillajs fronted
This commit is contained in:
64
apps/photos/analysis.py
Normal file
64
apps/photos/analysis.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
Group size computation from PointOfImpact real-world coordinates.
|
||||
|
||||
All measurements in millimetres. Origin is point-of-aim:
|
||||
x > 0 = right (windage), y > 0 = up (elevation).
|
||||
"""
|
||||
import math
|
||||
|
||||
|
||||
def compute_group_size(
|
||||
points: list[tuple[float, float]],
|
||||
distance_m: float | None = None,
|
||||
) -> dict:
|
||||
"""
|
||||
Compute ballistic group metrics from a list of (x_mm, y_mm) coordinates.
|
||||
|
||||
Args:
|
||||
points: list of (x_mm, y_mm) tuples — minimum 2 required.
|
||||
distance_m: shooting distance in metres, used for MOA conversion.
|
||||
Pass None to leave MOA fields as None.
|
||||
|
||||
Returns:
|
||||
dict with keys matching GroupPhotoAnalysis fields.
|
||||
"""
|
||||
if len(points) < 2:
|
||||
raise ValueError("At least 2 points of impact are required.")
|
||||
|
||||
xs = [p[0] for p in points]
|
||||
ys = [p[1] for p in points]
|
||||
n = len(points)
|
||||
|
||||
# Extreme spread: maximum pairwise distance
|
||||
group_size_mm = 0.0
|
||||
for i in range(n):
|
||||
for j in range(i + 1, n):
|
||||
d = math.sqrt((xs[i] - xs[j]) ** 2 + (ys[i] - ys[j]) ** 2)
|
||||
if d > group_size_mm:
|
||||
group_size_mm = d
|
||||
|
||||
# Centroid
|
||||
cx = sum(xs) / n
|
||||
cy = sum(ys) / n
|
||||
|
||||
# Mean radius: average distance from centroid
|
||||
mean_radius_mm = sum(
|
||||
math.sqrt((x - cx) ** 2 + (y - cy) ** 2) for x, y in points
|
||||
) / n
|
||||
|
||||
def to_moa(mm: float) -> float | None:
|
||||
"""Convert mm at distance_m to MOA. 1 MOA ≈ 0.29089 mm/m at that distance."""
|
||||
if distance_m is None or distance_m <= 0:
|
||||
return None
|
||||
return round(mm / (distance_m * 0.29089), 3)
|
||||
|
||||
return {
|
||||
'group_size_mm': round(group_size_mm, 2),
|
||||
'group_size_moa': to_moa(group_size_mm),
|
||||
'mean_radius_mm': round(mean_radius_mm, 2),
|
||||
'mean_radius_moa': to_moa(mean_radius_mm),
|
||||
'windage_offset_mm': round(cx, 2),
|
||||
'windage_offset_moa': to_moa(cx),
|
||||
'elevation_offset_mm': round(cy, 2),
|
||||
'elevation_offset_moa': to_moa(cy),
|
||||
}
|
||||
Reference in New Issue
Block a user