Molmodel
|
00001 #ifndef VOXEL_HASH_HPP_ 00002 #define VOXEL_HASH_HPP_ 00003 00004 #include "SimTKsimbody.h" 00005 #include "molmodel/internal/common.h" 00006 #include <vector> 00007 #include <map> 00008 // #include "md_units.hpp" 00009 00010 #ifdef __GNUC__ 00011 #include <ext/hash_map> 00012 #define HASH_MAP_NAMESPACE __gnu_cxx 00013 #else 00014 #include <hash_map> 00015 #define HASH_MAP_NAMESPACE stdext 00016 #endif 00017 00018 // Subystem for managing atom locations. 00019 // Depends on matter subsystem 00020 00021 namespace SimTK { 00022 00023 // Elide use of boost::units for now 00024 namespace units { namespace md 00025 { 00026 typedef Real dimensionless_t; 00027 typedef Real length_t; 00028 typedef Real mass_t; 00029 typedef Real area_t; 00030 typedef Real inverse_volume_t; 00031 typedef Vec3 location_t; 00032 00033 static const Real nanometers = 1.0; 00034 static const Real daltons = 1.0; 00035 static const Real cubic_nanometer = 1.0; 00036 static const Real square_nanometers = 1.0; 00037 }} 00038 00039 template< class T > 00040 class SimTK_MOLMODEL_EXPORT VoxelHash 00041 { 00042 public: 00043 typedef std::pair<SimTK::Vec3, T> VoxelItem; 00044 typedef std::vector< VoxelItem > Voxel; 00045 00046 class VoxelIndex { 00047 public: 00048 VoxelIndex(int x, int y, int z, size_t numBuckets) 00049 : x(x), y(y), z(z), numBuckets(numBuckets) 00050 {} 00051 00052 // operator<() needed for map 00053 bool operator<(const VoxelIndex& other) const { 00054 if (x < other.x) return true; 00055 else if (x > other.x) return false; 00056 else if (y < other.y) return true; 00057 else if (y > other.y) return false; 00058 else if (z < other.z) return true; 00059 else return false; 00060 } 00061 bool operator==(const VoxelIndex& other) const { 00062 if (x != other.x) return false; 00063 else if (y != other.y) return false; 00064 else if (z != other.z) return false; 00065 else return true; 00066 } 00067 00068 // size_t conversion for use by hash_map 00069 operator size_t() const { 00070 return hash_value(); 00071 } 00072 00073 size_t hash_value() const { 00074 // multiply each index by a different large prime number 00075 size_t n = (size_t)(x * 0x8da6b343 + y * 0xd8163841 + z * 0xcb1ab31f); 00076 n = n % numBuckets; 00077 if (n < 0) n += numBuckets; 00078 return n; 00079 } 00080 00081 int x; 00082 int y; 00083 int z; 00084 size_t numBuckets; 00085 }; 00086 00087 private: 00088 VoxelIndex getVoxelIndex(const Vec3& location) const 00089 { 00090 SimTK::Real voxSize = voxelSize; 00091 int x = int(floor(location[0] / voxSize)); 00092 int y = int(floor(location[1] / voxSize)); 00093 int z = int(floor(location[2] / voxSize)); 00094 return VoxelIndex(x, y, z, numBuckets); 00095 } 00096 00097 SimTK::units::md::length_t voxelSize; 00098 00099 // TODO - replace std::map with hash_map or unordered map 00100 // std::map<VoxelIndex, Voxel> voxelMap; 00101 std::map<VoxelIndex, Voxel> voxelMap; 00102 // HASH_MAP_NAMESPACE::hash_map<VoxelIndex, Voxel> voxelMap; 00103 size_t numBuckets; 00104 00105 public: 00106 VoxelHash(SimTK::units::md::length_t voxelSize, int numBuckets) 00107 : voxelSize(voxelSize), numBuckets(numBuckets) 00108 {} 00109 00110 void insert(const T& item, const SimTK::Vec3& location) 00111 { 00112 VoxelIndex voxelIndex = getVoxelIndex(location); 00113 if ( voxelMap.find(voxelIndex) == voxelMap.end() ) voxelMap[voxelIndex] = Voxel(); 00114 Voxel& voxel = voxelMap.find(voxelIndex)->second; 00115 voxel.push_back( VoxelItem(location, item) ); 00116 } 00117 00118 void findNeighbors(std::vector<T>& neighbors, const SimTK::Vec3& locationI, SimTK::units::md::length_t maxDistance) const 00119 { 00120 SimTK::units::md::area_t maxDistanceSquared(maxDistance * maxDistance); 00121 00122 int dIndex = int(maxDistance / voxelSize) + 1; // How may voxels away do we have to look? 00123 VoxelIndex centerVoxelIndex(getVoxelIndex(locationI)); 00124 00125 for (int x = centerVoxelIndex.x - dIndex; x <= centerVoxelIndex.x + dIndex; ++x) 00126 for (int y = centerVoxelIndex.y - dIndex; y <= centerVoxelIndex.y + dIndex; ++y) 00127 for (int z = centerVoxelIndex.z - dIndex; z <= centerVoxelIndex.z + dIndex; ++z) 00128 { 00129 const VoxelIndex voxelIndex(x, y, z, numBuckets); 00130 00131 // TODO - store a list of neighbors for each voxel 00132 if ( voxelMap.find(voxelIndex) == voxelMap.end() ) continue; // no such voxel; skip 00133 00134 const Voxel& voxel = voxelMap.find(voxelIndex)->second; 00135 typename std::vector<VoxelItem>::const_iterator itemIter; 00136 for (itemIter = voxel.begin(); itemIter != voxel.end(); ++itemIter) 00137 { 00138 const SimTK::Vec3 r = locationI - itemIter->first; 00139 SimTK::units::md::area_t dSquared(dot(r, r) * units::md::square_nanometers); 00140 if (dSquared > maxDistanceSquared) continue; // beyond cutoff 00141 00142 neighbors.push_back(itemIter->second); // store neighbor 00143 } 00144 } 00145 } 00146 00147 }; 00148 00149 } // namespace SimTK 00150 00151 00152 #endif /* VOXEL_HASH_HPP_ */