00001
00002
00003
00004
00005
00006
00007
00008 #ifndef IMPALGEBRA_GRID_3D_H
00009 #define IMPALGEBRA_GRID_3D_H
00010
00011 #include "algebra_config.h"
00012
00013 #include <IMP/base_types.h>
00014 #include "Vector3D.h"
00015 #include "BoundingBoxD.h"
00016 #include "internal/grid_3d.h"
00017 #include <boost/iterator/transform_iterator.hpp>
00018
00019 #include <limits>
00020
00021 IMPALGEBRA_BEGIN_NAMESPACE
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 template <class VT>
00047 class Grid3D
00048 {
00049 public:
00050
00051 typedef VT Voxel;
00052
00053 #ifndef IMP_DOXYGEN
00054 typedef internal::GridIndex Index;
00055 typedef internal::VirtualGridIndex ExtendedIndex;
00056 typedef typename std::vector<VT>::reference reference;
00057 typedef typename std::vector<VT>::const_reference const_reference;
00058 #endif
00059
00060 private:
00061 std::vector<VT> data_;
00062 int d_[3];
00063 BoundingBoxD<3> bbox_;
00064 double edge_size_[3];
00065
00066 struct GetVoxel {
00067 mutable Grid3D<VT> *home_;
00068 GetVoxel(Grid3D<VT> *home): home_(home) {}
00069 typedef reference result_type;
00070 typedef const Index& argument_type;
00071 result_type operator()(argument_type i) const {
00072 return home_->operator[](i);
00073 }
00074 };
00075
00076 struct ConstGetVoxel {
00077 const Grid3D<VT> *home_;
00078 ConstGetVoxel(const Grid3D<VT> *home): home_(home) {}
00079 typedef reference result_type;
00080 typedef const Index& argument_type;
00081 result_type operator()(argument_type i) const {
00082 return home_->operator[](i);
00083 }
00084 };
00085
00086 unsigned int index(const Index &i) const {
00087 unsigned int ii= i[2]*d_[0]*d_[1] + i[1]*d_[0]+i[0];
00088 IMP_INTERNAL_CHECK(ii < data_.size(), "Invalid grid index "
00089 << i[0] << " " << i[1] << " " << i[2]
00090 << ": " << d_[0] << " " << d_[1] << " " << d_[2]);
00091 return ii;
00092 }
00093
00094 int snap(unsigned int dim, int v) const {
00095 IMP_INTERNAL_CHECK(dim <3, "Invalid dim");
00096 if (v < 0) return 0;
00097 else if (v > d_[dim]) return d_[dim];
00098 else return v;
00099 }
00100
00101 Index snap(const ExtendedIndex &v) const {
00102 return Index(snap(0, v[0]),
00103 snap(1, v[1]),
00104 snap(2, v[2]));
00105 }
00106 std::pair<Index, ExtendedIndex> empty_range() const {
00107 return std::make_pair(Index(0,0,0), ExtendedIndex(0,0,0));
00108 }
00109
00110 std::pair<Index, ExtendedIndex> intersect(ExtendedIndex l,
00111 ExtendedIndex u) const {
00112 Index rlb;
00113 ExtendedIndex rub;
00114 for (unsigned int i=0; i< 3; ++i) {
00115 if (u[i] <= 0) return empty_range();
00116 if (l[i] >= d_[i]) return empty_range();
00117 }
00118 return std::make_pair(snap(l), snap(u));
00119 }
00120
00121 public:
00122
00123
00124
00125
00126
00127
00128
00129
00130 Grid3D(int xd, int yd, int zd,
00131 const BoundingBoxD<3> &bb,
00132 Voxel def=Voxel()): data_(xd*yd*zd, def),
00133 bbox_(bb) {
00134 IMP_USAGE_CHECK(xd > 0 && yd>0 && zd>0,
00135 "Can't have empty grid");
00136 d_[0]=xd;
00137 d_[1]=yd;
00138 d_[2]=zd;
00139 for (unsigned int i=0; i< 3; ++i) {
00140 double side= bbox_.get_corner(1)[i]- bbox_.get_corner(0)[i];
00141 IMP_USAGE_CHECK(side>0, "Can't have flat grid");
00142 edge_size_[i]= 1.01*side/d_[i];
00143 }
00144 }
00145
00146
00147
00148
00149
00150
00151
00152
00153 Grid3D(float side,
00154 const BoundingBoxD<3> &bb,
00155 Voxel def=Voxel()) {
00156 IMP_USAGE_CHECK(side>0, "Side cannot be 0");
00157 for (unsigned int i=0; i< 3; ++i ) {
00158 double bside= bb.get_corner(1)[i]- bb.get_corner(0)[i];
00159 d_[i]= static_cast<int>(std::ceil(bside / side))+1;
00160 edge_size_[i]= side;
00161 }
00162 bbox_=BoundingBoxD<3>(bb.get_corner(0), bb.get_corner(0)
00163 +VectorD<3>(d_[0]*edge_size_[0],
00164 d_[1]*edge_size_[1],
00165 d_[2]*edge_size_[2]));
00166 IMP_IF_CHECK(USAGE_AND_INTERNAL) {
00167 for (unsigned int i=0; i< 3; ++i) {
00168 IMP_INTERNAL_CHECK(bbox_.get_corner(1)[i] >= bb.get_corner(1)[i],
00169 "Old bounding box not subsumed in new.");
00170 }
00171 }
00172 data_.resize(d_[0]*d_[1]*d_[2], def);
00173 }
00174
00175
00176 Grid3D(){
00177 d_[0]=0;
00178 d_[1]=0;
00179 d_[2]=0;
00180 }
00181
00182 BoundingBoxD<3> get_bounding_box() const {
00183 return bbox_;
00184 }
00185
00186
00187 void set_bounding_box(const BoundingBoxD<3> &bb3) {
00188 bbox_ =bb3;
00189 for (unsigned int i=0; i< 3; ++i) {
00190 double el= (bb3.get_corner(1)[i]- bb3.get_corner(0)[i])/d_[i];
00191 edge_size_[i]=el;
00192 }
00193 }
00194
00195
00196 VectorD<3> get_unit_cell() const {
00197 return VectorD<3>(edge_size_[0], edge_size_[1], edge_size_[2]);
00198 }
00199
00200
00201 unsigned int get_number_of_voxels(unsigned int i) const {
00202 IMP_INTERNAL_CHECK(i < 3, "Only 3D: "<< i);
00203 return d_[i];
00204 }
00205
00206
00207 #if defined(IMP_DOXYGEN) || defined(SWIG)
00208
00209 Voxel& operator[](const VectorD<3> &v);
00210
00211
00212 const Voxel operator[](const VectorD<3> &v) const;
00213 const Voxel& get_voxel(const VectorD<3> &v) const;
00214 #else
00215 reference operator[](const VectorD<3> &v) {
00216 return data_[get_index(index(v))];
00217 }
00218 const_reference operator[](const VectorD<3> &v) const {
00219 return data_[get_index(index(v))];
00220 }
00221 const_reference get_voxel(const VectorD<3> &v) const {
00222 return operator[](v);
00223 }
00224 #endif
00225
00226
00227
00228 #ifndef IMP_DOXYGEN
00229
00230 Index get_index(VectorD<3> pt) const {
00231 IMP_USAGE_CHECK(bbox_.get_contains(pt),
00232 "Point " << pt << " is not part of grid "
00233 << bbox_);
00234 int index[3];
00235 for (unsigned int i=0; i< 3; ++i ) {
00236 IMP_INTERNAL_CHECK(d_[i] != 0, "Invalid grid in Index");
00237 double d = pt[i] - bbox_.get_corner(0)[i];
00238 double fi= d/edge_size_[i];
00239 index[i]= std::min(static_cast<int>(std::floor(fi)),
00240 d_[i]-1);
00241 }
00242 return Index(index[0], index[1], index[2]);
00243 }
00244
00245
00246
00247
00248
00249 ExtendedIndex get_extended_index(VectorD<3> pt) const {
00250
00251 if (bbox_.get_contains(pt)) return get_index(pt);
00252 int index[3];
00253 for (unsigned int i=0; i< 3; ++i ) {
00254 IMP_INTERNAL_CHECK(d_[i] != 0, "Invalid grid in Index");
00255 float d = pt[i] - bbox_.get_corner(0)[i];
00256 float fi= d/edge_size_[i];
00257 index[i]= static_cast<int>(std::floor(fi));
00258
00259 IMP_INTERNAL_CHECK(std::abs(index[i]) < 200000000,
00260 "Something is probably wrong " << d
00261 << " " << pt[i]
00262 << " " << bbox_
00263 << " " << edge_size_[i]);
00264 }
00265 return ExtendedIndex(index[0], index[1], index[2]);
00266 }
00267
00268 ExtendedIndex get_extended_index(int a, int b, int c) const {
00269 return ExtendedIndex(a,b,c);
00270 }
00271
00272
00273 ExtendedIndex get_offset(ExtendedIndex v, int xi, int yi, int zi) const {
00274 return ExtendedIndex(v[0]+xi, v[1]+yi, v[2]+zi);
00275 }
00276
00277
00278 bool get_is_index(ExtendedIndex v) const {
00279 for (unsigned int i=0; i< 3; ++i) {
00280 if (v[i] < 0 || v[i] >= d_[i]) return false;
00281 }
00282 return true;
00283 }
00284
00285
00286
00287
00288 Index get_index(ExtendedIndex v) const {
00289 IMP_USAGE_CHECK(get_is_index(v), "Passed index not in grid "
00290 << v);
00291 return Index(v[0], v[1], v[2]);
00292 }
00293
00294 BoundingBoxD<3> get_bounding_box(ExtendedIndex v) const {
00295 VectorD<3> l=bbox_.get_corner(0)+ VectorD<3>(get_unit_cell()[0]*v[0],
00296 get_unit_cell()[1]*v[1],
00297 get_unit_cell()[2]*v[2]);
00298 VectorD<3> u=bbox_.get_corner(0)+ VectorD<3>(get_unit_cell()[0]*(v[0]+1),
00299 get_unit_cell()[1]*(v[1]+1),
00300 get_unit_cell()[2]*(v[2]+1));
00301 return BoundingBoxD<3>(l,u);
00302 }
00303
00304 reference operator[](Index gi) {
00305 return data_[index(gi)];
00306 }
00307 const_reference operator[](Index gi) const {
00308 return data_[index(gi)];
00309 }
00310 const_reference get_voxel(Index gi) const {
00311 return operator[](gi);
00312 }
00313
00314
00315 VectorD<3> get_center(ExtendedIndex gi) const {
00316 return VectorD<3>(edge_size_[0]*(.5+ gi[0]) + bbox_.get_corner(0)[0],
00317 edge_size_[1]*(.5+ gi[1]) + bbox_.get_corner(0)[1],
00318 edge_size_[2]*(.5+ gi[2]) + bbox_.get_corner(0)[2]);
00319 }
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342 typedef internal::GridIndexIterator<Index> IndexIterator;
00343 IndexIterator indexes_begin(ExtendedIndex lb,
00344 ExtendedIndex ub) const {
00345 ExtendedIndex eub=get_offset(ub, 1,1,1);
00346 std::pair<Index, ExtendedIndex> bp= intersect(lb,eub);
00347 if (bp.first== bp.second) {
00348 return IndexIterator();
00349 } else {
00350 IMP_INTERNAL_CHECK(bp.second.strictly_larger_than(bp.first),
00351 "empty range");
00352 return IndexIterator(bp.first, bp.second);
00353 }
00354 }
00355 IndexIterator indexes_end(ExtendedIndex,
00356 ExtendedIndex) const {
00357
00358 return IndexIterator();
00359 }
00360
00361 IndexIterator all_indexes_begin() const {
00362 return indexes_begin(ExtendedIndex(0,0,0),
00363 ExtendedIndex(d_[0],
00364 d_[1],
00365 d_[2]));
00366 }
00367 IndexIterator all_indexes_end() const {
00368 return indexes_end(ExtendedIndex(0,0,0),
00369 ExtendedIndex(d_[0],
00370 d_[1],
00371 d_[2]));
00372 }
00373
00374 #endif
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386 #ifdef IMP_DOXYGEN
00387 class VoxelIterator;
00388 class VoxelConstIterator;
00389 class AllVoxelIterator;
00390 class AllVoxelConstIterator;
00391 #else
00392 typedef boost::transform_iterator<GetVoxel, IndexIterator> VoxelIterator;
00393 typedef boost::transform_iterator<ConstGetVoxel,
00394 IndexIterator> VoxelConstIterator;
00395 typedef typename std::vector<VT>::iterator AllVoxelIterator;
00396 typedef typename std::vector<VT>::iterator AllVoxelConstIterator;
00397 #endif
00398 VoxelIterator voxels_begin(const BoundingBoxD<3> &bb) {
00399 ExtendedIndex lb= get_extended_index(bb.get_corner(0));
00400 ExtendedIndex ub= get_extended_index(bb.get_corner(1));
00401 return VoxelIterator(indexes_begin(lb, ub), GetVoxel(this));
00402 }
00403 VoxelIterator voxels_end(const BoundingBoxD<3> &bb) {
00404
00405
00406 return VoxelIterator(indexes_end(ExtendedIndex(),
00407 ExtendedIndex()), GetVoxel(this));
00408 }
00409
00410 VoxelConstIterator voxels_begin(const BoundingBoxD<3> &bb) const {
00411 ExtendedIndex lb= get_extended_index(bb.get_corner(0));
00412 ExtendedIndex ub= get_extended_index(bb.get_corner(1));
00413 return VoxelConstIterator(indexes_begin(lb, ub), ConstGetVoxel(this));
00414 }
00415 VoxelConstIterator voxels_end(const BoundingBoxD<3> &bb) const {
00416 ExtendedIndex lb= get_extended_index(bb.get_corner(0));
00417 ExtendedIndex ub= get_extended_index(bb.get_corner(1));
00418 return VoxelConstIterator(indexes_end(ExtendedIndex(),
00419 ExtendedIndex()),
00420 ConstGetVoxel(this));
00421 }
00422
00423 AllVoxelIterator voxels_begin() { return data_.begin();}
00424 AllVoxelIterator voxels_end() { return data_.end();}
00425 AllVoxelConstIterator voxels_begin() const { return data_.begin();}
00426 AllVoxelConstIterator voxels_end() const { return data_.end();}
00427
00428 };
00429
00430
00431 IMPALGEBRA_END_NAMESPACE
00432
00433 #endif