Skip to content

Commit

Permalink
Merge pull request #8 from bmatthieu3/overlap
Browse files Browse the repository at this point in the history
Add a overlapped_by_iter method in RangeMOC and BorrowedRangeMOC.
  • Loading branch information
fxpineau authored Jun 20, 2024
2 parents 83d9fb6 + a6fd900 commit e588f13
Show file tree
Hide file tree
Showing 4 changed files with 347 additions and 10 deletions.
47 changes: 47 additions & 0 deletions src/moc/range/borrowed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
use std::{marker::PhantomData, ops::Range};

use crate::{
elemset::range::BorrowedMocRanges,
idx::Idx,
moc::{range::RangeRefMocIter, HasMaxDepth, NonOverlapping, RangeMOCIntoIterator, ZSorted},
qty::MocQty,
};

pub struct BorrowedRangeMOC<'a, T: Idx, Q: MocQty<T>> {
depth_max: u8,
ranges: BorrowedMocRanges<'a, T, Q>,
}

impl<'a, T: Idx, Q: MocQty<T>> BorrowedRangeMOC<'a, T, Q> {
pub fn new(depth_max: u8, ranges: BorrowedMocRanges<'a, T, Q>) -> Self {
Self { depth_max, ranges }
}
}

impl<'a, T: Idx, Q: MocQty<T>> HasMaxDepth for BorrowedRangeMOC<'a, T, Q> {
fn depth_max(&self) -> u8 {
self.depth_max
}
}
impl<'a, T: Idx, Q: MocQty<T>> ZSorted for BorrowedRangeMOC<'a, T, Q> {}
impl<'a, T: Idx, Q: MocQty<T>> NonOverlapping for BorrowedRangeMOC<'a, T, Q> {}

impl<'a, T: Idx, Q: MocQty<T>> RangeMOCIntoIterator<T> for BorrowedRangeMOC<'a, T, Q> {
type Qty = Q;
type IntoRangeMOCIter = RangeRefMocIter<'a, T, Self::Qty>;

fn into_range_moc_iter(self) -> Self::IntoRangeMOCIter {
let l = self.ranges.0 .0.len();
let last: Option<Range<T>> = if l > 0 {
Some(self.ranges.0 .0[l - 1].clone())
} else {
None
};
RangeRefMocIter {
depth_max: self.depth_max,
iter: self.ranges.0 .0.iter(),
last,
_qty: PhantomData,
}
}
}
78 changes: 68 additions & 10 deletions src/moc/range/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::{
cmp::Ordering,
convert::{TryFrom, TryInto},
error::Error,
fs::File,
Expand All @@ -7,7 +8,7 @@ use std::{
num::TryFromIntError,
ops::Range,
path::Path,
slice,
slice::SliceIndex,
vec::IntoIter,
};

Expand Down Expand Up @@ -41,21 +42,25 @@ use crate::{
maxdepth_range::RangeMocBuilder,
},
cell::CellMOC,
range::op::{
and::{and, AndRangeIter},
merge::merge_sorted,
minus::{minus, MinusRangeIter},
multi_op::kway_or,
or::{or, OrRangeIter},
xor::xor,
range::{
borrowed::BorrowedRangeMOC,
op::{
and::{and, AndRangeIter},
merge::merge_sorted,
minus::{minus, MinusRangeIter},
multi_op::kway_or,
or::{or, OrRangeIter},
overlap::{overlapped_by, OverlapRangeIter},
xor::xor,
},
},
CellMOCIntoIterator, CellMOCIterator, CellOrCellRangeMOCIterator, HasMaxDepth, MOCProperties,
NonOverlapping, RangeMOCIntoIterator, RangeMOCIterator, ZSorted,
},
qty::{Bounded, Frequency, Hpx, MocQty, Time},
ranges::{BorrowedRanges, Ranges, SNORanges},
};

pub mod borrowed;
pub mod op;

/// Structure made to draw MOCs in AladinLite.
Expand Down Expand Up @@ -144,6 +149,17 @@ impl<T: Idx, Q: MocQty<T>> RangeMOC<T, Q> {
ranges: Ranges::new_unchecked(vec![range]).into(),
}
}

/// Similar to what's Vec does: https://doc.rust-lang.org/src/core/slice/mod.rs.html#617-619
pub fn select<'a, I>(&'a self, index: I) -> BorrowedRangeMOC<'a, T, Q>
where
I: SliceIndex<[Range<T>], Output = [Range<T>]>,
{
let r = &self.ranges.0 .0[index];
let br = BorrowedRanges(r);
BorrowedRangeMOC::new(self.depth_max, br.into())
}

pub fn depth_max(&self) -> u8 {
self.depth_max
}
Expand Down Expand Up @@ -329,6 +345,43 @@ impl<T: Idx, Q: MocQty<T>> RangeMOC<T, Q> {
RangeMOC::new(depth_max, ranges)
}

/// Returns an iterator over the ranges of self that are overlapping the rhs range MOC
pub fn overlapped_by_iter<'a>(&'a self, rhs: &'a RangeMOC<T, Q>) -> OverlappedByIter<'a, T, Q> {
let l = &self.ranges.0 .0;
let r = &rhs.ranges.0 .0;

// Quick rejection test
let (il, ir) = if l.is_empty()
|| r.is_empty()
|| l[0].start >= r[r.len() - 1].end
|| l[l.len() - 1].end <= r[0].start
{
(l.len() - 1, r.len() - 1)
} else {
// Use binary search to find the starting indices
match l[0].start.cmp(&r[0].start) {
Ordering::Less => {
let il = match l.binary_search_by(|l_range| l_range.start.cmp(&r[0].start)) {
Ok(i) => i,
Err(i) => i - 1,
};
(il, 0)
}
Ordering::Greater => {
let ir = match r.binary_search_by(|r_range| r_range.start.cmp(&l[0].start)) {
Ok(i) => i,
Err(i) => i - 1,
};
(0, ir)
}
Ordering::Equal => (0, 0),
}
};

let (left, right) = (self.select(il..), rhs.select(ir..));
overlapped_by(left.into_range_moc_iter(), right.into_range_moc_iter())
}

// CONTAINS: union that stops at first elem found
// OVERLAP (=!CONTAINS on the COMPLEMENT ;) )

Expand Down Expand Up @@ -428,6 +481,10 @@ pub type ExtBorderIter<'a, T> =
pub type IntBorderIter<'a, T> =
AndRangeIter<T, Hpx<T>, RangeMocIter<T, Hpx<T>>, RangeRefMocIter<'a, T, Hpx<T>>>;

/// Complex type returned by the `internal_border_iter` method.
pub type OverlappedByIter<'a, T, Q> =
OverlapRangeIter<T, Q, RangeRefMocIter<'a, T, Q>, RangeRefMocIter<'a, T, Q>>;

impl<T: Idx> RangeMOC<T, Hpx<T>> {
/// Returns `true` if the given coordinates (in radians) is in the MOC
pub fn is_in(&self, lon: f64, lat: f64) -> bool {
Expand Down Expand Up @@ -1433,7 +1490,7 @@ impl<T: Idx, Q: MocQty<T>> RangeMOCIntoIterator<T> for RangeMOC<T, Q> {
/// Iterator borrowing the `RangeMOC` it iterates over.
pub struct RangeRefMocIter<'a, T: Idx, Q: MocQty<T>> {
depth_max: u8,
iter: slice::Iter<'a, Range<T>>,
iter: std::slice::Iter<'a, Range<T>>,
last: Option<Range<T>>,
_qty: PhantomData<Q>,
}
Expand Down Expand Up @@ -1462,6 +1519,7 @@ impl<'a, T: Idx, Q: MocQty<T>> RangeMOCIterator<T> for RangeRefMocIter<'a, T, Q>
self.last.as_ref()
}
}

impl<'a, T: Idx, Q: MocQty<T>> RangeMOCIntoIterator<T> for &'a RangeMOC<T, Q> {
type Qty = Q;
type IntoRangeMOCIter = RangeRefMocIter<'a, T, Self::Qty>;
Expand Down
2 changes: 2 additions & 0 deletions src/moc/range/op/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ pub mod or; // <=> union
pub mod xor; // <=> Aladin Difference

pub mod multi_op;

pub mod overlap;
Loading

0 comments on commit e588f13

Please sign in to comment.