00001 //--------------------------------------------------------------------------- 00002 // 00003 // Project: OpenWalnut ( http://www.openwalnut.org ) 00004 // 00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS 00006 // For more information see http://www.openwalnut.org/copying 00007 // 00008 // This file is part of OpenWalnut. 00009 // 00010 // OpenWalnut is free software: you can redistribute it and/or modify 00011 // it under the terms of the GNU Lesser General Public License as published by 00012 // the Free Software Foundation, either version 3 of the License, or 00013 // (at your option) any later version. 00014 // 00015 // OpenWalnut is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU Lesser General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU Lesser General Public License 00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>. 00022 // 00023 //--------------------------------------------------------------------------- 00024 00025 #ifndef WFIBERCLUSTER_H 00026 #define WFIBERCLUSTER_H 00027 00028 #include <list> 00029 #include <string> 00030 #include <vector> 00031 00032 #include <boost/shared_ptr.hpp> 00033 #include <boost/thread.hpp> 00034 00035 #include "../../common/WColor.h" 00036 #include "../../common/WTransferable.h" 00037 #include "../WDataSetFiberVector.h" 00038 #include "../WExportDataHandler.h" 00039 00040 /** 00041 * Represents a cluster of indices of a WDataSetFiberVector. 00042 */ 00043 class OWDATAHANDLER_EXPORT WFiberCluster : public WTransferable // NOLINT 00044 { 00045 friend class WFiberClusterTest; 00046 public: 00047 /** 00048 * Constructs an cluster with one fiber and a reference to the fiber dataset 00049 * to compute the intercluster distance. 00050 * 00051 * \param index The index of the first fiber belonging to this cluster 00052 */ 00053 explicit WFiberCluster( size_t index ); 00054 00055 /** 00056 * Copies the specified \ref WFiberCluster Instance. The copy does not contain a valid centerline or longest line. 00057 * 00058 * \param other the other instance to clone. 00059 */ 00060 WFiberCluster( const WFiberCluster& other ); 00061 00062 /** 00063 * Constructs an empty cluster. 00064 */ 00065 WFiberCluster(); 00066 00067 /** 00068 * Destructs. Frees used locks/mutex. 00069 */ 00070 virtual ~WFiberCluster(); 00071 00072 /** 00073 * Returns true if there are no fibers in that cluster, false otherwise. 00074 * 00075 * \return true if empty 00076 */ 00077 bool empty() const; 00078 00079 /** 00080 * Merge the fibers of the other cluster with the fibers of this cluster. 00081 * Afterwards the other cluster is empty. 00082 * 00083 * \param other The other WFiberCluster which should merged into this one 00084 */ 00085 void merge( WFiberCluster &other ); // NOLINT 00086 00087 /** 00088 * Returns a const reference of all indices inside this cluster 00089 * 00090 * \return the index list 00091 */ 00092 const std::list< size_t >& getIndices() const; 00093 00094 /** 00095 * Reset the indices belonging to that cluster 00096 * 00097 * \param indices list of indices 00098 */ 00099 void setIndices( const std::list< size_t >& indices ); 00100 00101 /** 00102 * Sort the indices of fibers associated with this cluster in ascending 00103 * order. 00104 */ 00105 void sort(); 00106 00107 /** 00108 * \return Number of fibers associated with this cluster. 00109 */ 00110 size_t size() const; 00111 00112 /** 00113 * Make this cluster empty. Note: The real fibers from fiber dataset are 00114 * not deleted. 00115 */ 00116 void clear(); 00117 00118 /** 00119 * Sets the color of which all fibers of this clusters should be painted 00120 * with. 00121 * 00122 * \param color The color for all fibers of this cluster. 00123 */ 00124 void setColor( WColor color ); 00125 00126 /** 00127 * Gets the color of which all fibers of this clusters should be painted 00128 * with. 00129 * 00130 * \return cluster color. 00131 */ 00132 WColor getColor() const; 00133 00134 /** 00135 * The only reason for implementing is here, to prevent this class from 00136 * beeing abstract. 00137 * 00138 * \return A name. 00139 */ 00140 virtual const std::string getName() const; 00141 00142 /** 00143 * The only reason for implementing is here, to prevent this class from 00144 * beeing abstract. 00145 * 00146 * \return A name. 00147 */ 00148 virtual const std::string getDescription() const; 00149 00150 /** 00151 * \param other The other fiber which should be compared 00152 * \return true If both clusters having same fibers IN SAME ORDER! 00153 */ 00154 bool operator==( const WFiberCluster& other ) const; 00155 00156 /** 00157 * The opposite of the operator== 00158 * 00159 * \param other The other fiber which should be compared 00160 * \return false If both clusters having same fibers IN SAME ORDER! 00161 */ 00162 bool operator!=( const WFiberCluster& other ) const; 00163 00164 /** 00165 * Copy assignment operator which does NOT copy the mutex's!!! 00166 * 00167 * \param other The instance to copy. 00168 * 00169 * \return itself 00170 */ 00171 WFiberCluster& operator=( const WFiberCluster& other ) 00172 { 00173 WTransferable::operator=( other ); 00174 m_memberIndices = other.m_memberIndices; 00175 m_fibs = other.m_fibs; 00176 m_color = other.m_color; 00177 m_centerLineCreationLock = new boost::shared_mutex(); 00178 m_longestLineCreationLock = new boost::shared_mutex(); 00179 // copy them only if they exist 00180 if( other.m_centerLine ) 00181 { 00182 m_centerLine = boost::shared_ptr< WFiber >( new WFiber( *other.m_centerLine.get() ) ); 00183 } 00184 if( other.m_longestLine ) 00185 { 00186 m_longestLine = boost::shared_ptr< WFiber >( new WFiber( *other.m_longestLine.get() ) ); 00187 } 00188 return *this; 00189 } 00190 00191 // TODO(math): The only reason why we store here a Reference to the fiber 00192 // dataset is, we need it in the WMVoxelizer module as well as the clustering 00193 // information. Since we don't have the possibility of multiple 00194 // InputConnectors we must agglomerate those into one object. Please remove this. 00195 // \cond Suppress_Doxygen 00196 void setDataSetReference( boost::shared_ptr< const WDataSetFiberVector > fibs ); 00197 boost::shared_ptr< const WDataSetFiberVector > getDataSetReference() const; 00198 static boost::shared_ptr< WPrototyped > getPrototype(); 00199 // \endcond 00200 00201 /** 00202 * Returns the center line of this cluster. The centerline gets calculated during the first call of this method. 00203 * 00204 * \return Reference to the center line 00205 */ 00206 boost::shared_ptr< WFiber > getCenterLine() const; 00207 00208 /** 00209 * Returns the center line of this cluster. The longest line gets calculated during the first call if this method. 00210 * 00211 * \return Reference to the longest line 00212 */ 00213 boost::shared_ptr< WFiber > getLongestLine() const; 00214 00215 /** 00216 * Makes the hard work to compute the center line. 00217 */ 00218 void generateCenterLine() const; 00219 00220 /** 00221 * Makes the hard work to find the longest line. 00222 */ 00223 void generateLongestLine() const; 00224 00225 /** 00226 * Recomputes on every call the axis aligned bounding box incorporating all tracts in this cluster. 00227 * 00228 * \return AABB as WBoundingBox. 00229 */ 00230 WBoundingBox getBoundingBox() const; 00231 00232 protected: 00233 // TODO(math): The only reason why we store here a Reference to the fiber 00234 // dataset is, we need it in the WMVoxelizer module as well as the clustering 00235 // information. Since we don't have the possibility of multiple 00236 // InputConnectors we must agglomerate those into one object. Please remove this. 00237 // \cond Suppress_Doxygen 00238 static boost::shared_ptr< WPrototyped > m_prototype; 00239 // \endcond 00240 00241 /** 00242 * Alings all fibers within the given dataset to be in one main direction. But Alignment only may swap the ordering of the fibers 00243 * but not the positions or something similar. We need this only for the centerline generation. 00244 * 00245 * \param fibs The dataset 00246 */ 00247 void unifyDirection( boost::shared_ptr< WDataSetFiberVector > fibs ) const; 00248 00249 private: 00250 /** 00251 * The centerline may be shortened due to the averaging of outliers. To 00252 * nevertheless color almost the whole bundle surface we need a surface 00253 * parameterization (given via the centerline) upto the endings of the 00254 * bundle. Therefore the centerline is stepwise elongated with the last 00255 * known direction, until no perpendicular plane intersects any of the 00256 * tracts inside of the bundle. 00257 */ 00258 void elongateCenterLine() const; 00259 00260 /** 00261 * All indices in this set are members of this cluster 00262 */ 00263 std::list< size_t > m_memberIndices; 00264 00265 // TODO(math): The only reason why we store here a Reference to the fiber 00266 // dataset is, we need it in the WMVoxelizer module as well as the clustering 00267 // information. Since we don't have the possibility of multiple 00268 // InputConnectors we must agglomerate those into one object. Please remove this. 00269 /** 00270 * Reference to the real fibers of the brain this cluster belongs to. 00271 */ 00272 boost::shared_ptr< const WDataSetFiberVector > m_fibs; 00273 00274 /** 00275 * Color which is used to paint the members of this cluster. 00276 */ 00277 WColor m_color; 00278 00279 /** 00280 * Lock the modification in the m_centerLine mutable. The lock is stored as pointer to avoid copy construction problems. 00281 */ 00282 boost::shared_mutex* m_centerLineCreationLock; 00283 00284 /** 00285 * Lock the modification in the m_longestLine mutable. The lock is stored as pointer to avoid copy construction problems. 00286 */ 00287 boost::shared_mutex* m_longestLineCreationLock; 00288 00289 /** 00290 * Average fiber for this cluster representing the main direction and curvature of this cluster. 00291 * 00292 * \note This member is mutable as it needs to be modified during a const getter. 00293 */ 00294 mutable boost::shared_ptr< WFiber > m_centerLine; 00295 00296 /** 00297 * The longest fiber in the dataset. 00298 * 00299 * \note This member is mutable as it needs to be modified during a const getter. 00300 */ 00301 mutable boost::shared_ptr< WFiber > m_longestLine; 00302 }; 00303 00304 inline bool WFiberCluster::empty() const 00305 { 00306 return m_memberIndices.empty(); 00307 } 00308 00309 inline void WFiberCluster::sort() 00310 { 00311 m_memberIndices.sort(); 00312 } 00313 00314 inline size_t WFiberCluster::size() const 00315 { 00316 return m_memberIndices.size(); 00317 } 00318 00319 inline void WFiberCluster::clear() 00320 { 00321 m_memberIndices.clear(); 00322 } 00323 00324 inline void WFiberCluster::setColor( WColor color ) 00325 { 00326 m_color = color; 00327 } 00328 00329 inline WColor WFiberCluster::getColor() const 00330 { 00331 return m_color; 00332 } 00333 00334 inline const std::string WFiberCluster::getName() const 00335 { 00336 return "FiberCluster"; 00337 } 00338 00339 inline const std::string WFiberCluster::getDescription() const 00340 { 00341 return "A collection of indices for fibers representing a fiber cluster"; 00342 } 00343 00344 inline bool WFiberCluster::operator==( const WFiberCluster& other ) const 00345 { 00346 return m_memberIndices == other.m_memberIndices; 00347 } 00348 00349 inline bool WFiberCluster::operator!=( const WFiberCluster& other ) const 00350 { 00351 return m_memberIndices != other.m_memberIndices; 00352 } 00353 00354 inline const std::list< size_t >& WFiberCluster::getIndices() const 00355 { 00356 return m_memberIndices; 00357 } 00358 00359 inline void WFiberCluster::setIndices( const std::list< size_t >& indices ) 00360 { 00361 m_memberIndices = indices; 00362 } 00363 00364 inline std::ostream& operator<<( std::ostream& os, const WFiberCluster& c ) 00365 { 00366 using string_utils::operator<<; 00367 return os << c.getIndices(); 00368 } 00369 00370 #endif // WFIBERCLUSTER_H