51bool comparePrimaryRun(PrimaryRun
const& first, PrimaryRun
const& second) {
61class ComparePrimaryRunY {
63 bool operator()(PrimaryRun
const& pr,
int yval) {
return pr.y < yval; }
64 bool operator()(
int yval, PrimaryRun
const& pr) {
return yval < pr.y; }
67class ComparePrimaryRunM {
69 bool operator()(PrimaryRun
const& pr,
int mval) {
return pr.m < mval; }
70 bool operator()(
int mval, PrimaryRun
const& pr) {
return mval < pr.m; }
79bool spansOverlap(Span
const& a, Span
const&
b,
bool compareY =
true) {
82 yTruth = a.getY() ==
b.getY();
84 return (yTruth && ((a.getMaxX() >=
b.getMinX() && a.getMinX() <=
b.getMinX()) ||
85 (
b.getMaxX() >= a.getMinX() &&
b.getMinX() <= a.getMinX())))
97bool spansContiguous(Span
const& a, Span
const&
b,
bool compareY =
true) {
100 yTruth = a.getY() ==
b.getY();
102 return (yTruth && ((a.getMaxX() + 1 >=
b.getMinX() && a.getMinX() <=
b.getMinX()) ||
103 (
b.getMaxX() + 1 >= a.getMinX() &&
b.getMinX() <= a.getMinX())))
119template <
typename T,
bool invert>
123 auto maskBBox =
mask.getBBox();
124 for (
auto const& spn : spanSet) {
127 bool started =
false;
130 if (
y < maskBBox.getMinY() ||
y > maskBBox.getMaxY()) {
137 int startX =
std::max(spn.getMinX(), maskBBox.getMinX());
138 int endX =
std::min(spn.getMaxX(), maskBBox.getMaxX());
139 for (
int x = startX;
x <= endX; ++
x) {
145 pixelCompare = !pixelCompare;
162 }
else if (started) {
170 return std::make_shared<SpanSet>(
std::move(newVec));
177SpanSet::SpanSet() : _spanVector(), _bbox(), _area(0) {}
186 for (
int i = beginY; i < _bbox.
getEndY(); ++i) {
187 _spanVector.emplace_back(i, beginX, maxX);
194 if (_spanVector.empty()) {
208 if (_spanVector.size() == 0) {
219void SpanSet::_runNormalize() {
225 std::sort(_spanVector.begin(), _spanVector.end());
230 newSpans.
reserve(_spanVector.size());
232 newSpans.
push_back(*_spanVector.begin());
238 for (
auto iter = ++(_spanVector.begin()); iter != _spanVector.end(); ++iter) {
239 auto& newSpansEnd = newSpans.
back();
240 if (spansContiguous(newSpansEnd, *iter)) {
241 newSpansEnd =
Span(newSpansEnd.getY(),
std::min(newSpansEnd.getMinX(), iter->getMinX()),
242 std::max(newSpansEnd.getMaxX(), iter->getMaxX()));
252void SpanSet::_initialize() {
264 int minX = _spanVector[0].getMinX();
265 int maxX = _spanVector[0].getMaxX();
268 for (
const auto& span : _spanVector) {
269 if (span.getMinX() < minX) {
270 minX = span.getMinX();
272 if (span.getMaxX() > maxX) {
273 maxX = span.getMaxX();
276 _area += span.getMaxX() - span.getMinX() + 1;
324 auto currentIndex = spn.
getY();
325 if (currentIndex > 0) {
327 for (
auto const& tup : sortMap[currentIndex - 1]) {
328 if (!labelVector[tup.first] && spansOverlap(spn, *(tup.second),
false)) {
329 labelVector[tup.first] = currentLabel;
330 _label(*(tup.second), labelVector, currentLabel, sortMap);
334 if (currentIndex <= _spanVector.back().getY() - 1) {
336 for (
auto& tup : sortMap[currentIndex + 1]) {
337 if (!labelVector[tup.first] && spansOverlap(spn, *(tup.second),
false)) {
338 labelVector[tup.first] = currentLabel;
339 _label(*(tup.second), labelVector, currentLabel, sortMap);
352 for (
auto const& spn : _spanVector) {
356 for (
auto const& currentSpan : _spanVector) {
357 if (!labelVector[index]) {
358 labelVector[index] = currentLabel;
359 _label(currentSpan, labelVector, currentLabel, sortMap);
374 auto labeledPair = _makeLabels();
379 return labeledPair.second <= 2;
383 auto labeledPair = _makeLabels();
384 auto labels = labeledPair.first;
385 auto numberOfLabels = labeledPair.second;
393 if (numberOfLabels == 1) {
394 subRegions.
push_back(std::make_shared<SpanSet>());
397 subRegions.
reserve(numberOfLabels - 1);
401 for (
std::size_t i = 0; i < _spanVector.size(); ++i) {
402 subSpanLists[labels[i] - 1].
push_back(_spanVector[i]);
405 for (
std::size_t i = 0; i < numberOfLabels - 1; ++i) {
406 subRegions.
push_back(std::make_shared<SpanSet>(subSpanLists[i]));
421 return makeShift(
x,
y);
426 return makeShift(offset.getX(), offset.getY());
432 tempVec.
reserve(_spanVector.size());
433 for (
auto const& spn : _spanVector) {
436 return std::make_shared<SpanSet>(
std::move(tempVec),
false);
444 for (
auto const& spn : _spanVector) {
451 return std::make_shared<SpanSet>(
std::move(tempVec),
false);
456 for (
auto const& otherSpan : other) {
457 for (
auto const& spn : _spanVector) {
458 if (spansOverlap(otherSpan, spn)) {
472 for (
auto const& otherSpn : other) {
474 for (
auto const& spn : _spanVector) {
494 for (
auto& spn : _spanVector) {
505 double xc = 0, yc = 0;
506 for (
auto const& spn : _spanVector) {
507 int const y = spn.
getY();
510 int const npix = x1 - x0 + 1;
513 xc += npix * 0.5 * (x1 + x0);
524 double const xc = cen.getX();
525 double const yc = cen.getY();
527 double sumxx = 0, sumxy = 0, sumyy = 0;
528 for (
auto const& spn : _spanVector) {
529 int const y = spn.
getY();
530 int const x0 = spn.
getX0();
531 int const x1 = spn.
getX1();
532 int const npix = x1 - x0 + 1;
534 for (
int x = x0;
x <= x1; ++
x) {
535 sumxx += (
x - xc) * (
x - xc);
537 sumxy += npix * (0.5 * (x1 + x0) - xc) * (
y - yc);
538 sumyy += npix * (
y - yc) * (
y - yc);
548 return dilated(*stencilToSpanSet);
553 if (other.
size() == 0) {
554 return std::make_shared<SpanSet>(_spanVector.begin(), _spanVector.end(),
false);
560 for (
auto const& spn : _spanVector) {
561 for (
auto const& otherSpn : other) {
562 int const xmin = spn.
getMinX() + otherSpn.getMinX();
563 int const xmax = spn.
getMaxX() + otherSpn.getMaxX();
564 int const yval = spn.
getY() + otherSpn.getY();
569 return std::make_shared<SpanSet>(
std::move(tempVec));
576 return eroded(*stencilToSpanSet);
581 if (other.
size() == 0 || this->size() == 0) {
582 return std::make_shared<SpanSet>(_spanVector.begin(), _spanVector.end(),
false);
590 for (
auto const& spn : _spanVector) {
592 for (
auto const& otherSpn : other) {
593 if ((otherSpn.getMaxX() - otherSpn.getMinX()) <= (spn.
getMaxX() - spn.
getMinX())) {
596 int y = spn.
getY() - otherSpn.getY();
607 for (
int y = primaryRuns.
front().y;
y <= primaryRuns.
back().y; ++
y) {
616 if (
std::distance(yRange.first, yRange.second) < otherYRange) {
627 for (
int m = 0;
m < otherYRange; ++
m) {
628 auto mRange =
std::equal_range(yRange.first, yRange.second,
m, ComparePrimaryRunM());
629 if ((mRange.first == mRange.second)) {
636 int startX = mRange.first->xmin;
637 int endX = mRange.first->xmax;
638 for (
auto run = mRange.first + 1; run != mRange.second; ++run) {
639 if (run->xmin > endX) {
641 candidateRuns.
push_back(PrimaryRun{
m,
y, startX, endX});
649 candidateRuns.
push_back(PrimaryRun{
m,
y, startX, endX});
658 for (
auto& good : goodRuns) {
659 for (
auto& cand : candidateRuns) {
660 int start =
std::max(good.xmin, cand.xmin);
671 for (
auto& run : goodRuns) {
675 return std::make_shared<SpanSet>(
std::move(tempVec));
680 return _spanVector == other._spanVector;
685 return _spanVector != other._spanVector;
694 for (
auto dy = -r; dy <= r; ++dy) {
695 int dx =
static_cast<int>(sqrt(r * r - dy * dy));
696 tempVec.
emplace_back(dy + offset.getY(), -dx + offset.getX(), dx + offset.getX());
700 for (
auto dy = -r; dy <= r; ++dy) {
701 int dx = r - abs(dy);
702 tempVec.
emplace_back(dy + offset.getY(), -dx + offset.getX(), dx + offset.getX());
706 for (
auto dy = -r; dy <= r; ++dy) {
708 tempVec.
emplace_back(dy + offset.getY(), -dx + offset.getX(), dx + offset.getX());
712 return std::make_shared<SpanSet>(
std::move(tempVec),
false);
717 return std::make_shared<SpanSet>(pr.
begin(), pr.
end());
723 return std::make_shared<SpanSet>();
726 if (other == *
this) {
727 return std::make_shared<SpanSet>(this->_spanVector);
730 auto otherIter = other.
begin();
731 for (
auto const& spn : _spanVector) {
732 while (otherIter != other.
end() && otherIter->getY() <= spn.
getY()) {
733 if (spansOverlap(spn, *otherIter)) {
736 auto newSpan =
Span(spn.
getY(), newMin, newMax);
742 return std::make_shared<SpanSet>(
std::move(tempVec));
748 return std::make_shared<SpanSet>(this->
begin(), this->
end());
751 if (other == *
this) {
752 return std::make_shared<SpanSet>();
761 auto otherIter = other.
begin();
762 for (
auto const& spn : _spanVector) {
764 bool spanStarted =
false;
766 while (otherIter != other.
end() && otherIter->getY() <= spn.
getY()) {
767 if (spansOverlap(spn, *otherIter)) {
783 if (spn.
getMinX() < otherIter->getMinX()) {
790 if (spn.
getMaxX() > otherIter->getMaxX()) {
792 spanBottom = otherIter->getMaxX() + 1;
800 if (spn.
getMaxX() > otherIter->getMaxX()) {
802 spanBottom = otherIter->getMaxX() + 1;
806 if (otherIter->getMaxX() > spn.
getMaxX()) {
823 return std::make_shared<SpanSet>(
std::move(tempVec));
834 tempVec.
insert(tempVec.
end(), _spanVector.begin(), _spanVector.end());
837 return std::make_shared<SpanSet>(
std::move(tempVec));
853 if (_spanVector.empty()) {
854 return std::make_shared<SpanSet>();
871 for (
int i = 0; i < 4; ++i) {
872 if ((std::abs(fromToPoints[i].getX() - fromCorners[i].getX()) > 1.0) ||
873 (std::abs(fromToPoints[i].getY() - fromCorners[i].getY()) > 1.0)) {
874 return std::make_shared<SpanSet>();
878 for (
auto const& tc : toPoints) {
893 newBoxPoints.
clear();
898 auto oldBoxPointIter = oldBoxPoints.cbegin();
900 auto p = *oldBoxPointIter;
901 int const xSource =
std::floor(0.5 + p.getX());
902 int const ySource =
std::floor(0.5 + p.getY());
918 return std::make_shared<SpanSet>(
std::move(tempVec));
921template <
typename ImageT>
930 auto setterFunc = [](
lsst::geom::Point2I const& point, ImageT& out, ImageT in) { out = in; };
934 tmpSpan->applyFunctor(setterFunc,
image,
val);
940 "Footprint Bounds Outside image, set doClip to true");
947 auto targetArray =
target.getArray();
948 auto xy0 =
target.getBBox().getMin();
951 T bitmask) { maskVal |= bitmask; };
958 auto targetArray =
target.getArray();
959 auto xy0 =
target.getBBox().getMin();
962 T bitmask) { maskVal &= ~bitmask; };
968 return maskIntersect<T, false>(*
this, other, bitmask);
973 return maskIntersect<T, true>(*
this, other, bitmask);
978 auto comparator = [bitmask](T pixelValue) {
return (pixelValue & bitmask); };
979 auto spanSetFromMask =
fromMask(other, comparator);
980 return union_(*spanSetFromMask);
985class SpanSetPersistenceHelper {
992 static SpanSetPersistenceHelper
const& get() {
993 static SpanSetPersistenceHelper instance;
998 SpanSetPersistenceHelper(
const SpanSetPersistenceHelper&) =
delete;
999 SpanSetPersistenceHelper& operator=(
const SpanSetPersistenceHelper&) =
delete;
1002 SpanSetPersistenceHelper(SpanSetPersistenceHelper&&) =
delete;
1003 SpanSetPersistenceHelper& operator=(SpanSetPersistenceHelper&&) =
delete;
1006 SpanSetPersistenceHelper()
1013std::string getSpanSetPersistenceName() {
return "SpanSet"; }
1015class SpanSetFactory :
public table::io::PersistableFactory {
1018 CatalogVector
const& catalogs)
const override {
1022 auto spansCatalog = catalogs.front();
1024 auto const&
keys = SpanSetPersistenceHelper::get();
1027 tempVec.
reserve(spansCatalog.size());
1028 for (
auto const&
val : spansCatalog) {
1031 return std::make_shared<SpanSet>(
std::move(tempVec));
1033 explicit SpanSetFactory(
std::string const& name) : table::io::PersistableFactory(name) {}
1038SpanSetFactory registration(getSpanSetPersistenceName());
1045 auto const& keys = SpanSetPersistenceHelper::get();
1046 auto spanCat = handle.
makeCatalog(keys.spanSetSchema);
1048 for (
auto const&
val : *
this) {
1049 auto record = spanCat.addNew();
1050 record->set(keys.spanY,
val.getY());
1051 record->set(keys.spanX0,
val.getX0());
1052 record->set(keys.spanX1,
val.getX1());
1059#define INSTANTIATE_IMAGE_TYPE(T) \
1060 template void SpanSet::setImage<T>(image::Image<T> & image, T val, \
1061 lsst::geom::Box2I const& region = lsst::geom::Box2I(), \
1062 bool doClip = false) const;
1064#define INSTANTIATE_MASK_TYPE(T) \
1065 template void SpanSet::setMask<T>(image::Mask<T> & target, T bitmask) const; \
1066 template void SpanSet::clearMask<T>(image::Mask<T> & target, T bitmask) const; \
1067 template std::shared_ptr<SpanSet> SpanSet::intersect<T>(image::Mask<T> const& other, T bitmask) const; \
1068 template std::shared_ptr<SpanSet> SpanSet::intersectNot<T>(image::Mask<T> const& other, T bitmask) \
1070 template std::shared_ptr<SpanSet> SpanSet::union_<T>(image::Mask<T> const& other, T bitmask) const;
Key< Flag > const & target
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
#define INSTANTIATE_MASK_TYPE(T)
#define INSTANTIATE_IMAGE_TYPE(T)
table::Schema spanSetSchema
#define LSST_ARCHIVE_ASSERT(EXPR)
An assertion macro used to validate the structure of an InputArchive.
A range of pixels within one row of an Image.
int getMinX() const noexcept
Minimum x-value.
int getMaxX() const noexcept
Maximum x-value.
bool contains(int x) const noexcept
int getY() const noexcept
Return the y-value.
int getX0() const noexcept
Return the starting x-value.
int getX1() const noexcept
Return the ending x-value.
A compact representation of a collection of pixels.
bool isContiguous() const
Defines if the SpanSet is simply contiguous.
SpanSet()
Default constructor.
std::shared_ptr< SpanSet > shiftedBy(int x, int y) const
Return a new SpanSet shifted by specified amount.
static std::shared_ptr< geom::SpanSet > fromMask(image::Mask< T > const &mask, UnaryPredicate comparator=details::AnyBitSetFunctor< T >())
Create a SpanSet from a mask.
static std::shared_ptr< geom::SpanSet > fromShape(int r, Stencil s=Stencil::CIRCLE, lsst::geom::Point2I offset=lsst::geom::Point2I())
Factory function for creating SpanSets from a Stencil.
void setImage(image::Image< ImageT > &image, ImageT val, lsst::geom::Box2I const ®ion=lsst::geom::Box2I(), bool doClip=false) const
Set the values of an Image at points defined by the SpanSet.
std::shared_ptr< SpanSet > union_(SpanSet const &other) const
Create a new SpanSet that contains all points from two SpanSets.
std::shared_ptr< SpanSet > transformedBy(lsst::geom::LinearTransform const &t) const
Return a new SpanSet who's pixels are the product of applying the specified transformation.
std::shared_ptr< SpanSet > clippedTo(lsst::geom::Box2I const &box) const
Return a new SpanSet which has all pixel values inside specified box.
void write(OutputArchiveHandle &handle) const override
Write the object to one or more catalogs.
const_iterator end() const
std::shared_ptr< SpanSet > intersect(SpanSet const &other) const
Determine the common points between two SpanSets, and create a new SpanSet.
void applyFunctor(Functor &&func, Args &&... args) const
Apply functor on individual elements from the supplied parameters.
std::shared_ptr< SpanSet > eroded(int r, Stencil s=Stencil::CIRCLE) const
Perform a set erosion, and return a new object.
lsst::geom::Box2I getBBox() const
Return a new integer box which is the minimum size to contain the pixels.
std::shared_ptr< SpanSet > dilated(int r, Stencil s=Stencil::CIRCLE) const
Perform a set dilation operation, and return a new object.
const_reference front() const
void setMask(lsst::afw::image::Mask< T > &target, T bitmask) const
Set a Mask at pixels defined by the SpanSet.
std::vector< std::shared_ptr< geom::SpanSet > > split() const
Split a discontinuous SpanSet into multiple SpanSets which are contiguous.
bool overlaps(SpanSet const &other) const
Specifies if this SpanSet overlaps with another SpanSet.
std::string getPersistenceName() const override
Return the unique name used to persist this object and look up its factory.
const_iterator begin() const
bool operator!=(SpanSet const &other) const
void clearMask(lsst::afw::image::Mask< T > &target, T bitmask) const
Unset a Mask at pixels defined by the SpanSet.
lsst::geom::Point2D computeCentroid() const
Compute the point about which the SpanSet's first moment is zero.
bool contains(SpanSet const &other) const
Check if a SpanSet instance entirely contains another SpanSet.
std::shared_ptr< geom::SpanSet > findEdgePixels() const
Select pixels within the SpanSet which touch its edge.
ellipses::Quadrupole computeShape() const
Compute the shape parameters for the distribution of points in the SpanSet.
bool operator==(SpanSet const &other) const
Compute equality between two SpanSets.
std::shared_ptr< SpanSet > intersectNot(SpanSet const &other) const
Determine the common points between a SpanSet and the logical inverse of a second SpanSet and return ...
const_reference back() const
size_type getArea() const
Return the number of pixels in the SpanSet.
typename ndarray::Array< T, N, C >::Reference::Reference Reference
An ellipse defined by an arbitrary BaseCore and a center point.
A pixelized region containing all pixels whose centers are within an Ellipse.
Iterator begin() const
Iterator range over Spans whose pixels are within the Ellipse.
An ellipse core with quadrupole moments as parameters.
A class to represent a 2-dimensional array of pixels.
Represent a 2-dimensional array of bitmask pixels.
void reserve(size_type n)
Increase the capacity of the catalog to the given size.
An object passed to Persistable::write to allow it to persist itself.
void saveCatalog(BaseCatalog const &catalog)
Save a catalog in the archive.
BaseCatalog makeCatalog(Schema const &schema)
Return a new, empty catalog with the given schema.
static std::shared_ptr< T > dynamicCast(std::shared_ptr< Persistable > const &ptr)
Dynamically cast a shared_ptr.
A floating-point coordinate rectangle geometry.
void include(Point2D const &point) noexcept
Expand this to ensure that this->contains(point).
An integer coordinate rectangle.
int getBeginX() const noexcept
int getMinY() const noexcept
bool overlaps(Box2I const &other) const noexcept
Return true if any points in other are also in this.
bool isEmpty() const noexcept
Return true if the box contains no points.
int getEndY() const noexcept
int getMinX() const noexcept
int getWidth() const noexcept
int getBeginY() const noexcept
int getMaxX() const noexcept
std::vector< Point2I > getCorners() const
Get the corner points.
int getMaxY() const noexcept
int getEndX() const noexcept
Reports attempts to access elements outside a valid range of indices.
T emplace_back(T... args)
std::shared_ptr< TransformPoint2ToPoint2 > makeTransform(lsst::geom::AffineTransform const &affine)
Wrap an lsst::geom::AffineTransform as a Transform.
Stencil
An enumeration class which describes the shapes.
Point< double, 2 > Point2D
details::ImageNdGetter< T, inA, inB > ndImage(ndarray::Array< T, inA, inB > const &array, lsst::geom::Point2I xy0=lsst::geom::Point2I())
Marks a ndarray to be interpreted as an image when applying a functor from a SpanSet.
std::shared_ptr< table::io::Persistable > read(table::io::InputArchive const &archive, table::io::CatalogVector const &catalogs) const override