Skip to content

Commit

Permalink
fix: consider open and semi-open intervals in contain and intersects …
Browse files Browse the repository at this point in the history
…functions (#142)

* fix: add Interval contains and intersects support for different types
* fix: use closed segment ellipsoid-segment intersection
  • Loading branch information
phc1990 authored Aug 14, 2024
1 parent c7c0f29 commit c56e032
Show file tree
Hide file tree
Showing 4 changed files with 707 additions and 554 deletions.
4 changes: 4 additions & 0 deletions include/OpenSpaceToolkit/Mathematics/Object/Interval.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,10 @@ 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;

Interval::Type type_;

T lowerBound_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ bool Ellipsoid::intersects(const Segment& aSegment) const
const Real t0 = (-a1 - discriminantRoot) * a2_inverse;
const Real t1 = (-a1 + discriminantRoot) * a2_inverse;

const Interval<Real> resultInterval = Interval<Real>::Open(t0, t1);
const Interval<Real> resultInterval = Interval<Real>::Closed(t0, t1);
const Interval<Real> segmentInterval = Interval<Real>::Closed(-segmentHalfLength, +segmentHalfLength);

if (!resultInterval.contains(segmentInterval))
Expand Down
129 changes: 104 additions & 25 deletions src/OpenSpaceToolkit/Mathematics/Object/Interval.tpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,33 @@ bool Interval<T>::intersects(const Interval& anInterval) const
throw ostk::core::error::runtime::Undefined("Interval");
}

return this->contains(anInterval.lowerBound_) || this->contains(anInterval.upperBound_) ||
anInterval.contains(lowerBound_) || anInterval.contains(upperBound_) || (*this) == anInterval;
if (!anInterval.isDefined())
{
throw ostk::core::error::runtime::Undefined("Interval");
}

return (
(this->checkAgainstLowerBound(
anInterval.lowerBound_,
anInterval.type_ == Interval<T>::Type::Open || anInterval.type_ == Interval<T>::Type::HalfOpenLeft,
false
) ||
this->checkAgainstLowerBound(
anInterval.upperBound_,
anInterval.type_ == Interval<T>::Type::Open || anInterval.type_ == Interval<T>::Type::HalfOpenRight,
true
)) &&
(this->checkAgainstUpperBound(
anInterval.lowerBound_,
anInterval.type_ == Interval<T>::Type::Open || anInterval.type_ == Interval<T>::Type::HalfOpenLeft,
true
) ||
this->checkAgainstUpperBound(
anInterval.upperBound_,
anInterval.type_ == Interval<T>::Type::Open || anInterval.type_ == Interval<T>::Type::HalfOpenRight,
false
))
);
}

template <class T>
Expand All @@ -98,42 +123,32 @@ bool Interval<T>::contains(const T& aValue) const
throw ostk::core::error::runtime::Undefined("Interval");
}

switch (type_)
{
case Interval<T>::Type::Closed:
return (lowerBound_ <= aValue) && (aValue <= upperBound_);

case Interval<T>::Type::Open:
return (lowerBound_ < aValue) && (aValue < upperBound_);

case Interval<T>::Type::HalfOpenLeft:
return (lowerBound_ < aValue) && (aValue <= upperBound_);

case Interval<T>::Type::HalfOpenRight:
return (lowerBound_ <= aValue) && (aValue < upperBound_);

default:
throw ostk::core::error::runtime::Wrong("Type");
break;
}

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

template <class T>
bool Interval<T>::contains(const Interval& anInterval) const
{
if (!anInterval.isDefined())
if (!this->isDefined())
{
throw ostk::core::error::runtime::Undefined("Interval");
}

if (!this->isDefined())
if (!anInterval.isDefined())
{
throw ostk::core::error::runtime::Undefined("Interval");
}

return this->contains(anInterval.lowerBound_) && this->contains(anInterval.upperBound_);
return this->checkAgainstLowerBound(
anInterval.lowerBound_,
anInterval.type_ == Interval<T>::Type::Open || anInterval.type_ == Interval<T>::Type::HalfOpenLeft,
false
) &&
this->checkAgainstUpperBound(
anInterval.upperBound_,
anInterval.type_ == Interval<T>::Type::Open || anInterval.type_ == Interval<T>::Type::HalfOpenRight,
false
);
}

template <class T>
Expand Down Expand Up @@ -500,6 +515,70 @@ 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
{
switch (type_)
{
case Interval<T>::Type::Closed:
case Interval<T>::Type::HalfOpenRight:
if (isOpen && isUpperBound)
{
return lowerBound_ < aValue;
}

return lowerBound_ <= aValue;

case Interval<T>::Type::HalfOpenLeft:
case Interval<T>::Type::Open:
if (isOpen && !isUpperBound)
{
return lowerBound_ <= aValue;
}

return lowerBound_ < aValue;

default:
throw ostk::core::error::runtime::Wrong("Type");
break;
}
}

template <class T>
bool Interval<T>::checkAgainstUpperBound(const T& aValue, const bool& isOpen, const bool& isLowerBound) const
{
switch (type_)
{
case Interval<T>::Type::Closed:
case Interval<T>::Type::HalfOpenLeft:
if (isOpen && isLowerBound)
{
return upperBound_ > aValue;
}

return upperBound_ >= aValue;

case Interval<T>::Type::HalfOpenRight:
case Interval<T>::Type::Open:
if (isOpen && !isLowerBound)
{
return upperBound_ >= aValue;
}

return upperBound_ > aValue;

default:
throw ostk::core::error::runtime::Wrong("Type");
break;
}
}

} // namespace object
} // namespace mathematics
} // namespace ostk
Loading

0 comments on commit c56e032

Please sign in to comment.