123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/DisjointIntervals.h>
- #include <functional>
- namespace WwiseGTE
- {
- // Compute Boolean operations of disjoint sets of half-open rectangles of
- // the form [xmin,xmax)x[ymin,ymax) with xmin < xmax and ymin < ymax.
- template <typename Scalar>
- class DisjointRectangles
- {
- public:
- // Convenient type definition.
- typedef DisjointIntervals<Scalar> ISet;
- // Construction and destruction. The non-default constructor requires
- // that xmin < xmax and ymin < ymax.
- DisjointRectangles()
- :
- mNumRectangles(0)
- {
- }
- DisjointRectangles(Scalar const& xmin, Scalar const& xmax, Scalar const& ymin, Scalar const& ymax)
- {
- if (xmin < xmax && ymin < ymax)
- {
- mNumRectangles = 1;
- mStrips.push_back(Strip(ymin, ymax, ISet(xmin, xmax)));
- }
- else
- {
- mNumRectangles = 0;
- }
- }
- ~DisjointRectangles()
- {
- }
- // Copy operations.
- DisjointRectangles(DisjointRectangles const& other)
- {
- *this = other;
- }
- DisjointRectangles& operator=(DisjointRectangles const& other)
- {
- mNumRectangles = other.mNumRectangles;
- mStrips = other.mStrips;
- return *this;
- }
- // Move operations.
- DisjointRectangles(DisjointRectangles&& other)
- {
- *this = std::move(other);
- }
- DisjointRectangles& operator=(DisjointRectangles&& other)
- {
- mNumRectangles = other.mNumRectangles;
- mStrips = std::move(other.mStrips);
- return *this;
- }
- // The rectangle set consists of y-strips of interval sets.
- class Strip
- {
- public:
- // Construction and destruction.
- Strip()
- :
- ymin((Scalar)0),
- ymax((Scalar)0)
- {
- }
- Strip(Scalar const& inYMin, Scalar const& inYMax, ISet const& inIntervalSet)
- :
- ymin(inYMin),
- ymax(inYMax),
- intervalSet(inIntervalSet)
- {
- }
- ~Strip()
- {
- }
- // Copy operations.
- Strip(Strip const& other)
- {
- *this = other;
- }
- Strip& operator=(Strip const& other)
- {
- ymin = other.ymin;
- ymax = other.ymax;
- intervalSet = other.intervalSet;
- return *this;
- }
- // Move operations.
- Strip(Strip&& other)
- {
- *this = std::move(other);
- }
- Strip& operator=(Strip&& other)
- {
- ymin = other.ymin;
- ymax = other.ymax;
- intervalSet = std::move(other.intervalSet);
- other.ymin = (Scalar)0;
- other.ymax = (Scalar)0;
- return *this;
- }
- // Member access.
- Scalar ymin, ymax;
- ISet intervalSet;
- };
- // The number of rectangles in the set.
- inline int GetNumRectangles() const
- {
- return mNumRectangles;
- }
- // The i-th rectangle is [xmin,xmax)x[ymin,ymax). The values xmin,
- // xmax, ymin and ymax are valid when 0 <= i < GetNumRectangles().
- bool GetRectangle(int i, Scalar& xmin, Scalar& xmax, Scalar& ymin, Scalar& ymax) const
- {
- int totalQuantity = 0;
- for (auto const& strip : mStrips)
- {
- ISet const& intervalSet = strip.intervalSet;
- int xQuantity = intervalSet.GetNumIntervals();
- int nextTotalQuantity = totalQuantity + xQuantity;
- if (i < nextTotalQuantity)
- {
- i -= totalQuantity;
- intervalSet.GetInterval(i, xmin, xmax);
- ymin = strip.ymin;
- ymax = strip.ymax;
- return true;
- }
- totalQuantity = nextTotalQuantity;
- }
- return false;
- }
- // Make this set empty.
- inline void Clear()
- {
- mNumRectangles = 0;
- mStrips.clear();
- }
- // The number of y-strips in the set.
- inline int GetNumStrips() const
- {
- return static_cast<int>(mStrips.size());
- }
- // The i-th strip. The returned values are valid when
- // 0 <= i < GetStripQuantity().
- bool GetStrip(int i, Scalar& ymin, Scalar& ymax, ISet& xIntervalSet) const
- {
- if (0 <= i && i < GetNumStrips())
- {
- Strip const& strip = mStrips[i];
- ymin = strip.ymin;
- ymax = strip.ymax;
- xIntervalSet = strip.intervalSet;
- return true;
- }
- return false;
- }
- // Insert [xmin,xmax)x[ymin,ymax) into the set. This is a Boolean
- // union operation. The operation is successful only when xmin < xmax
- // and ymin < ymax.
- bool Insert(Scalar const& xmin, Scalar const& xmax, Scalar const& ymin, Scalar const& ymax)
- {
- if (xmin < xmax && ymin < ymax)
- {
- DisjointRectangles input(xmin, xmax, ymin, ymax);
- DisjointRectangles output = *this | input;
- *this = std::move(output);
- return true;
- }
- return false;
- }
- // Remove [xmin,xmax)x[ymin,ymax) from the set. This is a Boolean
- // difference operation. The operation is successful only when
- // xmin < xmax and ymin < ymax.
- bool Remove(Scalar const& xmin, Scalar const& xmax, Scalar const& ymin, Scalar const& ymax)
- {
- if (xmin < xmax && ymin < ymax)
- {
- DisjointRectangles input(xmin, xmax, ymin, ymax);
- DisjointRectangles output = *this - input;
- *this = std::move(output);
- return true;
- }
- return false;
- }
- // Get the union of the rectangle sets sets, input0 union input1.
- friend DisjointRectangles operator|(DisjointRectangles const& input0, DisjointRectangles const& input1)
- {
- return Execute(
- [](ISet const& i0, ISet const& i1) { return i0 | i1; },
- true, true, input0, input1);
- }
- // Get the intersection of the rectangle sets, input0 intersect is1.
- friend DisjointRectangles operator&(DisjointRectangles const& input0, DisjointRectangles const& input1)
- {
- return Execute(
- [](ISet const& i0, ISet const& i1) { return i0 & i1; },
- false, false, input0, input1);
- }
- // Get the differences of the rectangle sets, input0 minus input1.
- friend DisjointRectangles operator-(DisjointRectangles const& input0, DisjointRectangles const& input1)
- {
- return Execute(
- [](ISet const& i0, ISet const& i1) { return i0 - i1; },
- false, true, input0, input1);
- }
- // Get the exclusive or of the rectangle sets, input0 xor input1 =
- // (input0 minus input1) or (input1 minus input0).
- friend DisjointRectangles operator^(DisjointRectangles const& input0, DisjointRectangles const& input1)
- {
- return Execute(
- [](ISet const& i0, ISet const& i1) { return i0 ^ i1; },
- true, true, input0, input1);
- }
- private:
- static DisjointRectangles Execute(
- std::function<ISet(ISet const&, ISet const&)> const& operation,
- bool unionExclusiveOr, bool unionExclusiveOrDifference,
- DisjointRectangles const& input0, DisjointRectangles const& input1)
- {
- DisjointRectangles output;
- size_t const numStrips0 = input0.GetNumStrips();
- size_t const numStrips1 = input1.GetNumStrips();
- size_t i0 = 0, i1 = 0;
- bool getOriginal0 = true, getOriginal1 = true;
- Scalar ymin0 = (Scalar)0;
- Scalar ymax0 = (Scalar)0;
- Scalar ymin1 = (Scalar)0;
- Scalar ymax1 = (Scalar)0;
- while (i0 < numStrips0 && i1 < numStrips1)
- {
- ISet const& intr0 = input0.mStrips[i0].intervalSet;
- if (getOriginal0)
- {
- ymin0 = input0.mStrips[i0].ymin;
- ymax0 = input0.mStrips[i0].ymax;
- }
- ISet const& intr1 = input1.mStrips[i1].intervalSet;
- if (getOriginal1)
- {
- ymin1 = input1.mStrips[i1].ymin;
- ymax1 = input1.mStrips[i1].ymax;
- }
- // Case 1.
- if (ymax1 <= ymin0)
- {
- // operator(empty,strip1)
- if (unionExclusiveOr)
- {
- output.mStrips.push_back(Strip(ymin1, ymax1, intr1));
- }
- ++i1;
- getOriginal0 = false;
- getOriginal1 = true;
- continue; // using next ymin1/ymax1
- }
- // Case 11.
- if (ymin1 >= ymax0)
- {
- // operator(strip0,empty)
- if (unionExclusiveOrDifference)
- {
- output.mStrips.push_back(Strip(ymin0, ymax0, intr0));
- }
- ++i0;
- getOriginal0 = true;
- getOriginal1 = false;
- continue; // using next ymin0/ymax0
- }
- // Reduce cases 2, 3, 4 to cases 5, 6, 7.
- if (ymin1 < ymin0)
- {
- // operator(empty,[ymin1,ymin0))
- if (unionExclusiveOr)
- {
- output.mStrips.push_back(Strip(ymin1, ymin0, intr1));
- }
- ymin1 = ymin0;
- getOriginal1 = false;
- }
- // Reduce cases 8, 9, 10 to cases 5, 6, 7.
- if (ymin1 > ymin0)
- {
- // operator([ymin0,ymin1),empty)
- if (unionExclusiveOrDifference)
- {
- output.mStrips.push_back(Strip(ymin0, ymin1, intr0));
- }
- ymin0 = ymin1;
- getOriginal0 = false;
- }
- // Case 5.
- if (ymax1 < ymax0)
- {
- // operator(strip0,[ymin1,ymax1))
- auto result = operation(intr0, intr1);
- output.mStrips.push_back(Strip(ymin1, ymax1, result));
- ymin0 = ymax1;
- ++i1;
- getOriginal0 = false;
- getOriginal1 = true;
- continue; // using next ymin1/ymax1
- }
- // Case 6.
- if (ymax1 == ymax0)
- {
- // operator(strip0,[ymin1,ymax1))
- auto result = operation(intr0, intr1);
- output.mStrips.push_back(Strip(ymin1, ymax1, result));
- ++i0;
- ++i1;
- getOriginal0 = true;
- getOriginal1 = true;
- continue; // using next ymin0/ymax0 and ymin1/ymax1
- }
- // Case 7.
- if (ymax1 > ymax0)
- {
- // operator(strip0,[ymin1,ymax0))
- auto result = operation(intr0, intr1);
- output.mStrips.push_back(Strip(ymin1, ymax0, result));
- ymin1 = ymax0;
- ++i0;
- getOriginal0 = true;
- getOriginal1 = false;
- // continue; using current ymin1/ymax1
- }
- }
- if (unionExclusiveOrDifference)
- {
- while (i0 < numStrips0)
- {
- if (getOriginal0)
- {
- ymin0 = input0.mStrips[i0].ymin;
- ymax0 = input0.mStrips[i0].ymax;
- }
- else
- {
- getOriginal0 = true;
- }
- // operator(strip0,empty)
- output.mStrips.push_back(Strip(ymin0, ymax0,
- input0.mStrips[i0].intervalSet));
- ++i0;
- }
- }
- if (unionExclusiveOr)
- {
- while (i1 < numStrips1)
- {
- if (getOriginal1)
- {
- ymin1 = input1.mStrips[i1].ymin;
- ymax1 = input1.mStrips[i1].ymax;
- }
- else
- {
- getOriginal1 = true;
- }
- // operator(empty,strip1)
- output.mStrips.push_back(Strip(ymin1, ymax1,
- input1.mStrips[i1].intervalSet));
- ++i1;
- }
- }
- output.ComputeRectangleQuantity();
- return output;
- }
- void ComputeRectangleQuantity()
- {
- mNumRectangles = 0;
- for (auto strip : mStrips)
- {
- mNumRectangles += strip.intervalSet.GetNumIntervals();
- }
- }
- // The number of rectangles in the set.
- int mNumRectangles;
- // The y-strips of the set, each containing an x-interval set.
- std::vector<Strip> mStrips;
- };
- }
|