import math
from typing import List, Sequence
from .charts_downsample_types import Sample
def downsample(points: Sequence[Sample], threshold: int) -> List[Sample]:
"""Largest-Triangle-Three-Buckets (Steinarsson 2013).
Same bucket arithmetic, in the same order, as the TypeScript and Rust
versions and the reference implementation. See the README.
"""
if isinstance(threshold, bool) or not isinstance(threshold, int) or threshold < 3:
raise ValueError("threshold must be a whole number of at least 3, received %r" % (threshold,))
n = len(points)
if threshold >= n:
return list(points)
every = (n - 2) / (threshold - 2)
sampled = [points[0]]
a = 0
for i in range(threshold - 2):
avg_start = math.floor((i + 1) * every) + 1
avg_end = min(math.floor((i + 2) * every) + 1, n)
avg_x = 0.0
avg_y = 0.0
for j in range(avg_start, avg_end):
avg_x += points[j].x
avg_y += points[j].y
avg_x /= avg_end - avg_start
avg_y /= avg_end - avg_start
start = math.floor(i * every) + 1
stop = math.floor((i + 1) * every) + 1
ax = points[a].x
ay = points[a].y
max_area = -1.0
nxt = start
for j in range(start, stop):
area = abs((ax - avg_x) * (points[j].y - ay) - (ax - points[j].x) * (avg_y - ay))
if area > max_area:
max_area = area
nxt = j
sampled.append(points[nxt])
a = nxt
sampled.append(points[n - 1])
return sampled