CLAM-Development  1.4.0
UnsizedSegmentation.hxx
Go to the documentation of this file.
1 #ifndef UnsizedSegmentation_hxx
2 #define UnsizedSegmentation_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:
19  : Segmentation(0)
20  {
21  }
23  : Segmentation(maxPosition)
24  {
25  }
26 
27  UnsizedSegmentation(double maxPosition, const TData * begin, const TData * end)
28  : Segmentation(maxPosition)
29  {
30  takeArray(begin, end);
31  }
35  void takeArray(const TData * begin, const TData * end)
36  {
37  for (const TData * it=begin; it!=end; it++)
38  insert(*it);
39  }
41  {
42  }
46  unsigned insert(double timePosition)
47  {
48  if (timePosition<0.0) throw InsertedOutOfBounds();
49  if (timePosition>=maxPosition()) throw InsertedOutOfBounds();
50  TimePositions::iterator insertPoint =
51  std::lower_bound(_offsets.begin(), _offsets.end(), timePosition);
52  if (insertPoint==_offsets.end())
53  {
54  _offsets.push_back(timePosition);
55  _onsets.push_back(timePosition);
56  _selection.push_back(false);
57  return _offsets.size()-1;
58  }
59  unsigned position = insertPoint - _offsets.begin();
60  _offsets.insert(insertPoint, timePosition);
61  _onsets.insert(_onsets.begin()+position, timePosition);
62  _selection.insert(_selection.begin()+position, false);
63  if (position<=_current) _current++;
64  return position;
65  }
72  void remove(unsigned segment)
73  {
74  _offsets.erase(_offsets.begin()+segment);
75  _onsets.erase(_onsets.begin()+segment);
76  _selection.erase(_selection.begin()+segment);
77  if (_current!=0 && segment<=_current) _current--;
78  }
85  unsigned pickOffset(double timePosition, double tolerance) const
86  {
87  return pickPosition(_offsets, timePosition, tolerance);
88  }
95  unsigned pickOnset(double timePosition, double tolerance) const
96  {
97  return pickPosition(_onsets, timePosition, tolerance);
98  }
102  unsigned pickSegmentBody(double timePosition) const
103  {
104  if (timePosition<0) return _offsets.size();
105  TimePositions::const_iterator upperBound =
106  std::lower_bound(_offsets.begin(), _offsets.end(), timePosition);
107  if (upperBound == _offsets.begin()) return 0;
108  if (timePosition - *(upperBound-1) > *upperBound - timePosition) return upperBound - _offsets.begin();
109  return upperBound - _offsets.begin()-1;
110  }
116  void dragOnset(unsigned segment, double newTimePosition)
117  {
118  // The onset is attached to the offset
119  dragOffset(segment, newTimePosition);
120  }
126  void dragOffset(unsigned segment, double newTimePosition)
127  {
128  if (segment==_offsets.size()) return; // Invalid segment
129 
130  // Limit movement on the left to the onset
131  double leftLimit = segment!=0 ?
132  _onsets[segment-1] : 0.0;
133  double rightLimit = segment+1<_offsets.size()?
134  _onsets[segment+1] : maxPosition();
135  if (newTimePosition<leftLimit)
136  newTimePosition = leftLimit;
137  // Limit movement on the right to the next offset
138  if (newTimePosition>rightLimit)
139  newTimePosition = rightLimit;
140 
141  // The offset and the onset change together
142  _offsets[segment]=newTimePosition;
143  _onsets[segment]=newTimePosition;
144  }
148  void fillArray(DataArray& segmentation) const
149  {
150  unsigned nSegments = _onsets.size();
151  segmentation.Resize(nSegments);
152  segmentation.SetSize(nSegments);
153  for (unsigned i=0; i<nSegments; i++)
154  segmentation[i]=_onsets[i];
155  }
156 
157  const char * GetClassName() const { return "UnsizedSegmentation"; }
158 
159  private:
167  unsigned pickPosition(const TimePositions & positions, double timePosition, double tolerance) const
168  {
169  TimePositions::const_iterator lowerBound =
170  std::lower_bound(positions.begin(), positions.end(), timePosition-tolerance);
171  TimePositions::const_iterator upperBound =
172  std::upper_bound(lowerBound, positions.end(), timePosition+tolerance);
173 
174  if (lowerBound==upperBound) return positions.size(); // None found
175 
176  // Pick the closest in range
177  unsigned lowerSegment = lowerBound - positions.begin();
178  unsigned upperSegment = upperBound - positions.begin();
179  double lastDifference = std::fabs(timePosition-positions[lowerSegment]);
180  for (unsigned i=lowerSegment; i<upperSegment; i++)
181  {
182  double newDifference = std::fabs(timePosition-positions[i]);
183  if (newDifference>lastDifference) break;
184  lastDifference = newDifference;
185  lowerSegment = i;
186  }
187  return lowerSegment;
188  }
189  };
190 
191 }
192 
193 
194 
195 #endif//UnsizedSegmentation_hxx
196