00001 /** 00002 * \file DensityMap.h 00003 * \brief Class for handling density maps. 00004 * 00005 * Copyright 2007-2010 IMP Inventors. All rights reserved. 00006 * 00007 */ 00008 00009 #ifndef IMPEM_DENSITY_MAP_H 00010 #define IMPEM_DENSITY_MAP_H 00011 00012 #include "em_config.h" 00013 #include "DensityHeader.h" 00014 #include "MapReaderWriter.h" 00015 #include <IMP/Object.h> 00016 #include <IMP/algebra/Vector3D.h> 00017 #include <IMP/algebra/BoundingBoxD.h> 00018 #include <IMP/algebra/Transformation3D.h> 00019 #include <IMP/VectorOfRefCounted.h> 00020 #include <boost/scoped_array.hpp> 00021 #include <iostream> 00022 #include <iomanip> 00023 00024 IMPEM_BEGIN_NAMESPACE 00025 00026 class DensityMap; 00027 00028 /** Read a density map from a file and return it. 00029 \relatesalso DensityMap 00030 */ 00031 IMPEMEXPORT DensityMap* read_map(const char *filename, MapReaderWriter &reader); 00032 00033 /** Read a density map from a file and return it. Guess the file type from the 00034 file name. The file formats supported are: 00035 - .mrc for MRC files 00036 \relatesalso DensityMap 00037 */ 00038 IMPEMEXPORT DensityMap* read_map(const char *filename); 00039 00040 00041 /** Write a density map to a file. 00042 \relatesalso DensityMap 00043 */ 00044 IMPEMEXPORT void write_map(DensityMap* m, const char *filename, 00045 MapReaderWriter &writer); 00046 //! 00047 /** 00048 \param[in] m a density map 00049 \param[in] threshold find the boudning box for voxels 00050 with value above the threshold 00051 */ 00052 IMPEMEXPORT algebra::BoundingBoxD<3> 00053 get_bounding_box(DensityMap* m, Float threshold); 00054 //! 00055 /** 00056 \param[in] m a density map 00057 \param[in] threshold consider volume of only voxels above this threshold 00058 \note The method assumes 1.21 cubic A per dalton (Harpaz 1994). 00059 */ 00060 IMPEMEXPORT Float approximate_molecular_mass(DensityMap* m, Float threshold); 00061 00062 00063 //! Class for handling density maps. 00064 /** /note The location of a voxel is its center. That is important 00065 for sampling function as well as for functions like voxel2loc. 00066 */ 00067 class IMPEMEXPORT DensityMap: public Object 00068 { 00069 IMP_NO_SWIG(friend IMPEMEXPORT DensityMap* read_map(const char *filename, 00070 MapReaderWriter &reader)); 00071 IMP_NO_SWIG(friend IMPEMEXPORT void write_map(DensityMap* m, 00072 const char *filename, 00073 MapReaderWriter &writer)); 00074 00075 public: 00076 DensityMap(); 00077 DensityMap(const DensityMap &other); 00078 DensityMap& operator=(const DensityMap &other ); 00079 //! Creates a new map with the given dimension 00080 /** 00081 param[in] nx x-dimension (voxels) 00082 param[in] ny y-dimension (voxels) 00083 param[in] nz z-dimension (voxels) 00084 */ 00085 void CreateVoidMap(const int &nx,const int &ny,const int &nz); 00086 00087 #ifndef IMP_DOXYGEN 00088 #ifndef IMP_DEPRECATED 00089 /** \deprecated Use read() instead.*/ 00090 void Read(const char *filename, MapReaderWriter &reader); 00091 /** \deprecated Use write() instead.*/ 00092 void Write(const char *filename,MapReaderWriter &writer); 00093 #endif 00094 #endif 00095 00096 00097 //! Set the density voxels to some calue and reset the managment flags. 00098 /** 00099 \param[in] value all of the density voxels will have this value 00100 */ 00101 void reset_data(float value=0.0); 00102 00103 //! Calculates RMSD and mean of a map values are stored in the header. 00104 /** The header stores whether map is normalized. 00105 */ 00106 emreal calcRMS(); 00107 00108 00109 //! Normailze the density voxles according to standard deviation (stdv). 00110 /** The mean is subtracted from the map, which is then divided by the stdv. 00111 The normalization flag is set to avoid repeated computation */ 00112 void std_normalize(); 00113 00114 inline bool is_normalized() const {return normalized_;} 00115 00116 //! Calculate the location of a given voxel. 00117 /** \param[in] index The voxel index 00118 \param[in] dim The dimesion of intereset ( between x:=0,y:=1,z:=2) 00119 \return the location (x,y,z) (in angstroms) of a given voxel. If the 00120 index is not part of the map, the function returns -1. 00121 \todo change to const and throw exception if loc_calculated == false 00122 */ 00123 float voxel2loc(const int &index,int dim) const; 00124 00125 00126 //! Calculate the voxel of a given xyz indexes 00127 /** \param[in] x The voxel index on the x axis of the grid 00128 \param[in] y The voxel index on the y axis of the grid 00129 \param[in] z The voxel index on the z axis of the grid 00130 \return the voxel index. 00131 */ 00132 long xyz_ind2voxel(int x,int y,int z) const; 00133 00134 //! Calculate the voxel of a given location 00135 /** \param[in] x The position ( in angstroms) of the x coordinate 00136 \param[in] y The position ( in angstroms) of the y coordinate 00137 \param[in] z The position ( in angstroms) of the z coordinate 00138 \exception IndexException The point is not covered by the grid. 00139 \return the voxel index of a given position. If the position is out of 00140 the boundaries of the map, the function returns -1. 00141 */ 00142 long loc2voxel(float x, float y, float z) const; 00143 long loc2voxel(const algebra::VectorD<3> &v) const { 00144 return loc2voxel(v[0],v[1],v[2]); 00145 } 00146 00147 bool is_xyz_ind_part_of_volume(int ix,int iy,int iz) const; 00148 00149 //! Checks whether a given point is in the grid the voxel of a given location 00150 /** \param[in] x The position ( in angstroms) of the x coordinate 00151 \param[in] y The position ( in angstroms) of the y coordinate 00152 \param[in] z The position ( in angstroms) of the z coordinate 00153 \return true if the point is part of the grid, false otherwise. 00154 */ 00155 bool is_part_of_volume(float x,float y,float z) const; 00156 //! Checks whether a given point is in the grid the voxel of a given location 00157 /** \param[in] v The position ( in angstroms) 00158 \return true if the point is part of the grid, false otherwise. 00159 */ 00160 bool is_part_of_volume(const algebra::VectorD<3> &v) const { 00161 return is_part_of_volume(v[0],v[1],v[2]); 00162 } 00163 00164 //! Gets the value of the voxel located at (x,y,z) 00165 /** \param[in] x The position ( in angstroms) of the x coordinate 00166 \param[in] y The position ( in angstroms) of the y coordinate 00167 \param[in] z The position ( in angstroms) of the z coordinate 00168 \return the value of the voxel located at (x,y,z) 00169 \exception IndexException The point is not covered by the grid. 00170 */ 00171 emreal get_value(float x,float y,float z) const; 00172 emreal get_value(const algebra::VectorD<3> &point) const { 00173 return get_value(point[0],point[1],point[2]); 00174 } 00175 00176 00177 //! Gets the value of the voxel at a given index 00178 /** 00179 \param[in] index voxel number in physical sense, NOT logical 00180 */ 00181 emreal get_value(long index) const; 00182 00183 00184 //! Set the value of the voxel at a given index 00185 /** 00186 \param[in] index voxel number in physical sense, NOT logical 00187 \param[in] value value 00188 */ 00189 void set_value(long index,emreal value); 00190 00191 00192 //! Set the value of the voxel at a given index 00193 /** 00194 index voxel number in physical sense, NOT logical 00195 */ 00196 void set_value(float x, float y, float z,emreal value); 00197 00198 //! Sets the origin of the header 00199 /** 00200 \param x the new x (angstroms) 00201 \param y the new y (angstroms) 00202 \param z the new z (angstroms) 00203 */ 00204 void set_origin(float x,float y,float z); 00205 void set_origin(const IMP::algebra::VectorD<3> &v) { 00206 set_origin(v[0],v[1],v[2]); 00207 } 00208 00209 algebra::VectorD<3> get_origin() const{ 00210 return algebra::Vector3D(header_.get_origin(0), 00211 header_.get_origin(1), 00212 header_.get_origin(2)); 00213 } 00214 00215 algebra::VectorD<3> get_top() const { 00216 return algebra::Vector3D(header_.get_top(0), 00217 header_.get_top(1), 00218 header_.get_top(2)); 00219 } 00220 00221 // inspection functions 00222 const DensityHeader *get_header()const {return &header_;} 00223 //! Returns a pointer to the header of the map in a writable version 00224 DensityHeader *get_header_writable() {return &header_;} 00225 00226 //! Returns the x-location of the map 00227 /** 00228 \exception InvalidStateException The locations have not been calculated. 00229 */ 00230 float* get_x_loc() const { 00231 IMP_USAGE_CHECK(loc_calculated_, 00232 "x location requested before being calculated"); 00233 return x_loc_.get(); 00234 } 00235 //! Returns the y-location of the map 00236 /** 00237 \exception InvalidStateException The locations have not been calculated. 00238 */ 00239 float* get_y_loc() const { 00240 IMP_USAGE_CHECK(loc_calculated_, 00241 "y location requested before being calculated"); 00242 return y_loc_.get(); 00243 } 00244 //! Returns the z-location of the map 00245 /** 00246 \exception InvalidStateException The locations have not been calculated. 00247 */ 00248 float* get_z_loc() const { 00249 IMP_USAGE_CHECK(loc_calculated_, 00250 "z location requested before being calculated"); 00251 return z_loc_.get(); 00252 } 00253 00254 emreal* get_data() const {return data_.get();} 00255 00256 //! Checks if two maps have the same origin 00257 /** \param[in] other the map to compare with 00258 \return true if the two maps have the same origin 00259 */ 00260 bool same_origin(const DensityMap &other) const; 00261 00262 //! Checks if two maps have the same dimensions 00263 /** \param[in] other the map to compare with 00264 \return true if the two maps have the same dimensions 00265 */ 00266 bool same_dimensions(const DensityMap &other) const; 00267 00268 //! Checks if two maps have the same voxel size 00269 /** \param[in] other the map to compare with 00270 \return true if the two maps have the same voxel size 00271 */ 00272 bool same_voxel_size(const DensityMap &other) const; 00273 //! Calculates the centroid of all the voxels with 00274 //! density above a given threshold 00275 /** \param[in] threshold the input threshold 00276 */ 00277 algebra::VectorD<3> get_centroid(emreal threshold=0.0) const; 00278 //! Returns the the value of the voxel with the highest density. 00279 emreal get_max_value() const; 00280 //! Returns the the value of the voxel with the lowest density. 00281 emreal get_min_value() const; 00282 //! Sums two grids. 00283 //! The result is kept in the map. 00284 //! The two maps should have the same dimensions and the same voxelsize 00285 /** \param[in] other the other map 00286 */ 00287 void add(const DensityMap &other); 00288 00289 long get_number_of_voxels() const; 00290 00291 //! Increase the dimension of the map 00292 //! The function pads zeros to the right-upper section on the map. 00293 //! The original content of the map will be in the lower XYZ part of the map 00294 /** \param[in] nx the number of voxels on the X axis 00295 \param[in] ny the number of voxels on the Y axis 00296 \param[in] nz the number of voxels on the Z axis 00297 \param[in] val all additional voxels will have this value 00298 \exception if the input x/y/z voxels is smaller than the one 00299 currently in the map 00300 */ 00301 void pad(int nx, int ny, int nz,float val=0.0); 00302 00303 //! Multiply each voxel in the map by the input factor 00304 //! The result is kept in the map. 00305 /** \param[in] factor the multiplication factor 00306 */ 00307 void multiply(float factor); 00308 00309 //! Prints the locations of all of the voxels with value above a given 00310 //! threshold into the input stream. 00311 std::string get_locations_string(float t); 00312 00313 //! Updated the voxel size of the map 00314 void update_voxel_size(float new_apix); 00315 00316 //! Updated the voxel size of the map 00317 /** \note Use update_voxel_size() to set the spacing value. 00318 */ 00319 Float get_spacing() const {return header_.get_spacing();} 00320 //! Calculates the coordinates that correspond to all voxels. 00321 /** Can be precomputed to make corr faster. 00322 \todo which is a better design - have it public or call it from voxel2loc? 00323 */ 00324 void calc_all_voxel2loc(); 00325 00326 IMP_OBJECT_INLINE(DensityMap, header_.show(out),); 00327 00328 protected: 00329 //!update the header values -- still in work 00330 void update_header(); 00331 void reset_voxel2loc(); 00332 00333 void allocated_data(); 00334 void float2real(float *f_data, boost::scoped_array<emreal> &r_data); 00335 void real2float(emreal *r_data, boost::scoped_array<float> &f_data); 00336 00337 DensityHeader header_; // holds all the info about the map 00338 boost::scoped_array<emreal> data_; // the order is ZYX (Z-slowest) 00339 bool data_allocated_; 00340 00341 //! Locations for each of the voxels of the map (they are precomputed and 00342 //! each one is of size nvox, being nvox the size of the map) 00343 boost::scoped_array<float> x_loc_, y_loc_, z_loc_; 00344 //! true if the locations have already been computed 00345 bool loc_calculated_; 00346 00347 bool normalized_; 00348 bool rms_calculated_; 00349 00350 }; 00351 00352 inline algebra::BoundingBoxD<3> get_bounding_box(const DensityMap *m) { 00353 return algebra::BoundingBoxD<3>(m->get_origin(), 00354 m->get_top()); 00355 } 00356 //! rotate a grid 00357 /** 00358 /param[in] orig_dens the density map to rotate 00359 /param[in] trans the transformation 00360 \note this is a low resolution operation. 00361 IMPEMEXPORT DensityMap* rotate_grid(const DensityMap *orig_dens, 00362 const algebra::Transformation3D &trans); 00363 */ 00364 00365 IMP_OBJECTS(DensityMap); 00366 /** \objects{DensityMap} 00367 */ 00368 /** \objectstemp{DensityMap} 00369 */ 00370 00371 /** Return the value for the density map, m, at point v, interpolating linearly 00372 from the sample values. The resulting function is C0 over R3. 00373 \relatesalso DensityMap 00374 */ 00375 IMPEMEXPORT double get_density(DensityMap *m, const algebra::VectorD<3> &v); 00376 00377 /** Return a new density map containing a rotated version of the old 00378 one. Only voxels whose value is above threshold are considered when 00379 computing the bounding box of the new map (set IMP::em::get_bounding_box()). 00380 \relatesalso DensityMap 00381 */ 00382 IMPEMEXPORT DensityMap* get_transformed(DensityMap *in, 00383 const algebra::Transformation3D &tr, 00384 double threshold); 00385 00386 /** Return a new density map containing a rotated version of the old 00387 one. The dimension of the new map is the same as the old one. 00388 \relatesalso DensityMap 00389 */ 00390 IMPEMEXPORT DensityMap* get_transformed(DensityMap *in, 00391 const algebra::Transformation3D &tr); 00392 00393 00394 /** Get a resampled version of the map. The spacing is multiplied by scaling. 00395 That means, scaling values greater than 1 increase the voxel size.*/ 00396 IMPEMEXPORT DensityMap* get_resampled(DensityMap *in, double scaling); 00397 00398 IMPEM_END_NAMESPACE 00399 00400 #endif /* IMPEM_DENSITY_MAP_H */