Skip to content

Commit

Permalink
feat: add Interval intersection for mixed types (#143)
Browse files Browse the repository at this point in the history
* feat: add Interval intersection for mixed types
  • Loading branch information
phc1990 authored Aug 19, 2024
1 parent c56e032 commit 02a9aac
Show file tree
Hide file tree
Showing 4 changed files with 531 additions and 159 deletions.
20 changes: 7 additions & 13 deletions bindings/python/test/object/test_interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,39 +35,33 @@ def test_default_constructor(self):
interval_1 = RealInterval(-4.31, 1.0, Type.Open)
interval_2 = RealInterval(-2.0, -1.0, Type.Closed)
interval_3 = RealInterval(3.5, 4567.35566, Type.HalfOpenRight)
interval_4 = RealInterval(1.45, 1.45, Type.Open)
interval_5 = RealInterval(1.45, 1.45, Type.Closed)
interval_4 = RealInterval(1.45, 1.45, Type.Closed)

assert isinstance(interval_1, RealInterval)
assert isinstance(interval_2, RealInterval)
assert isinstance(interval_3, RealInterval)
assert isinstance(interval_4, RealInterval)
assert isinstance(interval_5, RealInterval)
assert interval_1 is not None
assert interval_2 is not None
assert interval_3 is not None
assert interval_4 is not None
assert interval_5 is not None

with pytest.raises(TypeError):
interval = RealInterval(3.0, 1, Type.Closed)

interval_6 = RealInterval(Real(-4.31), Real(1.0), Type.Open)
interval_7 = RealInterval(Real(-2.0), Real(-1.0), Type.Closed)
interval_8 = RealInterval(Real(3.5), Real(4567.35566), Type.HalfOpenRight)
interval_9 = RealInterval(Real(1.45), Real(1.45), Type.Open)
interval_10 = RealInterval(Real(1.45), Real(1.45), Type.Closed)
interval_5 = RealInterval(Real(-4.31), Real(1.0), Type.Open)
interval_6 = RealInterval(Real(-2.0), Real(-1.0), Type.Closed)
interval_7 = RealInterval(Real(3.5), Real(4567.35566), Type.HalfOpenRight)
interval_8 = RealInterval(Real(1.45), Real(1.45), Type.Closed)

assert isinstance(interval_5, RealInterval)
assert isinstance(interval_6, RealInterval)
assert isinstance(interval_7, RealInterval)
assert isinstance(interval_8, RealInterval)
assert isinstance(interval_9, RealInterval)
assert isinstance(interval_10, RealInterval)
assert interval_5 is not None
assert interval_6 is not None
assert interval_7 is not None
assert interval_8 is not None
assert interval_9 is not None
assert interval_10 is not None

# Interval Bounds
a = -4.31
Expand Down
1 change: 0 additions & 1 deletion include/OpenSpaceToolkit/Mathematics/Object/Interval.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,6 @@ class Interval : public IntervalBase
static types::String StringFromType(const Interval::Type& anIntervalType);

private:
bool contains(const T& aValue, const bool& isOpen) const;
bool checkAgainstLowerBound(const T& aValue, const bool& isOpen, const bool& isUpperBound) const;
bool checkAgainstUpperBound(const T& aValue, const bool& isOpen, const bool& isLowerBound) const;

Expand Down
93 changes: 77 additions & 16 deletions src/OpenSpaceToolkit/Mathematics/Object/Interval.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,17 @@ Interval<T>::Interval(const T& aLowerBound, const T& anUpperBound, const Interva
lowerBound_(aLowerBound),
upperBound_(anUpperBound)
{
if (lowerBound_.isDefined() && upperBound_.isDefined() && (lowerBound_ > upperBound_))
if (lowerBound_.isDefined() && upperBound_.isDefined())
{
throw ostk::core::error::RuntimeError("Lower bound greater than upper bound.");
if (lowerBound_ > upperBound_)
{
throw ostk::core::error::RuntimeError("Lower bound greater than upper bound.");
}

if (lowerBound_ == upperBound_ && type_ != Interval<T>::Type::Closed)
{
throw ostk::core::error::RuntimeError("Lower bound equal to upper bound in a non-closed Interval.");
}
}
}

Expand Down Expand Up @@ -123,7 +131,7 @@ bool Interval<T>::contains(const T& aValue) const
throw ostk::core::error::runtime::Undefined("Interval");
}

return this->contains(aValue, false);
return this->checkAgainstLowerBound(aValue, false, false) && this->checkAgainstUpperBound(aValue, false, false);
}

template <class T>
Expand Down Expand Up @@ -219,20 +227,79 @@ Interval<T> Interval<T>::getIntersectionWith(const Interval& anInterval) const
throw ostk::core::error::runtime::Undefined("Interval");
}

if (anInterval.getType() != type_)
const T lowerBound = std::max(lowerBound_, anInterval.lowerBound_);
const T upperBound = std::min(upperBound_, anInterval.upperBound_);

if (lowerBound > upperBound)
{
return Interval<T>::Undefined();
}

bool openLowerBound = false;
if (lowerBound == lowerBound_)
{
throw ostk::core::error::runtime::ToBeImplemented("Intersection between different Interval::Type of interval.");
if (type_ == Interval<T>::Type::Open || type_ == Interval<T>::Type::HalfOpenLeft)
{
openLowerBound = true;
}
}

const T lowerBound = std::max(lowerBound_, anInterval.getLowerBound());
const T upperBound = std::min(upperBound_, anInterval.getUpperBound());
if (!openLowerBound && lowerBound == anInterval.lowerBound_)
{
if (anInterval.type_ == Interval<T>::Type::Open || anInterval.type_ == Interval<T>::Type::HalfOpenLeft)
{
openLowerBound = true;
}
}

if (lowerBound > upperBound)
bool openUpperBound = false;
if (upperBound == upperBound_)
{
return Interval<T>::Undefined();
if (type_ == Interval<T>::Type::Open || type_ == Interval<T>::Type::HalfOpenRight)
{
openUpperBound = true;
}
}

return Interval<T>(lowerBound, upperBound, type_);
if (!openUpperBound && upperBound == anInterval.upperBound_)
{
if (anInterval.type_ == Interval<T>::Type::Open || anInterval.type_ == Interval<T>::Type::HalfOpenRight)
{
openUpperBound = true;
}
}

if (openLowerBound && openUpperBound)
{
if (lowerBound == upperBound)
{
return Interval<T>::Undefined();
}

return Interval<T>::Open(lowerBound, upperBound);
}

if (openLowerBound)
{
if (lowerBound == upperBound)
{
return Interval<T>::Undefined();
}

return Interval<T>::HalfOpenLeft(lowerBound, upperBound);
}

if (openUpperBound)
{
if (lowerBound == upperBound)
{
return Interval<T>::Undefined();
}

return Interval<T>::HalfOpenRight(lowerBound, upperBound);
}

return Interval<T>::Closed(lowerBound, upperBound);
}

template <class T>
Expand Down Expand Up @@ -515,12 +582,6 @@ types::String Interval<T>::StringFromType(const Interval::Type& anIntervalType)
return types::String::Empty();
}

template <class T>
bool Interval<T>::contains(const T& aValue, const bool& isOpen) const
{
return this->checkAgainstLowerBound(aValue, isOpen, false) && this->checkAgainstUpperBound(aValue, isOpen, false);
}

template <class T>
bool Interval<T>::checkAgainstLowerBound(const T& aValue, const bool& isOpen, const bool& isUpperBound) const
{
Expand Down
Loading

0 comments on commit 02a9aac

Please sign in to comment.