Canorus 0.0
kdtree.h
Go to the documentation of this file.
1
8#ifndef KDTREE_H
9#define KDTREE_H
10
11#include <QMultiMap>
12#include <QRect>
13#include <limits> // max double for managing staffs with unlimited width
14#include <iostream> // debugging
15
16#include "layout/drawable.h"
20
21#include "score/muselement.h"
22#include "score/playable.h"
23#include "score/voice.h"
24
38template <typename T>
39class CAKDTree {
40public:
42
43 void addElement(T elt);
44 T removeElement(double x, double y);
45
46 QList<T> findInRange(double x, double y, double w=0, double h=0);
47 QList<T> findInRange(QRect &area);
48 T findNearestLeft(double x, bool timeBased=false, CADrawableContext *context=0, CAVoice *voice=0);
49 T findNearestRight(double x, bool timeBased=false, CADrawableContext *context=0, CAVoice *voice=0);
50 T findNearestUp(double y);
51 T findNearestDown(double y);
52
53 double getMaxX();
54 double getMaxY();
55
56 void clear(bool autoDelete=true);
57 inline int size() { return _mapX.size(); }
58 QList<T> list() { return _mapX.values(); }
59
60private:
62 // Basic properties //
64 QMultiMap<double, T> _mapX; // List of all the drawable elements sorted by xPos()
65 QMultiMap<double, T> _mapXW; // List of all the drawable elements sorted by xPos()+width()
66 double _maxY; // The largest Ypos()+height() value of any element
67
69};
70
74template <typename T>
76 _maxY = 0;
77}
78
82template <typename T>
84 _mapX.insertMulti(elt->xPos(), elt);
85
86 if (elt->width()) {
87 // regular music element
88 _mapXW.insertMulti(elt->xPos()+elt->width(), elt);
89 } else {
90 // music element with unlimited width (e.g. staffs)
91 _mapXW.insertMulti(std::numeric_limits<double>::max(), elt);
92 }
93
94 if (elt->yPos() + elt->height() > _maxY) {
95 _maxY = elt->yPos() + elt->height();
96 }
97}
98
103template <typename T>
104void CAKDTree<T>::clear(bool autoDelete) {
105 if (autoDelete) {
106 for (typename QMultiMap<double, T>::const_iterator it=_mapX.constBegin(); it!=_mapX.constEnd(); it++) {
107 delete it.value();
108 }
109 }
110
111 _mapX.clear();
112 _mapXW.clear();
113
114 _maxY = 0;
115}
116
121template <typename T>
122QList<T> CAKDTree<T>::findInRange(double x, double y, double w, double h) {
123 QList<T> l;
124
125 T rightMostElt = _mapX.lowerBound(x+w).value();
126 for (typename QMultiMap<double, T>::const_iterator it=_mapXW.upperBound(x); (it!=_mapXW.end()) && (it.value()!=rightMostElt); it++) {
127 if ( (// The object is normal and fits into the area
128 (it.value()->yPos() <= y+h) &&
129 (it.value()->yPos() + it.value()->height() >= y)) ||
130 (// The object is unlimited in width (eg. contexts)
131 (it.value()->width() == 0) &&
132 (it.value()->yPos() <= y+h) &&
133 (it.value()->yPos() + it.value()->height() >= y)) ||
134 (// The object is unlimited in height (eg. helper lines)
135 (it.value()->height() == 0))
136 ) {
137 l << it.value();
138 }
139 }
140
141 return l;
142}
143
149template <typename T>
150QList<T> CAKDTree<T>::findInRange(QRect &rect) {
151 return findInRange(rect.x(), rect.y(), rect.width(), rect.height());
152}
153
162template <typename T>
163T CAKDTree<T>::findNearestLeft(double x, bool timeBased, CADrawableContext *context, CAVoice *voice) {
164 if (_mapX.size()==0) {
165 return 0;
166 }
167
168 typename QMultiMap<double, T>::const_iterator it = _mapX.lowerBound(x); // returns constEnd, if not found
169 while (it!=_mapX.constBegin() && (it==_mapX.constEnd() || it.value()->xPos()>=x)) {
170 it--;
171 }
172
173 if (it.value()->xPos()>=x) {
174 // no elements to the left at all
175 return 0;
176 }
177
178 do {
179 if (
180 // compare contexts
181 (!context || it.value()->drawableContext() == context) &&
182 // compare voices
183 ( !voice ||
184 (
185 // if the element isn't playable, see if it has the same context as the voice
186 (!it.value()->musElement()->isPlayable() &&
187 it.value()->musElement()->context() == voice->staff())
188 ||
189 // if the element is playable, see if it has the exactly same voice
190 (it.value()->musElement()->isPlayable() &&
191 static_cast<CAPlayable*>(it.value()->musElement())->voice() == voice)
192 )
193 )
194 ) {
195 return static_cast<T>(it.value());
196 }
197 } while ((it--)!=_mapX.constBegin());
198
199 // no regular elements to the left exists
200 return 0;
201}
202
211template <typename T>
212T CAKDTree<T>::findNearestRight(double x, bool timeBased, CADrawableContext *context, CAVoice *voice) {
213 typename QMultiMap<double, T>::const_iterator it = _mapX.upperBound(x);
214
215 for (; it!=_mapX.constEnd(); it++) {
216 if (
217 // compare contexts
218 (!context || it.value()->drawableContext() == context) &&
219 // compare voices
220 ( !voice ||
221 (
222 // if the element isn't playable, see if it has the same context as the voice
223 (!it.value()->musElement()->isPlayable() &&
224 it.value()->musElement()->context() == voice->staff())
225 ||
226 // if the element is playable, see if it has the exactly same voice
227 (it.value()->musElement()->isPlayable() &&
228 static_cast<CAPlayable*>(it.value()->musElement())->voice() == voice)
229 )
230 )
231 ) {
232 return static_cast<T>(it.value());
233 }
234 }
235
236 // no elements to the right exists
237 return 0;
238}
239
248template <typename T>
250 if (_mapX.isEmpty())
251 return 0;
252
253 T elt=0;
254 for (typename QMultiMap<double, T>::const_iterator it=_mapX.constBegin(); it!=_mapX.constEnd(); it++) {
255 if ( ((!elt) || ((it.value()->yPos() + it.value()->height()) > (elt->yPos() + elt->height())))
256 && ((it.value()->yPos()+ it.value()->height()) < y) ) {
257 elt = it.value();
258 }
259 }
260 return elt;
261
262}
263
272template <typename T>
274 if (_mapX.isEmpty())
275 return 0;
276
277 T elt=0;
278 for (typename QMultiMap<double, T>::const_iterator it=_mapX.constBegin(); it!=_mapX.constEnd(); it++) {
279 if ( ((!elt) || (it.value()->yPos() < elt->yPos())) && (it.value()->yPos() > y) ) {
280 elt = it.value();
281 }
282 }
283
284 return elt;
285}
286
291template <typename T>
293 if(_mapXW.constEnd() == _mapXW.constBegin())
294 return 0.0;
295 for (typename QMultiMap<double, T>::const_iterator it=(--_mapXW.constEnd());
296 it!=_mapXW.constBegin();
297 it--) {
298 if (it.key()!=std::numeric_limits<double>::max()) {
299 // don't take contexts unlimited length into account
300 return it.key();
301 }
302 }
303 return 0;
304}
305
310template <typename T>
312 return _maxY;
313}
314
320template <typename T>
322 _maxY = 0;
323 for (typename QMultiMap<double, T>::iterator it=_mapX.begin(); it!=_mapX.end(); it++) {
324 if (it.value()->yPos()+it.value()->height() > _maxY) {
325 _maxY = it.value()->yPos()+it.value()->height();
326 }
327 }
328}
329
330#endif
331
Definition: drawablecontext.h:18
Space partitioning structure for fast access to drawable elements on canvas.
Definition: kdtree.h:39
void addElement(T elt)
Definition: kdtree.h:83
T findNearestDown(double y)
Definition: kdtree.h:273
double getMaxX()
Definition: kdtree.h:292
T findNearestUp(double y)
Definition: kdtree.h:249
T removeElement(double x, double y)
CAKDTree()
Definition: kdtree.h:75
QList< T > list()
Definition: kdtree.h:58
int size()
Definition: kdtree.h:57
QList< T > findInRange(QRect &area)
Definition: kdtree.h:150
double _maxY
Definition: kdtree.h:66
T findNearestRight(double x, bool timeBased=false, CADrawableContext *context=0, CAVoice *voice=0)
Definition: kdtree.h:212
T findNearestLeft(double x, bool timeBased=false, CADrawableContext *context=0, CAVoice *voice=0)
Definition: kdtree.h:163
double getMaxY()
Definition: kdtree.h:311
QMultiMap< double, T > _mapXW
Definition: kdtree.h:65
QList< T > findInRange(double x, double y, double w=0, double h=0)
Definition: kdtree.h:122
QMultiMap< double, T > _mapX
Definition: kdtree.h:64
void clear(bool autoDelete=true)
Definition: kdtree.h:104
void calculateMaxY()
Definition: kdtree.h:321
Playable instances of music elements.
Definition: playable.h:18
CAVoice * voice()
Definition: playable.h:31
Class which represents a voice in the staff.
Definition: voice.h:23
CAStaff * staff()
Definition: voice.h:29