use crate::math;
use super::node::DeviationNode;
#[derive(Debug, Clone, Copy)]
pub(crate) struct NodeRing<'a> {
nodes: &'a [DeviationNode],
}
impl<'a> NodeRing<'a> {
pub(crate) const fn new(nodes: &'a [DeviationNode]) -> Self {
Self { nodes }
}
pub(crate) const fn count(self) -> usize {
self.nodes.len()
}
pub(crate) fn value(self, index: usize) -> f64 {
let count = self.nodes.len().max(1);
self.nodes
.get(index % count)
.map_or(0.0, DeviationNode::deviation_degrees)
}
pub(crate) fn course(self, index: usize) -> f64 {
let count = self.nodes.len().max(1);
self.nodes
.get(index % count)
.map_or(0.0, DeviationNode::course_degrees)
}
pub(crate) fn after(self, index: usize) -> usize {
index.saturating_add(1) % self.count().max(1)
}
pub(crate) fn before(self, index: usize) -> usize {
let count = self.count().max(1);
index.saturating_add(count).saturating_sub(1) % count
}
pub(crate) fn span(self, index: usize) -> f64 {
if index.saturating_add(1) < self.count() {
self.course(self.after(index)) - self.course(index)
} else {
360.0 - self.course(index) + self.course(0)
}
}
pub(crate) fn locate(self, course: f64) -> Segment {
let count = self.count();
let last_index = count.saturating_sub(1);
let first = self.course(0);
let last = self.course(last_index);
let wrap_span = self.span(last_index);
if course < first {
return Segment {
index: last_index,
span: wrap_span,
offset: course + 360.0 - last,
};
}
let index = self
.nodes
.partition_point(|node| node.course_degrees() <= course)
.saturating_sub(1);
if index >= last_index {
Segment {
index: last_index,
span: wrap_span,
offset: course - last,
}
} else {
let start = self.course(index);
Segment {
index,
span: self.course(index + 1) - start,
offset: course - start,
}
}
}
pub(crate) fn local_error_bound(self, course: f64) -> f64 {
let segment = self.locate(course);
let second_difference = |centre: usize| {
let previous = self.value(self.before(centre));
let current = self.value(centre);
let next = self.value(self.after(centre));
math::abs(previous - 2.0 * current + next)
};
let left = second_difference(segment.index);
let right = second_difference(self.after(segment.index));
left.max(right) / 8.0
}
}
pub(crate) struct Segment {
pub(crate) index: usize,
pub(crate) span: f64,
pub(crate) offset: f64,
}
impl Segment {
pub(crate) fn fraction(&self) -> f64 {
self.offset / self.span
}
}