CLAM-Development  1.4.0
ContiguousSegmentation.hxx
Go to the documentation of this file.
1 #ifndef ContiguousSegmentation_hxx
2 #define ContiguousSegmentation_hxx
3 
4 #include "Segmentation.hxx"
5 
6 namespace CLAM
7 {
9  {
10  public:
11  class InsertedOutOfBounds : public std::exception
12  {
13  public:
14  const char * what() const throw () { return "Segmentation point inserted out of limits";}
15  };
16  typedef std::vector<double> TimePositions;
17  public:
20  {
21  _onsets.push_back(0);
22  _offsets.push_back(maxPosition);
23  _selection.push_back(false);
24 
25  }
26 
27  ContiguousSegmentation(double maxPosition, const TData * begin, const TData * end)
28  : Segmentation(maxPosition)
29  {
30  _onsets.push_back(0);
31  _offsets.push_back(maxPosition);
32  _selection.push_back(false);
33  takeArray(begin, end);
34  }
36  {
37  }
38 
42  void takeArray(const TData * begin, const TData * end)
43  {
44  for (const TData * it=begin; it!=end; it++)
45  insert(*it);
46  }
47 
51  unsigned insert(double timePosition)
52  {
53  if (timePosition<=0.0) throw InsertedOutOfBounds();
54  TimePositions::iterator insertPoint =
55  std::lower_bound(_offsets.begin(), _offsets.end(), timePosition);
56  if (insertPoint == _offsets.end()) throw InsertedOutOfBounds();
57  //if (insertPoint == _offsets.end()) return insertPoint - _offsets.begin();
58  // 'position' must be computed before the insertion to not invalidate iterators.
59  unsigned position = insertPoint - _offsets.begin() +1;
60  _offsets.insert(insertPoint, timePosition);
61  _onsets.insert(_onsets.begin()+position, _offsets[position-1]);
62  _selection.insert(_selection.begin()+position, false);
63  if (position<=_current) _current++;
64  return position;
65  }
69  void maxPosition(double maxPosition)
70  {
71  Segmentation::maxPosition(maxPosition);
72  _offsets.back()=maxPosition;
73  }
74 
81  void remove(unsigned segment)
82  {
83  if (_offsets.size()==1) return;
84  unsigned offsetToRemove = segment? segment-1 : 0;
85  _offsets.erase(_offsets.begin()+offsetToRemove);
86  _onsets.erase(_onsets.begin()+segment);
87  _selection.erase(_selection.begin()+segment);
88  if (_current!=0 && segment<=_current) _current--;
89  if (segment==0) _onsets[0]=0;
90  }
97  unsigned pickOffset(double timePosition, double tolerance) const
98  {
99  return pickPosition(_offsets, timePosition, tolerance);
100  }
107  unsigned pickOnset(double timePosition, double tolerance) const
108  {
109  return pickPosition(_onsets, timePosition, tolerance);
110  }
114  unsigned pickSegmentBody(double timePosition) const
115  {
116  if (timePosition<0) return _offsets.size();
117  TimePositions::const_iterator lowerBound =
118  std::lower_bound(_offsets.begin(), _offsets.end(), timePosition);
119  return lowerBound - _offsets.begin();
120  }
126  void dragOnset(unsigned segment, double newTimePosition)
127  {
128  // first onset cannot be moved on Contiguous mode
129  if (segment==0) return;
130  // The onset is attached to the previous offset
131  dragOffset(segment-1, newTimePosition);
132  }
138  void dragOffset(unsigned segment, double newTimePosition)
139  {
140  if (segment==_offsets.size()) return; // Invalid segment
141  if (segment==_offsets.size()-1) return; // Last offset, cannot be moved
142 
143  // Limit movement on the left to the onset
144  if (newTimePosition<_onsets[segment])
145  newTimePosition = _onsets[segment];
146  // Limit movement on the right to the next offset
147  if (newTimePosition>_offsets[segment+1])
148  newTimePosition = _offsets[segment+1];
149 
150  // The offset and the next onset change together
151  _offsets[segment]=newTimePosition;
152  _onsets[segment+1]=newTimePosition;
153  }
157  void fillArray(DataArray& segmentation) const
158  {
159  unsigned nSegments= _onsets.size();
160  segmentation.Resize(nSegments-1);
161  segmentation.SetSize(nSegments-1);
162  for(unsigned i=1; i<nSegments; i++)
163  segmentation[i-1]=_onsets[i];
164  }
165  const char * GetClassName() const { return "ContiguousSegmentation"; }
166 
167  private:
175  unsigned pickPosition(const TimePositions & positions, double timePosition, double tolerance) const
176  {
177  TimePositions::const_iterator lowerBound =
178  std::lower_bound(positions.begin(), positions.end(), timePosition-tolerance);
179  TimePositions::const_iterator upperBound =
180  std::upper_bound(lowerBound, positions.end(), timePosition+tolerance);
181 
182  if (lowerBound==upperBound) return positions.size(); // None found
183 
184  // Pick the closest in range
185  unsigned lowerSegment = lowerBound - positions.begin();
186  unsigned upperSegment = upperBound - positions.begin();
187  double lastDifference = std::fabs(timePosition-positions[lowerSegment]);
188  for (unsigned i=lowerSegment; i<upperSegment; i++)
189  {
190  double newDifference = std::fabs(timePosition-positions[i]);
191  if (newDifference>lastDifference) break;
192  lastDifference = newDifference;
193  lowerSegment = i;
194  }
195  return lowerSegment;
196  }
197  };
198 
199 }
200 
201 
202 
203 #endif//ContiguousSegmentation_hxx
204