Skip to content

Commit

Permalink
Merge pull request #75 from lsst/tickets/DM-47947
Browse files Browse the repository at this point in the history
DM-47947: add functions for processing concatenations of encoded regions
  • Loading branch information
TallJimbo authored Dec 13, 2024
2 parents 781aacb + f4e84c9 commit 3b1af35
Show file tree
Hide file tree
Showing 35 changed files with 1,829 additions and 196 deletions.
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: check-yaml
args:
Expand All @@ -9,7 +9,7 @@ repos:
- id: trailing-whitespace
- id: check-toml
- repo: https://github.com/psf/black
rev: 24.4.2
rev: 24.10.0
hooks:
- id: black
# It is recommended to specify the latest version of Python
Expand All @@ -23,11 +23,11 @@ repos:
- id: isort
name: isort (python)
- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
rev: 7.1.1
hooks:
- id: flake8
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.4.3
rev: v0.7.4
hooks:
- id: ruff
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
39 changes: 31 additions & 8 deletions include/lsst/sphgeom/CompoundRegion.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

#include <iosfwd>
#include <iterator>
#include <array>
#include <vector>
#include <cstdint>

#include "Region.h"
Expand All @@ -55,9 +55,8 @@ class Ellipse;
class CompoundRegion : public Region {
public:
//@{
/// Construct by copying or taking ownership of operands.
CompoundRegion(Region const &first, Region const &second);
explicit CompoundRegion(std::array<std::unique_ptr<Region>, 2> operands) noexcept;
/// Construct by taking ownership of operands.
explicit CompoundRegion(std::vector<std::unique_ptr<Region>> operands) noexcept;
//@}

CompoundRegion(CompoundRegion const &);
Expand All @@ -68,6 +67,9 @@ class CompoundRegion : public Region {
CompoundRegion &operator=(CompoundRegion const &) = delete;
CompoundRegion &operator=(CompoundRegion &&) = delete;

// Return number of operands
size_t nOperands() const { return _operands.size(); }

// Return references to the operands.
Region const & getOperand(std::size_t n) const {
return *_operands[n];
Expand Down Expand Up @@ -95,11 +97,18 @@ class CompoundRegion : public Region {
std::vector<std::uint8_t> _encode(std::uint8_t tc) const;

// Implementation helper for decode().
static std::array<std::unique_ptr<Region>, 2> _decode(
static std::vector<std::unique_ptr<Region>> _decode(
std::uint8_t tc, std::uint8_t const *buffer, std::size_t nBytes);

// Provide read access to all operands for quick iteration.
std::vector<std::unique_ptr<Region>> const& operands() const { return _operands; }

// Flatten vector of regions in-place.
template <typename Compound>
void flatten_operands();

private:
std::array<std::unique_ptr<Region>, 2> _operands;
std::vector<std::unique_ptr<Region>> _operands;
};

/// UnionRegion is a lazy point-set union of its operands.
Expand All @@ -110,16 +119,23 @@ class UnionRegion : public CompoundRegion {
public:
static constexpr std::uint8_t TYPE_CODE = 'u';

using CompoundRegion::CompoundRegion;
/// Construct by taking ownership of operands.
explicit UnionRegion(std::vector<std::unique_ptr<Region>> operands);

// 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 All @@ -143,16 +159,23 @@ class IntersectionRegion : public CompoundRegion {
public:
static constexpr std::uint8_t TYPE_CODE = 'i';

using CompoundRegion::CompoundRegion;
/// Construct by taking ownership of operands.
explicit IntersectionRegion(std::vector<std::unique_ptr<Region>> operands);

// 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
63 changes: 63 additions & 0 deletions include/lsst/sphgeom/Region.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@
#include <memory>
#include <vector>
#include <cstdint>
#include <string>

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


namespace lsst {
Expand Down Expand Up @@ -100,6 +102,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 +141,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 @@ -149,9 +166,55 @@ class Region {
static std::unique_ptr<Region> decode(std::uint8_t const * buffer, size_t n);
///@}

///@{
/// `decodeBase64` deserializes a Region from an ASCII string produced by
/// encode and then base64-encoding that result.
///
/// This method also interprets ':' as a delimiter for the elements of a
/// UnionRegion, to support cases where a union of region is constructed
/// server-side in a database as a concatenation with that delimiter.
static std::unique_ptr<Region> decodeBase64(std::string const & s) {
return decodeBase64(s);
}

static std::unique_ptr<Region> decodeBase64(std::string_view const & s);
///@}

///@{
/// `decodeOverlapsBase64` evaluates an encoded overlap expression.
///
/// A single overlap expression is formed by concatenating a pair of
/// base64-encoded regions (`Region::encode` then base64 encoding) with
/// '&' as the delimiter. Multiple such pairwise overlap expressions can
/// then be concatenated with '|' as the delimiter to form the logical OR.
static TriState decodeOverlapsBase64(std::string const & s) {
return decodeOverlapsBase64(s);
}

static TriState decodeOverlapsBase64(std::string_view const & s);
///@}

/// `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
Loading

0 comments on commit 3b1af35

Please sign in to comment.