Skip to content

Commit

Permalink
Add Region.overlaps method.
Browse files Browse the repository at this point in the history
This new method can be implemented more efficiently for CompoundRegion
than `relate` which returns superset of region relations.
  • Loading branch information
andy-slac committed Nov 18, 2024
1 parent 486f839 commit d6cd8a6
Show file tree
Hide file tree
Showing 27 changed files with 596 additions and 107 deletions.
10 changes: 9 additions & 1 deletion include/lsst/sphgeom/Box.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ class Box : public Region {
AngleInterval const & getLat() const { return _lat; }

/// `isEmpty` returns true if this box does not contain any points.
bool isEmpty() const { return _lat.isEmpty(); }
bool isEmpty() const override { return _lat.isEmpty(); }

/// `isFull` returns true if this box contains all points on
/// the unit sphere.
Expand Down Expand Up @@ -341,6 +341,14 @@ class Box : public Region {
Relationship relate(ConvexPolygon const &) const override;
Relationship relate(Ellipse const &) const override;

TriState overlaps(Region const& other) const override {
return other.overlaps(*this);
}
TriState overlaps(Box const &) const override;
TriState overlaps(Circle const &) const override;
TriState overlaps(ConvexPolygon const &) const override;
TriState overlaps(Ellipse const &) const override;

std::vector<std::uint8_t> encode() const override;

///@{
Expand Down
10 changes: 9 additions & 1 deletion include/lsst/sphgeom/Circle.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ class Circle : public Region {
}
bool operator!=(Circle const & c) const { return !(*this == c); }

bool isEmpty() const {
bool isEmpty() const override {
// Return true when _squaredChordLength is negative or NaN.
return !(_squaredChordLength >= 0.0);
}
Expand Down Expand Up @@ -252,6 +252,14 @@ class Circle : public Region {
Relationship relate(ConvexPolygon const &) const override;
Relationship relate(Ellipse const &) const override;

TriState overlaps(Region const& other) const override {
return other.overlaps(*this);
}
TriState overlaps(Box const &) const override;
TriState overlaps(Circle const &) const override;
TriState overlaps(ConvexPolygon const &) const override;
TriState overlaps(Ellipse const &) const override;

std::vector<std::uint8_t> encode() const override;

///@{
Expand Down
15 changes: 15 additions & 0 deletions include/lsst/sphgeom/CompoundRegion.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class CompoundRegion : public Region {
// Provide read access to all operands for quick iteration.
std::vector<std::unique_ptr<Region>> const& operands() const { return _operands; }

// Check if we have any operands.
bool empty() const { return _operands.empty(); }

private:
std::vector<std::unique_ptr<Region>> _operands;
};
Expand All @@ -119,12 +122,18 @@ class UnionRegion : public CompoundRegion {

// Region interface.
std::unique_ptr<Region> clone() const override { return std::make_unique<UnionRegion>(*this); }
bool isEmpty() const override;
Box getBoundingBox() const override;
Box3d getBoundingBox3d() const override;
Circle getBoundingCircle() const override;
using Region::contains;
bool contains(UnitVector3d const &v) const override;
Relationship relate(Region const &r) const override;
TriState overlaps(Region const& other) const override;
TriState overlaps(Box const &) const override;
TriState overlaps(Circle const &) const override;
TriState overlaps(ConvexPolygon const &) const override;
TriState overlaps(Ellipse const &) const override;
std::vector<std::uint8_t> encode() const override { return _encode(TYPE_CODE); }

///@{
Expand Down Expand Up @@ -152,12 +161,18 @@ class IntersectionRegion : public CompoundRegion {

// Region interface.
std::unique_ptr<Region> clone() const override { return std::make_unique<IntersectionRegion>(*this); }
bool isEmpty() const override;
Box getBoundingBox() const override;
Box3d getBoundingBox3d() const override;
Circle getBoundingCircle() const override;
using Region::contains;
bool contains(UnitVector3d const &v) const override;
Relationship relate(Region const &r) const override;
TriState overlaps(Region const& other) const override;
TriState overlaps(Box const &) const override;
TriState overlaps(Circle const &) const override;
TriState overlaps(ConvexPolygon const &) const override;
TriState overlaps(Ellipse const &) const override;
std::vector<std::uint8_t> encode() const override { return _encode(TYPE_CODE); }

///@{
Expand Down
10 changes: 10 additions & 0 deletions include/lsst/sphgeom/ConvexPolygon.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ class ConvexPolygon : public Region {
return std::unique_ptr<ConvexPolygon>(new ConvexPolygon(*this));
}

bool isEmpty() const override;

Box getBoundingBox() const override;
Box3d getBoundingBox3d() const override;
Circle getBoundingCircle() const override;
Expand Down Expand Up @@ -158,6 +160,14 @@ class ConvexPolygon : public Region {
Relationship relate(ConvexPolygon const &) const override;
Relationship relate(Ellipse const &) const override;

TriState overlaps(Region const& other) const override {
return other.overlaps(*this);
}
TriState overlaps(Box const &) const override;
TriState overlaps(Circle const &) const override;
TriState overlaps(ConvexPolygon const &) const override;
TriState overlaps(Ellipse const &) const override;

std::vector<std::uint8_t> encode() const override;

///@{
Expand Down
10 changes: 9 additions & 1 deletion include/lsst/sphgeom/Ellipse.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ class Ellipse : public Region {

bool operator!=(Ellipse const & e) const { return !(*this == e); }

bool isEmpty() const { return Angle(0.5 * PI) + _a < _gamma; }
bool isEmpty() const override { return Angle(0.5 * PI) + _a < _gamma; }

bool isFull() const { return Angle(0.5 * PI) - _a <= _gamma; }

Expand Down Expand Up @@ -303,6 +303,14 @@ class Ellipse : public Region {
Relationship relate(ConvexPolygon const &) const override;
Relationship relate(Ellipse const &) const override;

TriState overlaps(Region const& other) const override {
return other.overlaps(*this);
}
TriState overlaps(Box const &) const override;
TriState overlaps(Circle const &) const override;
TriState overlaps(ConvexPolygon const &) const override;
TriState overlaps(Ellipse const &) const override;

std::vector<std::uint8_t> encode() const override;

///@{
Expand Down
34 changes: 34 additions & 0 deletions include/lsst/sphgeom/Region.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <cstdint>

#include "Relationship.h"
#include "TriState.h"


namespace lsst {
Expand Down Expand Up @@ -100,6 +101,9 @@ class Region {
/// `getBoundingCircle` returns a bounding-circle for this region.
virtual Circle getBoundingCircle() const = 0;

/// `isEmpty` returns true when a region does not contain any points.
virtual bool isEmpty() const = 0;

/// `contains` tests whether the given unit vector is inside this region.
virtual bool contains(UnitVector3d const &) const = 0;

Expand Down Expand Up @@ -136,6 +140,18 @@ class Region {
virtual Relationship relate(Ellipse const &) const = 0;
///@}

///@{
/// `overlaps` tests whether two regions overlap. This method returns
/// a `TriState` object, when the value is `true` it means that regions
/// definitely overlap, `false` means they are definitely disjont, and
/// unknown state means that they may or may not overlap.
virtual TriState overlaps(Region const& other) const = 0;
virtual TriState overlaps(Box const &) const = 0;
virtual TriState overlaps(Circle const &) const = 0;
virtual TriState overlaps(ConvexPolygon const &) const = 0;
virtual TriState overlaps(Ellipse const &) const = 0;
///@}

/// `encode` serializes this region into an opaque byte string. Byte strings
/// emitted by encode can be deserialized with decode.
virtual std::vector<std::uint8_t> encode() const = 0;
Expand All @@ -152,6 +168,24 @@ class Region {
/// `getRegions` returns a vector of Region.
static std::vector<std::unique_ptr<Region>> getRegions(Region const &region);
///@}

protected:

// Default transformation of the region Relationship as returned from
// `relate` to TriState. Can be used when specific region class cannot
// compute more precise overlap relation.
static TriState _relationship_to_overlaps(Relationship r) {
// `relate` returns exact relation when specific bit is set, if it is
// not then relation may be true or not.
if ((r & DISJOINT) == DISJOINT) {
return TriState(false);
}
if ((r & (WITHIN | CONTAINS)).any()) {
return TriState(true);
}
return TriState();
}

};

}} // namespace lsst::sphgeom
Expand Down
105 changes: 105 additions & 0 deletions include/lsst/sphgeom/TriState.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* This file is part of sphgeom.
*
* Developed for the LSST Data Management System.
* This product includes software developed by the LSST Project
* (http://www.lsst.org).
* See the COPYRIGHT file at the top-level directory of this distribution
* for details of code ownership.
*
* This software is dual licensed under the GNU General Public License and also
* under a 3-clause BSD license. Recipients may choose which of these licenses
* to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
* respectively. If you choose the GPL option then the following text applies
* (but note that there is still no warranty even if you opt for BSD instead):
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef LSST_SPHGEOM_TRISTATE_H_
#define LSST_SPHGEOM_TRISTATE_H_

/// \file
/// \brief This file declares a class for representing tri-state values.

#include <iostream>
#include <stdexcept>


namespace lsst {
namespace sphgeom {

/// `TriState` represents a boolean value with additional `unknown` state.
/// Instances of this class can be compared to booleans `true` and `false`,
/// when the state is unknown, comparisons will return `false`.
class TriState {
public:
/// Construct value in unknown state.
TriState() {}

/// COnstruct value in a known state.
explicit TriState(bool value) : _known(true), _value(value) {}

TriState& operator=(TriState const & other) = default;

/// @brief Compare this tri-state value with other tri-state value.
/// @param other Tri-state value to compare to.
/// @return True is returned when both states are unknown or when both
/// states are known and values are equal, false returned otherwise.
bool operator==(TriState const & other) const {
if (not _known) {
return not other._known;
} else {
return other._known && _value == other._value;
}
}

bool operator!=(TriState const & other) const {
return not this->operator==(other);
}

/// @brief Compare this tri-state value with a boolean.
/// @param value Boolean value to compare to.
/// @return Return true
bool operator==(bool value) const {
return _known && _value == value;
}

bool operator!=(bool value) const {
return not this->operator==(value);
}

/// @brief Check whether the state is known.
/// @return True is returned when state is known.
bool known() const { return _known; }

private:
bool _known = false;
bool _value = false;
};

inline
std::ostream & operator<<(std::ostream & stream, TriState const & value) {
const char* str = "unknown";
if (value == true) {
str = "true";
} else if (value == false) {
str = "false";
}
return stream << str;
}

}} // namespace lsst::sphgeom

#endif // LSST_SPHGEOM_TRISTATE_H_
80 changes: 80 additions & 0 deletions include/lsst/sphgeom/python/tristate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* This file is part of sphgeom.
*
* Developed for the LSST Data Management System.
* This product includes software developed by the LSST Project
* (http://www.lsst.org).
* See the COPYRIGHT file at the top-level directory of this distribution
* for details of code ownership.
*
* This software is dual licensed under the GNU General Public License and also
* under a 3-clause BSD license. Recipients may choose which of these licenses
* to use; please see the files gpl-3.0.txt and/or bsd_license.txt,
* respectively. If you choose the GPL option then the following text applies
* (but note that there is still no warranty even if you opt for BSD instead):
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef LSST_SPHGEOM_PYTHON_TRISTATE_H_
#define LSST_SPHGEOM_PYTHON_TRISTATE_H_

#include "pybind11/pybind11.h"

#include "../TriState.h"

namespace pybind11 {
namespace detail {

/// This struct is a partial specialization of type_caster for
/// for lsst::sphgeom::TriState.
///
/// It maps between TriState and Python bool or None, avoiding the need to
/// wrap the former. This header should be included by all wrappers for
/// functions that consume or return TriState instances.
template <>
struct type_caster<lsst::sphgeom::TriState> {
public:
// Declare a local variable `value` of type lsst::sphgeom::TriState,
// and describe the TriState type as an "bool | None" in pybind11-generated
// docstrings.
PYBIND11_TYPE_CASTER(lsst::sphgeom::TriState, _("bool | None"));

// Convert a Python object to an lsst::sphgeom::TriState.
bool load(handle src, bool) {
if (src.is_none()) {
value = lsst::sphgeom::TriState();
} else {
value = lsst::sphgeom::TriState(src.cast<bool>());
}
return true;
}

// Convert an lsst::sphgeom::TriState to a Python integer.
static handle cast(lsst::sphgeom::TriState src, return_value_policy,
handle) {

if (src == true) {
Py_RETURN_TRUE;
} else if (src == false) {
Py_RETURN_FALSE;
}
Py_RETURN_NONE;
}
};

} // detail
} // pybind11

#endif // LSST_SPHGEOM_PYTHON_TRISTATE_H_
Loading

0 comments on commit d6cd8a6

Please sign in to comment.