Skip to content

Commit

Permalink
Merge pull request #757 from lsst/tickets/DM-47945
Browse files Browse the repository at this point in the history
DM-47945: Fix bug in non-contiguous SpanSet intersection and difference
  • Loading branch information
fred3m authored Dec 4, 2024
2 parents 3280fe6 + be0c884 commit 9bd4706
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 6 deletions.
16 changes: 10 additions & 6 deletions src/geom/SpanSet.cc
Original file line number Diff line number Diff line change
Expand Up @@ -727,16 +727,18 @@ std::shared_ptr<SpanSet> SpanSet::intersect(SpanSet const& other) const {
return std::make_shared<SpanSet>(this->_spanVector);
}
std::vector<Span> tempVec;
auto otherIter = other.begin();
auto otherBeginIter = other.begin();
for (auto const& spn : _spanVector) {
while (otherIter != other.end() && otherIter->getY() <= spn.getY()) {
while(otherBeginIter != other.end() && otherBeginIter->getY() < spn.getY()) {
++otherBeginIter;
}
for (auto otherIter = otherBeginIter; otherIter != other.end() && otherIter->getY() <= spn.getY(); ++otherIter) {
if (spansOverlap(spn, *otherIter)) {
auto newMin = std::max(spn.getMinX(), otherIter->getMinX());
auto newMax = std::min(spn.getMaxX(), otherIter->getMaxX());
auto newSpan = Span(spn.getY(), newMin, newMax);
tempVec.push_back(newSpan);
}
++otherIter;
}
}
return std::make_shared<SpanSet>(std::move(tempVec));
Expand All @@ -758,12 +760,15 @@ std::shared_ptr<SpanSet> SpanSet::intersectNot(SpanSet const& other) const {
* or with other containing this b1| a1| a2| b2|
*/
std::vector<Span> tempVec;
auto otherIter = other.begin();
auto otherBeginIter = other.begin();
for (auto const& spn : _spanVector) {
bool added = false;
bool spanStarted = false;
int spanBottom = 0;
while (otherIter != other.end() && otherIter->getY() <= spn.getY()) {
while(otherBeginIter != other.end() && otherBeginIter->getY() < spn.getY()) {
++otherBeginIter;
}
for (auto otherIter = otherBeginIter; otherIter != other.end() && otherIter->getY() <= spn.getY(); ++otherIter) {
if (spansOverlap(spn, *otherIter)) {
added = true;
/* To handle one span containing the other, the spans will be added
Expand Down Expand Up @@ -806,7 +811,6 @@ std::shared_ptr<SpanSet> SpanSet::intersectNot(SpanSet const& other) const {
if (otherIter->getMaxX() > spn.getMaxX()) {
break;
}
++otherIter;
}
// Check if a span has been started but not finished, if that is the case that means there are
// no further spans on this row to consider and the span should be closed and added
Expand Down
28 changes: 28 additions & 0 deletions tests/test_spanSets.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,20 @@ def testIntersection(self):
for expected, val in zip(expectedYRange, spanSetIntersectMask):
self.assertEqual(expected, val.getY())

def testIntersectionWithGap(self):
# This test was created in DM-47945 to fix a bug where the
# intersection of two spansets where multiple spans have the same
# y-value would fail.
spans1 = afwGeom.SpanSet([afwGeom.Span(1, 0, 3), afwGeom.Span(1, 5, 7)])
spans2 = afwGeom.SpanSet([afwGeom.Span(1, 2, 6)])
intersection = spans1.intersect(spans2)
trueIntersection = afwGeom.SpanSet([afwGeom.Span(1, 2, 3), afwGeom.Span(1, 5, 6)])

self.assertEqual(len(intersection), 2)

for a, b in zip(intersection, trueIntersection):
self.assertEqual(a, b)

def testIntersectNot(self):
firstSpanSet, secondSpanSet = self.makeOverlapSpanSets()

Expand Down Expand Up @@ -322,6 +336,20 @@ def testIntersectNot(self):
targetSpanSet.contains(point):
self.assertTrue(resultSpanSet.contains(point))

def testIntersectNotWithGap(self):
# This test was created in DM-47945 to fix a bug where the
# intersection of two spansets where multiple spans have the same
# y-value would fail.
spans1 = afwGeom.SpanSet([afwGeom.Span(1, 0, 3), afwGeom.Span(1, 5, 7)])
spans2 = afwGeom.SpanSet([afwGeom.Span(1, 2, 6)])
intersectNot = spans1.intersectNot(spans2)
trueIntersectNot = afwGeom.SpanSet([afwGeom.Span(1, 0, 1), afwGeom.Span(1, 7, 7)])

self.assertEqual(len(intersectNot), 2)

for a, b in zip(intersectNot, trueIntersectNot):
self.assertEqual(a, b)

def testUnion(self):
firstSpanSet, secondSpanSet = self.makeOverlapSpanSets()

Expand Down

0 comments on commit 9bd4706

Please sign in to comment.