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"
31 enum /*LIBEVORAL_API*/ OverlapType {
32 OverlapNone, // no overlap
33 OverlapInternal, // the overlap is 100% within the object
34 OverlapStart, // overlap covers start, but ends within
35 OverlapEnd, // overlap begins within and covers end
36 OverlapExternal // overlap extends to (at least) begin+end
40 /*LIBEVORAL_API*/ OverlapType coverage (T sa, T ea, T sb, T eb) {
41 /* OverlapType returned reflects how the second (B)
42 * range overlaps the first (A).
44 * The diagram shows the OverlapType of each possible relative
45 * placement of A and B.
48 * Internal: the start and end points cannot coincide
49 * External: the start and end points can coincide
50 * Start: end points can coincide
51 * End: start points can coincide
53 * Internal disallows start and end point equality, and thus implies
54 * that there are two disjoint portions of A which do not overlap B.
61 * B: |------| External
62 * B: |--------| External
71 * B starts at end of A
80 // seems we are sometimes called with negative length ranges
81 std::cerr << "a - start after end: " << sa << ", " << ea << std::endl;
86 // seems we are sometimes called with negative length ranges
87 std::cerr << "b - start after end: " << sb << ", " << eb << std::endl;
91 if (sb < sa) { // B starts before A
94 } else if (eb == sa) {
99 } else if (eb == ea) {
100 return OverlapExternal;
102 return OverlapExternal;
105 } else if (sb == sa) { // B starts equal to A
108 } else if (eb == ea) {
109 return OverlapExternal;
111 return OverlapExternal;
115 return OverlapInternal;
116 } else if (eb == ea) {
119 if (sb < ea) { // B starts inside A
121 } else if (sb == ea) { // B starts at end of A
123 } else { // sb > ea, B starts after A
129 std::cerr << "unknown overlap type!" << sa << ", " << ea << "; " << sb << ", " << eb << std::endl;
130 assert(!"unknown overlap type!");
134 /** Type to describe a time range */
136 struct /*LIBEVORAL_API*/ Range {
137 Range (T f, T t) : from (f), to (t) {}
138 T from; ///< start of the range
139 T to; ///< end of the range (inclusive: to lies inside the range)
140 bool empty() const { return from == to; }
144 bool operator== (Range<T> a, Range<T> b) {
145 return a.from == b.from && a.to == b.to;
149 class /*LIBEVORAL_API*/ RangeList {
151 RangeList () : _dirty (false) {}
153 typedef std::list<Range<T> > List;
155 List const & get () {
160 void add (Range<T> const & range) {
162 _list.push_back (range);
165 bool empty () const {
166 return _list.empty ();
175 for (typename List::iterator i = _list.begin(); i != _list.end(); ++i) {
176 for (typename List::iterator j = _list.begin(); j != _list.end(); ++j) {
182 if (coverage (i->from, i->to, j->from, j->to) != OverlapNone) {
183 i->from = std::min (i->from, j->from);
184 i->to = std::max (i->to, j->to);
200 /** Type to describe the movement of a time range */
202 struct /*LIBEVORAL_API*/ RangeMove {
203 RangeMove (T f, double l, T t) : from (f), length (l), to (t) {}
204 T from; ///< start of the range
205 double length; ///< length of the range
206 T to; ///< new start of the range
209 /** Subtract the ranges in `sub' from that in `range',
210 * returning the result.
213 RangeList<T> subtract (Range<T> range, RangeList<T> sub)
215 /* Start with the input range */
219 if (sub.empty () || range.empty()) {
223 typename RangeList<T>::List s = sub.get ();
225 /* The basic idea here is to keep a list of the result ranges, and subtract
226 the bits of `sub' from them one by one.
229 for (typename RangeList<T>::List::const_iterator i = s.begin(); i != s.end(); ++i) {
231 /* Here's where we'll put the new current result after subtracting *i from it */
232 RangeList<T> new_result;
234 typename RangeList<T>::List r = result.get ();
236 /* Work on all parts of the current result using this range *i */
237 for (typename RangeList<T>::List::const_iterator j = r.begin(); j != r.end(); ++j) {
239 switch (coverage (j->from, j->to, i->from, i->to)) {
241 /* The thing we're subtracting (*i) does not overlap this bit of the result (*j),
246 case OverlapInternal:
247 /* Internal overlap of the thing we're subtracting (*i) from this bit of the result,
248 so we should end up with two bits of (*j) left over, from the start of (*j) to
249 the start of (*i), and from the end of (*i) to the end of (*j).
251 assert (j->from < i->from);
252 assert (j->to > i->to);
253 new_result.add (Range<T> (j->from, i->from - 1));
254 new_result.add (Range<T> (i->to + 1, j->to));
257 /* The bit we're subtracting (*i) overlaps the start of the bit of the result (*j),
258 * so we keep only the part of of (*j) from after the end of (*i)
260 assert (i->to < j->to);
261 new_result.add (Range<T> (i->to + 1, j->to));
264 /* The bit we're subtracting (*i) overlaps the end of the bit of the result (*j),
265 * so we keep only the part of of (*j) from before the start of (*i)
267 assert (j->from < i->from);
268 new_result.add (Range<T> (j->from, i->from - 1));
270 case OverlapExternal:
271 /* total overlap of the bit we're subtracting with the result bit, so the
272 result bit is completely removed; do nothing */
277 new_result.coalesce ();