use std::{
f64::{self, consts::FRAC_PI_3},
marker::PhantomData,
ops::{AddAssign, Mul},
};
use num::Num;
use crate::{
idx::Idx,
moc::range::RangeMOC,
qty::{Hpx, MocQty},
};
pub trait Value<T: Idx>:
'static
+ Num
+ PartialOrd
+ Mul<f64, Output = Self>
+ AddAssign
+ Copy
+ Send
+ Sync
+ std::fmt::Debug
{
}
impl<T: Idx> Value<T> for f64 {}
pub trait MOMIterator<T: Idx, Q: MocQty<T>, V: Value<T>>: Sized + Iterator<Item = (T, V)> {
fn sum_values_in_moc(self, moc: &RangeMOC<T, Q>) -> V {
let mut sum = V::zero();
for (zuniq, value) in self {
let (depth, ipix) = Q::from_zuniq(zuniq);
let cell_fraction = moc.cell_fraction(depth, ipix);
sum += value * cell_fraction;
}
sum
}
}
pub trait HpxMOMIterator<T: Idx, V: Value<T>>: MOMIterator<T, Hpx<T>, V> {
fn sum_values_in_hpxmoc(self, moc: &RangeMOC<T, Hpx<T>>) -> V {
let mut sum = V::zero();
for (hpx_uniq, value) in self {
let (depth, ipix) = Hpx::<T>::from_uniq_hpx(hpx_uniq);
let cell_fraction = moc.cell_fraction(depth, ipix);
sum += value * cell_fraction;
}
sum
}
fn retain_values_with_weights_in_hpxmoc(
self,
moc: &RangeMOC<T, Hpx<T>>,
) -> HpxMOMFilter<'_, T, V, Self> {
HpxMOMFilter::new(self, moc)
}
}
pub struct HpxMomIter<T: Idx, Q: MocQty<T>, V: Value<T>, I: Sized + Iterator<Item = (T, V)>> {
it: I,
_phantom: PhantomData<Q>,
}
impl<T: Idx, Q: MocQty<T>, V: Value<T>, I: Sized + Iterator<Item = (T, V)>> HpxMomIter<T, Q, V, I> {
pub fn new(it: I) -> Self {
Self {
it,
_phantom: PhantomData,
}
}
}
impl<T: Idx, Q: MocQty<T>, V: Value<T>, I: Sized + Iterator<Item = (T, V)>> Iterator
for HpxMomIter<T, Q, V, I>
{
type Item = (T, V);
fn next(&mut self) -> Option<Self::Item> {
self.it.next()
}
}
impl<T: Idx, Q: MocQty<T>, V: Value<T>, I: Sized + Iterator<Item = (T, V)>>
MOMIterator<T, Hpx<T>, V> for HpxMomIter<T, Q, V, I>
{
}
impl<T: Idx, Q: MocQty<T>, V: Value<T>, I: Sized + Iterator<Item = (T, V)>> HpxMOMIterator<T, V>
for HpxMomIter<T, Q, V, I>
{
}
pub struct HpxMOMFilter<'a, T, V, I>
where
T: Idx,
V: Value<T>,
I: HpxMOMIterator<T, V>,
{
it: I,
moc: &'a RangeMOC<T, Hpx<T>>,
_phantom: PhantomData<V>,
}
impl<'a, T, V, I> HpxMOMFilter<'a, T, V, I>
where
T: Idx,
V: Value<T>,
I: HpxMOMIterator<T, V>,
{
pub fn new(it: I, moc: &'a RangeMOC<T, Hpx<T>>) -> Self {
Self {
it,
moc,
_phantom: PhantomData,
}
}
}
impl<'a, T, V, I> Iterator for HpxMOMFilter<'a, T, V, I>
where
T: Idx,
V: Value<T>,
I: HpxMOMIterator<T, V>,
{
type Item = (V, f64);
fn next(&mut self) -> Option<Self::Item> {
while let Some((uniq, val)) = self.it.next() {
let (depth, ipix) = Hpx::<T>::from_uniq_hpx(uniq);
let cell_fraction = self.moc.cell_fraction(depth, ipix);
if cell_fraction > 0.0 {
let cell_area = FRAC_PI_3 / (1_u64 << (depth << 1) as u32) as f64;
return Some((val, cell_area * cell_fraction));
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, self.it.size_hint().1)
}
}