![]() |
Mixxx
|
00001 #ifndef DiscontinuousSegmentation_hxx 00002 #define DiscontinuousSegmentation_hxx 00003 00004 #include "Segmentation.hxx" 00005 00006 namespace CLAM 00007 { 00008 class DiscontinuousSegmentation : public Segmentation 00009 { 00010 public: 00011 class InsertedOutOfBounds : public std::exception 00012 { 00013 public: 00014 const char * what() const throw () { return "Segmentation point inserted out of limits";} 00015 }; 00016 class OffsetMissing : public std::exception 00017 { 00018 public: 00019 const char * what() const throw () { return "Odd number of segmentation points, every segment beggining must be followed by its ending";} 00020 }; 00021 class MissplacedOnset : public std::exception 00022 { 00023 std::string _message; 00024 public: 00025 MissplacedOnset(unsigned missplacedOnset, 00026 double previousOffsetPosition, 00027 double intendedOnsetPosition) 00028 { 00029 std::ostringstream os; 00030 os << "Segment " << missplacedOnset 00031 << " starts at " << intendedOnsetPosition 00032 << " overlapping previous segment which ends at " << previousOffsetPosition; 00033 _message = os.str(); 00034 } 00035 virtual ~MissplacedOnset() throw () {} 00036 const char * what() const throw () { return _message.c_str(); } 00037 }; 00038 class MissplacedOffset : public std::exception 00039 { 00040 std::string _message; 00041 public: 00042 MissplacedOffset(unsigned missplacedOffset, 00043 double onsetPosition, 00044 double offsetPosition) 00045 { 00046 std::ostringstream os; 00047 os << "Segment " << missplacedOffset 00048 << " starts at " << onsetPosition 00049 << " but ends before that, at " << offsetPosition; 00050 _message = os.str(); 00051 } 00052 virtual ~MissplacedOffset() throw () {} 00053 const char * what() const throw () { return _message.c_str(); } 00054 }; 00055 typedef std::vector<double> TimePositions; 00056 public: 00057 DiscontinuousSegmentation(double maxPosition=0) 00058 : Segmentation(maxPosition) 00059 { 00060 } 00067 DiscontinuousSegmentation(double maxPosition, const TData * begin, const TData * end) 00068 : Segmentation(maxPosition) 00069 { 00070 takeArray(begin, end); 00071 } 00075 void takeArray(const TData * begin, const TData * end) 00076 { 00077 double previousOffset=0.0; 00078 unsigned i=0; 00079 for (const TData* it=begin; it!=end; i++) 00080 { 00081 double onset = *it++; 00082 std::cout << onset << " " << std::flush; 00083 if (onset<previousOffset) throw MissplacedOnset(i,previousOffset,onset); 00084 if (it==end) throw OffsetMissing(); 00085 double offset = *it++; 00086 std::cout << offset << " " << std::flush; 00087 if (offset<onset) throw MissplacedOffset(i, onset, offset); 00088 if (offset>_maxPosition) throw InsertedOutOfBounds(); //_maxPosition 00089 _onsets.push_back(onset); 00090 _offsets.push_back(offset); 00091 _labels.push_back(""); // TODO: a constructor with not empty labels 00092 _selection.push_back(false); 00093 previousOffset=offset; 00094 } 00095 } 00099 unsigned insert(double timePosition) 00100 { 00101 if (timePosition<0.0) throw InsertedOutOfBounds(); 00102 if (timePosition>_maxPosition) throw InsertedOutOfBounds(); 00103 TimePositions::iterator nextOffset = 00104 std::lower_bound(_offsets.begin(), _offsets.end(), timePosition); 00105 if (nextOffset == _offsets.end()) // Beyond any existing segment 00106 { 00107 _onsets.push_back(timePosition); 00108 _offsets.push_back(_maxPosition); 00109 _labels.push_back(""); 00110 _selection.push_back(false); 00111 return _onsets.size()-1; 00112 } 00113 // 'nextOffsetPosition' must be computed before the insertion to not invalidate iterators. 00114 unsigned nextOffsetPosition = nextOffset - _offsets.begin(); 00115 if (_onsets[nextOffsetPosition]<=timePosition) // Just in the middle of a segment 00116 { 00117 _offsets.insert(nextOffset, timePosition); 00118 _onsets.insert(_onsets.begin()+nextOffsetPosition+1, timePosition); 00119 _labels.insert(_labels.begin()+nextOffsetPosition+1, ""); 00120 _selection.insert(_selection.begin()+nextOffsetPosition+1, false); 00121 if (nextOffsetPosition<_current) _current++; 00122 return nextOffsetPosition+1; 00123 } 00124 else // In a gap before a segment 00125 { 00126 _offsets.insert(nextOffset, _onsets[nextOffsetPosition]); 00127 _onsets.insert(_onsets.begin()+nextOffsetPosition, timePosition); 00128 _labels.insert(_labels.begin()+nextOffsetPosition, ""); 00129 _selection.insert(_selection.begin()+nextOffsetPosition, false); 00130 if (_current>=nextOffsetPosition) _current++; 00131 return nextOffsetPosition; 00132 } 00133 00134 } 00138 unsigned insert(double timePosition, std::string label) 00139 { 00140 unsigned segment = insert(timePosition); 00141 setLabel(segment, label); 00142 return segment; 00143 } 00150 void remove(unsigned segment) 00151 { 00152 _offsets.erase(_offsets.begin()+segment); 00153 _onsets.erase(_onsets.begin()+segment); 00154 _labels.erase(_labels.begin()+segment); 00155 _selection.erase(_selection.begin()+segment); 00156 if (_current!=0 && segment<=_current) _current--; 00157 } 00164 unsigned pickOffset(double timePosition, double tolerance) const 00165 { 00166 return pickPosition(_offsets, timePosition, tolerance); 00167 } 00174 unsigned pickOnset(double timePosition, double tolerance) const 00175 { 00176 return pickPosition(_onsets, timePosition, tolerance); 00177 } 00181 unsigned pickSegmentBody(double timePosition) const 00182 { 00183 if (timePosition<0) return _offsets.size(); 00184 TimePositions::const_iterator lowerBound = 00185 std::lower_bound(_offsets.begin(), _offsets.end(), timePosition); 00186 unsigned index = lowerBound-_offsets.begin(); 00187 if (index==_offsets.size()) return index; 00188 if (_onsets[index]>timePosition) return _offsets.size(); 00189 return index; 00190 } 00196 void dragOnset(unsigned segment, double newTimePosition) 00197 { 00198 // The onset is attached to the previous offset 00199 if (segment>=_onsets.size()) return; // Invalid segment 00200 00201 // Limit to the left to the previous onset or 0 00202 double leftBound = segment ? _offsets[segment-1] : 0; 00203 if (newTimePosition<leftBound) 00204 newTimePosition=leftBound; 00205 // Limit to the right to the own offset 00206 double rigthBound = _offsets[segment]; 00207 if (newTimePosition>rigthBound) 00208 newTimePosition=rigthBound; 00209 00210 // The offset and the next onset change together 00211 _onsets[segment]=newTimePosition; 00212 } 00218 void dragOffset(unsigned segment, double newTimePosition) 00219 { 00220 if (segment>=_offsets.size()) return; // Invalid segment 00221 00222 // Limit to the right to the next offset or max 00223 double rigthBound = segment+1==_offsets.size()? _maxPosition : _onsets[segment+1]; 00224 if (newTimePosition>rigthBound) 00225 newTimePosition=rigthBound; 00226 // Limit to the left to the own onset 00227 double leftBound = _onsets[segment]; 00228 if (newTimePosition<leftBound) 00229 newTimePosition=leftBound; 00230 00231 // The offset and the next onset change together 00232 _offsets[segment]=newTimePosition; 00233 } 00237 /*void fillArray(DataArray& segmentation) const 00238 { 00239 unsigned nSegments = _onsets.size(); 00240 segmentation.Resize(nSegments*2); 00241 segmentation.SetSize(nSegments*2); 00242 for (unsigned i=0; i<nSegments; i++) 00243 { 00244 segmentation[i*2] = _onsets[i]; 00245 segmentation[i*2+1] = _offsets[i]; 00246 } 00247 }*/ 00248 00249 const char * GetClassName() const { return "DiscontinuousSegmentation"; } 00250 00251 00252 private: 00260 unsigned pickPosition(const TimePositions & positions, double timePosition, double tolerance) const 00261 { 00262 TimePositions::const_iterator lowerBound = 00263 std::lower_bound(positions.begin(), positions.end(), timePosition-tolerance); 00264 TimePositions::const_iterator upperBound = 00265 std::upper_bound(lowerBound, positions.end(), timePosition+tolerance); 00266 00267 if (lowerBound==upperBound) return positions.size(); // None found 00268 00269 // Pick the closest in range 00270 unsigned lowerSegment = lowerBound - positions.begin(); 00271 unsigned upperSegment = upperBound - positions.begin(); 00272 double lastDifference = std::fabs(timePosition-positions[lowerSegment]); 00273 for (unsigned i=lowerSegment; i<upperSegment; i++) 00274 { 00275 double newDifference = std::fabs(timePosition-positions[i]); 00276 if (newDifference>lastDifference) break; 00277 lastDifference = newDifference; 00278 lowerSegment = i; 00279 } 00280 return lowerSegment; 00281 } 00282 }; 00283 00284 } 00285 00286 00287 00288 #endif//DiscontinuousSegmentation_hxx 00289