1 /* This file is part of Evoral.
2 * Copyright (C) 2008 David Robillard <http://drobilla.net>
3 * Copyright (C) 2000-2008 Paul Davis
5 * Evoral is free software; you can redistribute it and/or modify it under the
6 * terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option) any later
10 * Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #ifndef EVORAL_RANGE_HPP
20 #define EVORAL_RANGE_HPP
25 #include "evoral/visibility.h"
58 enum /*LIBEVORAL_API*/ OverlapType {
59 OverlapNone, // no overlap
60 OverlapInternal, // the overlap is 100% with the object
61 OverlapStart, // overlap covers start, but ends within
62 OverlapEnd, // overlap begins within and covers end
63 OverlapExternal // overlap extends to (at least) begin+end
67 /*LIBEVORAL_API*/ OverlapType coverage (T sa, T ea, T sb, T eb) {
68 /* OverlapType returned reflects how the second (B)
69 range overlaps the first (A).
71 The diagrams show various relative placements
72 of A and B for each OverlapType.
75 Internal: the start and end points cannot coincide
76 External: the start and end points can coincide
77 Start: end points can coincide
78 End: start points can coincide
80 Internal disallows start and end point equality, and thus implies
81 that there are two disjoint portions of A which do not overlap B.
84 // assert(sa <= ea); // seems we are sometimes called with 0-length ranges
86 std::cerr << "a - start after end: " << sa << ", " << ea << std::endl;
92 std::cerr << "b - start after end: " << sb << ", " << eb << std::endl;
99 } else if (eb == sa) {
104 } else if (eb == ea) {
105 return OverlapExternal;
107 return OverlapExternal;
110 } else if (sb == sa) {
113 } else if (eb == ea) {
114 return OverlapExternal;
116 return OverlapExternal;
120 return OverlapInternal;
121 } else if (eb == ea) {
126 } else if (sb == ea) {
135 std::cerr << "unknown overlap type!" << sa << ", " << ea << "; " << sb << ", " << eb << std::endl;
136 // assert(!"unknown overlap type!");
141 |--------------------| A
143 |-----------------| B
148 if ((sb > sa) && (eb < ea)) {
149 return OverlapInternal;
153 |--------------------| A
154 -------------------------- B
155 |----------------------- B
156 ----------------------| B
157 |--------------------| B
159 "B overlaps all of A"
161 if ((sb <= sa) && (eb >= ea)) {
162 return OverlapExternal;
166 |--------------------| A
168 -----------------------| B
171 "B overlaps the start of A"
174 if ((sb <= sa) && (eb >= sa) && (eb <= ea)) {
178 |---------------------| A
180 |----------------------- B
183 "B overlaps the end of A"
185 if ((sb > sa) && (sb < ea) && (eb >= ea)) {
189 // assert(eb < sa || sb > ea);
194 /** Type to describe a time range */
196 struct /*LIBEVORAL_API*/ Range {
197 Range (T f, T t) : from (f), to (t) {}
198 T from; ///< start of the range
199 T to; ///< end of the range
203 bool operator== (Range<T> a, Range<T> b) {
204 return a.from == b.from && a.to == b.to;
208 class /*LIBEVORAL_API*/ RangeList {
210 RangeList () : _dirty (false) {}
212 typedef std::list<Range<T> > List;
214 List const & get () {
219 void add (Range<T> const & range) {
221 _list.push_back (range);
224 bool empty () const {
225 return _list.empty ();
234 for (typename List::iterator i = _list.begin(); i != _list.end(); ++i) {
235 for (typename List::iterator j = _list.begin(); j != _list.end(); ++j) {
241 if (coverage (i->from, i->to, j->from, j->to) != OverlapNone) {
242 i->from = std::min (i->from, j->from);
243 i->to = std::max (i->to, j->to);
259 /** Type to describe the movement of a time range */
261 struct /*LIBEVORAL_API*/ RangeMove {
262 RangeMove (T f, double l, T t) : from (f), length (l), to (t) {}
263 T from; ///< start of the range
264 double length; ///< length of the range
265 T to; ///< new start of the range
268 /** Subtract the ranges in `sub' from that in `range',
269 * returning the result.
272 RangeList<T> subtract (Range<T> range, RangeList<T> sub)
274 /* Start with the input range */
282 typename RangeList<T>::List s = sub.get ();
284 /* The basic idea here is to keep a list of the result ranges, and subtract
285 the bits of `sub' from them one by one.
288 for (typename RangeList<T>::List::const_iterator i = s.begin(); i != s.end(); ++i) {
290 /* Here's where we'll put the new current result after subtracting *i from it */
291 RangeList<T> new_result;
293 typename RangeList<T>::List r = result.get ();
295 /* Work on all parts of the current result using this range *i */
296 for (typename RangeList<T>::List::const_iterator j = r.begin(); j != r.end(); ++j) {
298 switch (coverage (j->from, j->to, i->from, i->to)) {
300 /* The thing we're subtracting does not overlap this bit of the result,
305 case OverlapInternal:
306 /* Internal overlap of the thing we're subtracting from this bit of the result,
307 so we might end up with two bits left over.
309 if (j->from < (i->from - 1)) {
310 new_result.add (Range<T> (j->from, i->from - 1));
312 if (j->to != i->to) {
313 new_result.add (Range<T> (i->to, j->to));
317 /* The bit we're subtracting overlaps the start of the bit of the result */
318 new_result.add (Range<T> (i->to, j->to - 1));
321 /* The bit we're subtracting overlaps the end of the bit of the result */
322 new_result.add (Range<T> (j->from, i->from - 1));
324 case OverlapExternal:
325 /* total overlap of the bit we're subtracting with the result bit, so the
326 result bit is completely removed; do nothing */
331 new_result.coalesce ();