DiscontinuousSegmentation.hxx

Go to the documentation of this file.
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 
Generated by  doxygen 1.6.3