use interval tree for list of spanners

This commit is contained in:
ws 2013-07-05 11:23:52 +02:00
parent 30fc3f20fc
commit 3f63dcd6d4
25 changed files with 528 additions and 79 deletions

View file

@ -76,7 +76,7 @@ add_library (
cursor.cpp read114.cpp paste.cpp
bsymbol.cpp marker.cpp jump.cpp stemslash.cpp ledgerline.cpp
synthesizerstate.cpp mcursor.cpp groups.cpp mscoreview.cpp
noteline.cpp
noteline.cpp spannermap.cpp
)
if (SCRIPT_INTERFACE)
set_target_properties (

View file

@ -2168,7 +2168,7 @@ QPointF Chord::layoutArticulation(Articulation* a)
// reserve space for slur
bool botGap = false;
bool topGap = false;
#if 0 // TODO-S
#if 0 // TODO-S: optimize
for (Spanner* sp = spannerFor(); sp; sp = sp->next()) {
if (sp->type() != SLUR)
continue;

View file

@ -554,7 +554,7 @@ void ChordRest::layoutArticulations()
bool botGap = false;
bool topGap = false;
#if 0 // TODO-S
#if 0 // TODO-S: optimize
for (Spanner* sp = _spannerFor; sp; sp = sp->next()) {
if (sp->type() != SLUR)
continue;

View file

@ -13,7 +13,6 @@
#include "elementmap.h"
#include "tupletmap.h"
#include "tiemap.h"
#include "spannermap.h"
#include "slur.h"
#include "chordrest.h"

View file

@ -32,7 +32,6 @@
#include "segment.h"
#include "tupletmap.h"
#include "tiemap.h"
#include "spannermap.h"
#include "layoutbreak.h"
namespace Ms {

View file

@ -642,7 +642,7 @@ void Score::doLayout()
}
}
for (const std::pair<int,Spanner*>& s : _spanner) {
for (const std::pair<int,Spanner*>& s : _spanner.map()) {
Spanner* sp = s.second;
if (sp->tick() == -1 || sp->tick2() == -1) {
printf("bad spanner id %d %s %d - %d\n", sp->id(), sp->name(), sp->tick(), sp->tick2());

View file

@ -71,7 +71,6 @@
#include "tablature.h"
#include "tiemap.h"
#include "tupletmap.h"
#include "spannermap.h"
#include "accidental.h"
#include "layout.h"
#include "icon.h"
@ -3408,7 +3407,7 @@ Fraction Measure::stretchedLen(Staff* staff) const
// cloneMeasure
//---------------------------------------------------------
Measure* Measure::cloneMeasure(Score* sc, TieMap* tieMap, SpannerMap* /*spannerMap*/)
Measure* Measure::cloneMeasure(Score* sc, TieMap* tieMap)
{
Measure* m = new Measure(sc);
m->_timesig = _timesig;

View file

@ -37,7 +37,6 @@ class System;
class Note;
class Spacer;
class TieMap;
class SpannerMap;
class AccidentalState;
class Spanner;
class Part;
@ -149,7 +148,7 @@ class Measure : public MeasureBase {
virtual Measure* clone() const { return new Measure(*this); }
virtual ElementType type() const { return MEASURE; }
virtual void setScore(Score* s);
Measure* cloneMeasure(Score*, TieMap*, SpannerMap*);
Measure* cloneMeasure(Score*, TieMap*);
void read(XmlReader&, int idx);
void read(XmlReader& d) { read(d, 0); }

View file

@ -161,22 +161,16 @@ LineSegment* Ottava::createLineSegment()
void Ottava::endEdit()
{
#if 0 // TODO-S
if (oStartElement != startElement() || oEndElement != endElement()) {
if (editTick != tick() || editTick2 != tick2()) {
Staff* s = staff();
int tick1 = static_cast<Segment*>(oStartElement)->tick();
int tick2 = static_cast<Segment*>(oEndElement)->tick();
s->pitchOffsets().remove(tick1);
s->pitchOffsets().remove(tick2);
s->pitchOffsets().remove(editTick);
s->pitchOffsets().remove(editTick2);
tick1 = static_cast<Segment*>(startElement())->tick();
tick2 = static_cast<Segment*>(endElement())->tick();
s->pitchOffsets().setPitchOffset(tick1, _pitchShift);
s->pitchOffsets().setPitchOffset(tick2, 0);
s->pitchOffsets().setPitchOffset(tick(), _pitchShift);
s->pitchOffsets().setPitchOffset(tick2(), 0);
score()->addLayoutFlags(LAYOUT_FIX_PITCH_VELO);
}
#endif
}
//---------------------------------------------------------

View file

@ -143,7 +143,7 @@ void Score::cmdPaste(MuseScoreView* view)
void Score::pasteStaff(XmlReader& e, ChordRest* dst)
{
for (auto i :_spanner)
for (auto i :_spanner.map())
i.second->setId(-1);
QList<Chord*> graceNotes;

View file

@ -676,7 +676,7 @@ void Score::createPlayEvents(Chord* chord)
int tick = chord->tick();
Slur* slur = 0;
for (auto sp : _spanner) {
for (auto sp : _spanner.map()) {
if (sp.second->type() != Element::SLUR || sp.second->track() != chord->track())
continue;
Slur* s = static_cast<Slur*>(sp.second);
@ -804,7 +804,7 @@ void Score::renderMidi(EventMap* events)
int utick1 = rs->utick;
int utick2 = utick1 + rs->len;
for (std::pair<int,Spanner*> sp : _spanner) {
for (std::pair<int,Spanner*> sp : _spanner.map()) {
Spanner* s = sp.second;
if (s->type() != Element::PEDAL)
continue;

View file

@ -28,7 +28,7 @@ namespace Ms {
Volta* Score::searchVolta(int tick) const
{
for (const std::pair<int,Spanner*>& p : _spanner) {
for (const std::pair<int,Spanner*>& p : _spanner.map()) {
Spanner* s = p.second;
if (s->type() != Element::VOLTA)
continue;

View file

@ -56,7 +56,6 @@
#include "articulation.h"
#include "revisions.h"
#include "tiemap.h"
#include "spannermap.h"
#include "layoutbreak.h"
#include "harmony.h"
#include "mscore.h"
@ -1371,7 +1370,6 @@ void Score::addElement(Element* element)
}
break;
#if 0 // TODO-S
case Element::OTTAVA:
{
Ottava* o = static_cast<Ottava*>(element);
@ -1380,23 +1378,18 @@ void Score::addElement(Element* element)
ss->system()->add(ss);
}
Staff* s = o->staff();
if (o->startElement()) {
int tick = static_cast<Segment*>(o->startElement())->tick();
s->pitchOffsets().setPitchOffset(tick, o->pitchShift());
}
if (o->endElement()) {
int tick = static_cast<Segment*>(o->endElement())->tick();
s->pitchOffsets().setPitchOffset(tick, 0);
}
s->pitchOffsets().setPitchOffset(o->tick(), o->pitchShift());
s->pitchOffsets().setPitchOffset(o->tick2(), 0);
layoutFlags |= LAYOUT_FIX_PITCH_VELO;
_playlistDirty = true;
}
break;
#endif
case Element::DYNAMIC:
layoutFlags |= LAYOUT_FIX_PITCH_VELO;
_playlistDirty = true;
break;
case Element::CLEF:
{
Clef* clef = static_cast<Clef*>(element);
@ -1404,6 +1397,7 @@ void Score::addElement(Element* element)
updateNoteLines(clef->segment(), clef->track());
}
break;
case Element::KEYSIG:
{
KeySig* ks = static_cast<KeySig*>(element);
@ -1415,12 +1409,14 @@ void Score::addElement(Element* element)
}
}
break;
case Element::TEMPO_TEXT:
{
TempoText* tt = static_cast<TempoText*>(element);
setTempo(tt->segment(), tt->tempo());
}
break;
case Element::INSTRUMENT_CHANGE:
rebuildMidiMapping();
_instrumentsChanged = true;
@ -1515,7 +1511,6 @@ void Score::removeElement(Element* element)
}
break;
#if 0 // TODO-S
case Element::OTTAVA:
{
Ottava* o = static_cast<Ottava*>(element);
@ -1524,15 +1519,13 @@ void Score::removeElement(Element* element)
ss->system()->remove(ss);
}
Staff* s = o->staff();
int tick1 = static_cast<Segment*>(o->startElement())->tick();
int tick2 = static_cast<Segment*>(o->endElement())->tick();
s->pitchOffsets().remove(tick1);
s->pitchOffsets().remove(tick2);
s->pitchOffsets().remove(o->tick());
s->pitchOffsets().remove(o->tick2());
layoutFlags |= LAYOUT_FIX_PITCH_VELO;
_playlistDirty = true;
}
break;
#endif
case Element::DYNAMIC:
layoutFlags |= LAYOUT_FIX_PITCH_VELO;
_playlistDirty = true;
@ -2170,13 +2163,12 @@ void Score::removeAudio()
bool Score::appendScore(Score* score)
{
TieMap tieMap;
SpannerMap spannerMap;
MeasureBaseList* ml = &score->_measures;
for (MeasureBase* mb = ml->first(); mb; mb = mb->next()) {
MeasureBase* nmb;
if (mb->type() == Element::MEASURE)
nmb = static_cast<Measure*>(mb)->cloneMeasure(this, &tieMap, &spannerMap);
nmb = static_cast<Measure*>(mb)->cloneMeasure(this, &tieMap);
else
nmb = mb->clone();
nmb->setNext(0);
@ -3341,7 +3333,7 @@ Cursor* Score::newCursor()
void Score::addSpanner(Spanner* s)
{
_spanner.insert(std::pair<int,Spanner*>(s->tick(), s));
_spanner.addSpanner(s);
}
//---------------------------------------------------------
@ -3350,14 +3342,7 @@ void Score::addSpanner(Spanner* s)
void Score::removeSpanner(Spanner* s)
{
// for (auto i = _spanner.lower_bound(s->tick()); i != _spanner.upper_bound(s->tick()); ++i) {
for (auto i = _spanner.begin(); i != _spanner.end(); ++i) {
if (i->second == s) {
_spanner.erase(i);
return;
}
}
qDebug("Score::removeSpanner: %s not found", s->name());
_spanner.removeSpanner(s);
}
//---------------------------------------------------------
@ -3366,7 +3351,7 @@ void Score::removeSpanner(Spanner* s)
Spanner* Score::findSpanner(int id) const
{
for (auto i = _spanner.rbegin(); i != _spanner.rend(); ++i) {
for (auto i = _spanner.crbegin(); i != _spanner.crend(); ++i) {
if (i->second->id() == id)
return i->second;
}
@ -3381,7 +3366,7 @@ Spanner* Score::findSpanner(int id) const
bool Score::isSpannerStartEnd(int tick, int track) const
{
for (auto i : _spanner) {
for (auto i : _spanner.map()) {
if (i.second->track() != track)
continue;
if (i.second->tick() == tick || i.second->tick2() == tick)
@ -3399,12 +3384,10 @@ void Score::insertTime(int tick, int len)
if (len == 0)
return;
printf("insertTime score %p at %d len %d\n", this, tick, len);
for (auto i : _spanner) {
for (auto i : _spanner.map()) {
Spanner* s = i.second;
if (s->tick2() < tick)
continue;
printf(" %p score %p change spanner %d+%d\n", s, s->score(), s->tick(), s->tickLen());
if (len > 0) {
if (tick > s->tick() && tick < s->tick2()) {
//

View file

@ -30,6 +30,7 @@
#include "segment.h"
#include "accidental.h"
#include "note.h"
#include "spannermap.h"
class QPainter;
@ -262,7 +263,7 @@ class Score : public QObject {
int _pageNumberOffset; ///< Offset for page numbers.
MeasureBaseList _measures; // here are the notes
std::multimap<int, Spanner*> _spanner; // spanner map, key is the start tick of the spanner
SpannerMap _spanner;
//
// generated objects during layout:
//
@ -929,8 +930,8 @@ class Score : public QObject {
qreal noteHeadWidth() const { return _noteHeadWidth; }
std::multimap<int, Spanner*>& spanner() { return _spanner; }
const std::multimap<int, Spanner*>& spanner() const { return _spanner; }
std::multimap<int, Spanner*>& spanner() { return _spanner.map(); }
const std::multimap<int, Spanner*>& spanner() const { return _spanner.map(); }
Spanner* findSpanner(int id) const;
bool isSpannerStartEnd(int tick, int track) const;
void removeSpanner(Spanner*);

View file

@ -1184,7 +1184,7 @@ void Score::writeSegments(Xml& xml, const Measure* m, int strack, int etrack,
e->write(xml);
}
if (segment->segmentType() & (Segment::SegChordRest)) {
for (auto i : _spanner) { // TODO: dont search whole list
for (auto i : _spanner.map()) { // TODO: dont search whole list
Spanner* s = i.second;
if (s->track() != track || s->generated())
continue;

View file

@ -106,10 +106,12 @@ class Spanner : public Element {
int _tick, _tick2;
int _id; // used for xml serialization
static int editTick, editTick2;
static QList<QPointF> userOffsets;
static QList<QPointF> userOffsets2;
protected:
static int editTick, editTick2;
public:
Spanner(Score* = 0);
Spanner(const Spanner&);

93
libmscore/spannermap.cpp Normal file
View file

@ -0,0 +1,93 @@
//=============================================================================
// MuseScore
// Music Composition & Notation
//
// Copyright (C) 2013 Werner Schweer
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2
// as published by the Free Software Foundation and appearing in
// the file LICENCE.GPL
//=============================================================================
#include "spannermap.h"
#include "spanner.h"
namespace Ms {
//---------------------------------------------------------
// SpannerMap
//---------------------------------------------------------
SpannerMap::SpannerMap()
: std::multimap<int, Spanner*>()
{
dirty = true;
}
//---------------------------------------------------------
// update
//---------------------------------------------------------
void SpannerMap::update() const
{
std::vector< ::Interval<Spanner*> > intervals;
for (auto i : *this)
intervals.push_back(Interval<Spanner*>(i.second->tick(), i.second->tick2(), i.second));
tree = IntervalTree<Spanner*>(intervals);
dirty = false;
}
//---------------------------------------------------------
// findContained
//---------------------------------------------------------
const std::vector<Interval<Spanner*>>& SpannerMap::findContained(int start, int stop)
{
if (dirty)
update();
tree.findContained(start, stop, results);
return results;
}
//---------------------------------------------------------
// findOverlapping
//---------------------------------------------------------
const std::vector<Interval<Spanner*>>& SpannerMap::findOverlapping(int start, int stop)
{
if (dirty)
update();
tree.findOverlapping(start, stop, results);
return results;
}
//---------------------------------------------------------
// addSpanner
//---------------------------------------------------------
void SpannerMap::addSpanner(Spanner* s)
{
insert(std::pair<int,Spanner*>(s->tick(), s));
dirty = true;
}
//---------------------------------------------------------
// removeSpanner
//---------------------------------------------------------
bool SpannerMap::removeSpanner(Spanner* s)
{
for (auto i = begin(); i != end(); ++i) {
if (i->second == s) {
erase(i);
dirty = true;
return true;
}
}
qDebug("Score::removeSpanner: %s not found", s->name());
return false;
}
} // namespace Ms

View file

@ -13,25 +13,39 @@
#ifndef __SPANNERMAP_H__
#define __SPANNERMAP_H__
#include "elementmap.h"
#include "thirdparty/intervaltree/IntervalTree.h"
namespace Ms {
class Spanner;
class Element;
//---------------------------------------------------------
// SpannerMap
//---------------------------------------------------------
class SpannerMap : public ElementMap {
class SpannerMap : std::multimap<int, Spanner*> {
mutable bool dirty;
mutable IntervalTree<Spanner*> tree;
std::vector< ::Interval<Spanner*> > results;
void update() const;
public:
SpannerMap() {}
Spanner* findNew(Spanner* o) const { return (Spanner*)(ElementMap::findNew((Element*)o)); }
void add(Spanner* _o, Spanner* _n) { ElementMap::add((Element*)_o, (Element*)_n); }
SpannerMap();
const std::vector< ::Interval<Spanner*> >& findContained(int start, int stop);
const std::vector< ::Interval<Spanner*> >& findOverlapping(int start, int stop);
std::multimap<int, Spanner*>& map() { return *this; }
const std::multimap<int, Spanner*>& map() const { return *this; }
std::multimap<int,Spanner*>::const_reverse_iterator crbegin() const { return std::multimap<int, Spanner*>::crbegin(); }
std::multimap<int,Spanner*>::const_reverse_iterator crend() const { return std::multimap<int, Spanner*>::crend(); }
std::multimap<int,Spanner*>::const_iterator cbegin() const { return std::multimap<int, Spanner*>::cbegin(); }
std::multimap<int,Spanner*>::const_iterator cend() const { return std::multimap<int, Spanner*>::cend(); }
void addSpanner(Spanner* s);
bool removeSpanner(Spanner* s);
};
} // namespace Ms
#endif

View file

@ -2636,14 +2636,9 @@ void Score::undoRemoveMeasures(Measure* m1, Measure* m2)
int tick1 = m1->tick();
int tick2 = m2->endTick();
auto i = _spanner.lower_bound(tick1);
while(i != _spanner.upper_bound(tick2)) {
Spanner* s = i->second;
++i; //iterate before potentially deleting it
if (s->tick() >= tick1 && s->tick() < tick2) {
undoRemoveElement(s);
}
}
for (auto i : _spanner.findContained(tick1, tick2))
undoRemoveElement(i.value);
//
// handle ties which start before m1 and end in (m1-m2)
//

View file

@ -577,7 +577,7 @@ void OveToMScore::convertTrackHeader(OVE::Track* track, Part* part){
part->setMidiProgram(track->getPatch());
if (ove_->getShowTransposeTrack() && track->getTranspose() != 0 ) {
Interval interval = part->instr()->transpose();
Ms::Interval interval = part->instr()->transpose();
interval.diatonic = -track->getTranspose();
part->instr()->setTranspose(interval);
}

219
thirdparty/intervaltree/IntervalTree.h vendored Normal file
View file

@ -0,0 +1,219 @@
#ifndef __INTERVAL_TREE_H
#define __INTERVAL_TREE_H
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
template <class T, typename K = int>
class Interval {
public:
K start;
K stop;
T value;
Interval(K s, K e, const T& v)
: start(s)
, stop(e)
, value(v)
{ }
};
template <class T, typename K = int>
int intervalStart(const Interval<T,K>& i) {
return i.start;
}
template <class T, typename K = int>
int intervalStop(const Interval<T,K>& i) {
return i.stop;
}
template <class T, typename K = int>
ostream& operator<<(ostream& out, Interval<T,K>& i) {
out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
return out;
}
template <class T, typename K = int>
class IntervalStartSorter {
public:
bool operator() (const Interval<T,K>& a, const Interval<T,K>& b) {
return a.start < b.start;
}
};
template <class T, typename K = int>
class IntervalTree {
public:
typedef Interval<T,K> interval;
typedef vector<interval> intervalVector;
typedef IntervalTree<T,K> intervalTree;
intervalVector intervals;
intervalTree* left;
intervalTree* right;
int center;
IntervalTree<T,K>(void)
: left(NULL)
, right(NULL)
, center(0)
{ }
IntervalTree<T,K>(const intervalTree& other) {
center = other.center;
intervals = other.intervals;
if (other.left) {
left = (intervalTree*) malloc(sizeof(intervalTree));
*left = *other.left;
} else {
left = NULL;
}
if (other.right) {
right = new intervalTree();
*right = *other.right;
} else {
right = NULL;
}
}
IntervalTree<T,K>& operator=(const intervalTree& other) {
center = other.center;
intervals = other.intervals;
if (other.left) {
left = new intervalTree();
*left = *other.left;
} else {
left = NULL;
}
if (other.right) {
right = new intervalTree();
*right = *other.right;
} else {
right = NULL;
}
return *this;
}
IntervalTree<T,K>(
intervalVector& ivals,
unsigned int depth = 16,
unsigned int minbucket = 64,
int leftextent = 0,
int rightextent = 0,
unsigned int maxbucket = 512
)
: left(NULL)
, right(NULL)
{
--depth;
if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) {
intervals = ivals;
} else {
if (leftextent == 0 && rightextent == 0) {
// sort intervals by start
IntervalStartSorter<T,K> intervalStartSorter;
sort(ivals.begin(), ivals.end(), intervalStartSorter);
}
int leftp = 0;
int rightp = 0;
int centerp = 0;
if (leftextent || rightextent) {
leftp = leftextent;
rightp = rightextent;
} else {
leftp = ivals.front().start;
vector<K> stops;
stops.resize(ivals.size());
transform(ivals.begin(), ivals.end(), stops.begin(), intervalStop<T,K>);
rightp = *max_element(stops.begin(), stops.end());
}
//centerp = ( leftp + rightp ) / 2;
centerp = ivals.at(ivals.size() / 2).start;
center = centerp;
intervalVector lefts;
intervalVector rights;
for (typename intervalVector::iterator i = ivals.begin(); i != ivals.end(); ++i) {
interval& interval = *i;
if (interval.stop < center) {
lefts.push_back(interval);
} else if (interval.start > center) {
rights.push_back(interval);
} else {
intervals.push_back(interval);
}
}
if (!lefts.empty()) {
left = new intervalTree(lefts, depth, minbucket, leftp, centerp);
}
if (!rights.empty()) {
right = new intervalTree(rights, depth, minbucket, centerp, rightp);
}
}
}
void findOverlapping(K start, K stop, intervalVector& overlapping) {
if (!intervals.empty() && ! (stop < intervals.front().start)) {
for (typename intervalVector::iterator i = intervals.begin(); i != intervals.end(); ++i) {
interval& interval = *i;
if (interval.stop >= start && interval.start <= stop) {
overlapping.push_back(interval);
}
}
}
if (left && start <= center) {
left->findOverlapping(start, stop, overlapping);
}
if (right && stop >= center) {
right->findOverlapping(start, stop, overlapping);
}
}
void findContained(K start, K stop, intervalVector& contained) {
if (!intervals.empty() && ! (stop < intervals.front().start)) {
for (typename intervalVector::iterator i = intervals.begin(); i != intervals.end(); ++i) {
interval& interval = *i;
if (interval.start >= start && interval.stop <= stop) {
contained.push_back(interval);
}
}
}
if (left && start <= center) {
left->findContained(start, stop, contained);
}
if (right && stop >= center) {
right->findContained(start, stop, contained);
}
}
~IntervalTree(void) {
// traverse the left and right
// delete them all the way down
if (left) {
delete left;
}
if (right) {
delete right;
}
}
};
#endif

19
thirdparty/intervaltree/LICENSE vendored Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2011 Erik Garrison
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
thirdparty/intervaltree/Makefile vendored Normal file
View file

@ -0,0 +1,7 @@
interval_tree_test: interval_tree_test.cpp IntervalTree.h
g++ -Wall interval_tree_test.cpp -o interval_tree_test -std=c++0x
.PHONY: clean
clean:
rm interval_tree_test

41
thirdparty/intervaltree/README vendored Normal file
View file

@ -0,0 +1,41 @@
Overview:
An interval tree can be used to efficiently find a set of numeric
intervals overlapping or containing another interval.
This library provides a basic implementation of an interval tree using
C++ templates, allowing the insertion of arbitrary types into the
tree.
Usage:
Add #include "IntervalTree.h" to the source files in which you will
use the interval tree.
To make an IntervalTree to contain objects of class T, use:
vector<Interval<T> > intervals;
T a, b, c;
intervals.push_back(Interval<T>(2, 10, a));
intervals.push_back(Interval<T>(3, 4, b));
intervals.push_back(Interval<T>(20, 100, c));
IntervalTree<T> tree;
tree = IntervalTree<T>(intervals);
Now, it's possible to query the tree and obtain a set of intervals
which are contained within the start and stop coordinates.
vector<Interval<T> > results;
tree.findContained(start, stop, results);
cout << "found " << results.size()
<< " overlapping intervals" << endl;
The function IntervalTree::findOverlapping provides a method to find
all those intervals which are contained or partially overlap the
interval (start, stop).
Author: Erik Garrison <erik.garrison@gmail.com>
License: MIT

View file

@ -0,0 +1,85 @@
#include <iostream>
#include <thread>
#include <chrono>
#include <random>
#include <time.h>
#include <assert.h>
#include "IntervalTree.h"
using namespace std;
typedef Interval<bool> interval;
typedef vector<interval> intervalVector;
typedef IntervalTree<bool> intervalTree;
template<typename K>
K randKey(K floor, K ceiling) {
K range = ceiling - floor;
return floor + range * ((double) rand() / (double) (RAND_MAX + 1.0));
}
template<class T, typename K>
Interval<T,K> randomInterval(K maxStart, K maxLength, K maxStop, const T& value) {
K start = randKey<K>(0, maxStart);
K stop = min<K>(randKey<K>(start, start + maxLength), maxStop);
return Interval<T,K>(start, stop, value);
}
int main() {
typedef vector<std::size_t> countsVector;
srand((unsigned)time(NULL));
intervalVector intervals;
intervalVector queries;
// generate a test set of target intervals
for (int i = 0; i < 10000; ++i) {
intervals.push_back(randomInterval<bool>(100000, 1000, 100000 + 1, true));
}
// and queries
for (int i = 0; i < 5000; ++i) {
queries.push_back(randomInterval<bool>(100000, 1000, 100000 + 1, true));
}
typedef chrono::high_resolution_clock Clock;
typedef chrono::milliseconds milliseconds;
// using brute-force search
countsVector bruteforcecounts;
Clock::time_point t0 = Clock::now();
for (intervalVector::iterator q = queries.begin(); q != queries.end(); ++q) {
intervalVector results;
for (intervalVector::iterator i = intervals.begin(); i != intervals.end(); ++i) {
if (i->start >= q->start && i->stop <= q->stop) {
results.push_back(*i);
}
}
bruteforcecounts.push_back(results.size());
}
Clock::time_point t1 = Clock::now();
milliseconds ms = chrono::duration_cast<milliseconds>(t1 - t0);
cout << "brute force:\t" << ms.count() << "ms" << endl;
// using the interval tree
intervalTree tree = intervalTree(intervals);
countsVector treecounts;
t0 = Clock::now();
for (intervalVector::iterator q = queries.begin(); q != queries.end(); ++q) {
intervalVector results;
tree.findContained(q->start, q->stop, results);
treecounts.push_back(results.size());
}
t1 = Clock::now();
ms = std::chrono::duration_cast<milliseconds>(t1 - t0);
cout << "interval tree:\t" << ms.count() << "ms" << endl;
// check that the same number of results are returned
countsVector::iterator b = bruteforcecounts.begin();
for (countsVector::iterator t = treecounts.begin(); t != treecounts.end(); ++t, ++b) {
assert(*b == *t);
}
return 0;
}