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 otherBeginIter = other.
begin();
731 for (
auto const& spn : _spanVector) {
732 while(otherBeginIter != other.
end() && otherBeginIter->getY() < spn.
getY()) {
735 for (
auto otherIter = otherBeginIter; otherIter != other.
end() && otherIter->getY() <= spn.
getY(); ++otherIter) {
736 if (spansOverlap(spn, *otherIter)) {
739 auto newSpan =
Span(spn.
getY(), newMin, newMax);
744 return std::make_shared<SpanSet>(
std::move(tempVec));
750 return std::make_shared<SpanSet>(this->
begin(), this->
end());
753 if (other == *
this) {
754 return std::make_shared<SpanSet>();
763 auto otherBeginIter = other.
begin();
764 for (
auto const& spn : _spanVector) {
766 bool spanStarted =
false;
768 while(otherBeginIter != other.
end() && otherBeginIter->getY() < spn.
getY()) {
771 for (
auto otherIter = otherBeginIter; otherIter != other.
end() && otherIter->getY() <= spn.
getY(); ++otherIter) {
772 if (spansOverlap(spn, *otherIter)) {
788 if (spn.
getMinX() < otherIter->getMinX()) {
795 if (spn.
getMaxX() > otherIter->getMaxX()) {
797 spanBottom = otherIter->getMaxX() + 1;
805 if (spn.
getMaxX() > otherIter->getMaxX()) {
807 spanBottom = otherIter->getMaxX() + 1;
811 if (otherIter->getMaxX() > spn.
getMaxX()) {
827 return std::make_shared<SpanSet>(
std::move(tempVec));
838 tempVec.
insert(tempVec.
end(), _spanVector.begin(), _spanVector.end());
841 return std::make_shared<SpanSet>(
std::move(tempVec));
857 if (_spanVector.empty()) {
858 return std::make_shared<SpanSet>();
875 for (
int i = 0; i < 4; ++i) {
876 if ((std::abs(fromToPoints[i].getX() - fromCorners[i].getX()) > 1.0) ||
877 (std::abs(fromToPoints[i].getY() - fromCorners[i].getY()) > 1.0)) {
878 return std::make_shared<SpanSet>();
882 for (
auto const& tc : toPoints) {
897 newBoxPoints.
clear();
902 auto oldBoxPointIter = oldBoxPoints.cbegin();
904 auto p = *oldBoxPointIter;
905 int const xSource =
std::floor(0.5 + p.getX());
906 int const ySource =
std::floor(0.5 + p.getY());
922 return std::make_shared<SpanSet>(
std::move(tempVec));
925template <
typename ImageT>
934 auto setterFunc = [](
lsst::geom::Point2I const& point, ImageT& out, ImageT in) { out = in; };
938 tmpSpan->applyFunctor(setterFunc,
image,
val);
944 "Footprint Bounds Outside image, set doClip to true");
951 auto targetArray =
target.getArray();
952 auto xy0 =
target.getBBox().getMin();
955 T bitmask) { maskVal |= bitmask; };
962 auto targetArray =
target.getArray();
963 auto xy0 =
target.getBBox().getMin();
966 T bitmask) { maskVal &= ~bitmask; };
972 return maskIntersect<T, false>(*
this, other, bitmask);
977 return maskIntersect<T, true>(*
this, other, bitmask);
982 auto comparator = [bitmask](T pixelValue) {
return (pixelValue & bitmask); };
983 auto spanSetFromMask =
fromMask(other, comparator);
984 return union_(*spanSetFromMask);
989class SpanSetPersistenceHelper {
996 static SpanSetPersistenceHelper
const& get() {
997 static SpanSetPersistenceHelper instance;
1002 SpanSetPersistenceHelper(
const SpanSetPersistenceHelper&) =
delete;
1003 SpanSetPersistenceHelper& operator=(
const SpanSetPersistenceHelper&) =
delete;
1006 SpanSetPersistenceHelper(SpanSetPersistenceHelper&&) =
delete;
1007 SpanSetPersistenceHelper& operator=(SpanSetPersistenceHelper&&) =
delete;
1010 SpanSetPersistenceHelper()
1017std::string getSpanSetPersistenceName() {
return "SpanSet"; }
1019class SpanSetFactory :
public table::io::PersistableFactory {
1022 CatalogVector
const& catalogs)
const override {
1026 auto spansCatalog =
catalogs.front();
1028 auto const&
keys = SpanSetPersistenceHelper::get();
1031 tempVec.
reserve(spansCatalog.size());
1032 for (
auto const&
val : spansCatalog) {
1035 return std::make_shared<SpanSet>(
std::move(tempVec));
1037 explicit SpanSetFactory(
std::string const& name) : table::io::PersistableFactory(name) {}
1042SpanSetFactory registration(getSpanSetPersistenceName());
1049 auto const& keys = SpanSetPersistenceHelper::get();
1050 auto spanCat = handle.
makeCatalog(keys.spanSetSchema);
1052 for (
auto const&
val : *
this) {
1053 auto record = spanCat.addNew();
1054 record->set(keys.spanY,
val.getY());
1055 record->set(keys.spanX0,
val.getX0());
1056 record->set(keys.spanX1,
val.getX1());
1063#define INSTANTIATE_IMAGE_TYPE(T) \
1064 template void SpanSet::setImage<T>(image::Image<T> & image, T val, \
1065 lsst::geom::Box2I const& region = lsst::geom::Box2I(), \
1066 bool doClip = false) const;
1068#define INSTANTIATE_MASK_TYPE(T) \
1069 template void SpanSet::setMask<T>(image::Mask<T> & target, T bitmask) const; \
1070 template void SpanSet::clearMask<T>(image::Mask<T> & target, T bitmask) const; \
1071 template std::shared_ptr<SpanSet> SpanSet::intersect<T>(image::Mask<T> const& other, T bitmask) const; \
1072 template std::shared_ptr<SpanSet> SpanSet::intersectNot<T>(image::Mask<T> const& other, T bitmask) \
1074 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