00001
00002
00003
00004
00005
00006
00007 #ifndef BALL_DATATYPE_CONTOURSURFACE_H
00008 #define BALL_DATATYPE_CONTOURSURFACE_H
00009
00010 #ifndef BALL_COMMON_H
00011 # include <BALL/common.h>
00012 #endif
00013
00014 #ifndef BALL_DATATYPE_REGULARDATA3D_H
00015 # include <BALL/DATATYPE/regularData3D.h>
00016 #endif
00017
00018 #ifndef BALL_MATHS_SURFACE_H
00019 # include <BALL/MATHS/surface.h>
00020 #endif
00021
00022 #ifndef BALL_DATATYPE_HASHMAP_H
00023 # include <BALL/DATATYPE/hashMap.h>
00024 #endif
00025
00026 #include <vector>
00027 #include <math.h>
00028
00029 #ifdef BALL_HAS_HASH_MAP
00030 namespace BALL_MAP_NAMESPACE
00031 {
00032 template<>
00033 struct hash<std::pair<BALL::Position, BALL::Position> >
00034 {
00035 size_t operator () (const std::pair<BALL::Position, BALL::Position>& p) const
00036 {return (size_t)(p.first + p.second);}
00037 };
00038 }
00039 #endif
00040
00041 namespace BALL
00042 {
00043 template<>
00044 BALL_EXPORT HashIndex Hash(const std::pair<Position, Position>& p);
00045
00046
00047 typedef Index FacetArray[256][12];
00048
00049
00050 BALL_EXPORT extern const FacetArray& getContourSurfaceFacetData(double threshold);
00051
00058 template <typename T>
00059 class TContourSurface
00060 : public Surface
00061 {
00062 public:
00063
00067
00070 typedef std::pair<Position, Position> KeyType;
00071
00075 typedef Vector3 PointType;
00076
00080 typedef std::vector<std::pair<PointType, std::pair<Position, Position> > > VectorType;
00082
00086
00088 TContourSurface();
00089
00091 TContourSurface(T threshold);
00092
00094 TContourSurface(const TContourSurface& surface);
00095
00097 TContourSurface(const TRegularData3D<T>& data, T threshold = 0.0);
00098
00100 virtual ~TContourSurface();
00102
00106
00108 const TContourSurface& operator = (const TContourSurface<T>& surface);
00109
00111 const TContourSurface<T>& operator << (const TRegularData3D<T>& data);
00112
00114 virtual void clear();
00116
00120
00122 bool operator == (const TContourSurface<T>& surface) const;
00123
00125
00126
00127 protected:
00128
00134 class Cube
00135 {
00136 public:
00137
00138 Cube(const TRegularData3D<T>& grid)
00139 : grid_(&grid),
00140 current_position_(0),
00141 ptr_(0),
00142 spacing_(grid.getSpacing().x, grid.getSpacing().y, grid.getSpacing().z)
00143 {
00144
00145 Size nx = grid.getSize().x;
00146 Size ny = grid.getSize().y;
00147
00148
00149
00150 grid_offset_[0] = nx * ny;
00151 grid_offset_[1] = 0;
00152 grid_offset_[2] = 1;
00153 grid_offset_[3] = 1 + nx * ny;
00154 grid_offset_[4] = nx * ny + nx;
00155 grid_offset_[5] = nx;
00156 grid_offset_[6] = nx + 1;
00157 grid_offset_[7] = nx * ny + nx + 1;
00158 }
00159
00160 void setTo(Position p)
00161 {
00162 current_position_ = p;
00163
00164 ptr_ = &(const_cast<TRegularData3D<T>*>(grid_)->getData(current_position_));
00165 for (Position i = 0; i < 8; i++)
00166 {
00167 values[i] = *(ptr_ + grid_offset_[i]);
00168 }
00169 }
00170
00171 inline Vector3 getOrigin() const
00172 {
00173 return grid_->getCoordinates(current_position_);
00174 }
00175
00176 inline const Vector3& getSpacing() const
00177 {
00178 return spacing_;
00179 }
00180
00181 inline Vector3 getCoordinates(Position index) const
00182 {
00183 return grid_->getCoordinates(index);
00184 }
00185
00187 inline Position getIndex(Position corner) const
00188 {
00189 return current_position_ + grid_offset_[corner];
00190 }
00191
00192 void shift()
00193 {
00194
00195 current_position_++;
00196 ptr_++;
00197
00198
00199 values[0] = values[3];
00200 values[1] = values[2];
00201 values[4] = values[7];
00202 values[5] = values[6];
00203
00204
00205 values[3] = *(ptr_ + grid_offset_[3]);
00206 values[2] = *(ptr_ + grid_offset_[2]);
00207 values[7] = *(ptr_ + grid_offset_[7]);
00208 values[6] = *(ptr_ + grid_offset_[6]);
00209 }
00210
00212 Position computeTopology(double threshold)
00213 {
00214 static const Position topology_modifier[8] = {1, 2, 4, 8, 16, 32, 64, 128};
00215
00216
00217
00218
00219 Position topology = 0;
00220 for (Position i = 0; i < 8; i++)
00221 {
00222 topology |= ((values[i] > threshold) ? topology_modifier[i] : 0);
00223 }
00224
00225 return topology;
00226 }
00227
00228
00229 double values[8];
00230
00231 protected:
00232
00233
00234 const TRegularData3D<T>* grid_;
00235
00236
00237 Position current_position_;
00238
00239
00240
00241 Position grid_offset_[8];
00242
00243
00244 const T* ptr_;
00245
00246
00247 Vector3 spacing_;
00248 };
00249
00250
00252 void addTriangles_(Cube& cube, const FacetArray& facet_data);
00253
00255 void computeTriangles(Size topology, const TRegularData3D<T>& data);
00256
00258 T threshold_;
00259
00260
00261 HashMap<std::pair<Position, Position>, Position> cut_hash_map_;
00262 };
00263
00265 typedef TContourSurface<float> ContourSurface;
00266
00267 template <typename T>
00268 TContourSurface<T>::TContourSurface()
00269 : threshold_(0.0)
00270 {
00271 }
00272
00273 template <typename T>
00274 TContourSurface<T>::TContourSurface(T threshold)
00275 : threshold_(threshold)
00276 {
00277 }
00278
00279 template <typename T>
00280 TContourSurface<T>::TContourSurface(const TRegularData3D<T>& data, T threshold)
00281 : threshold_(threshold)
00282 {
00283 this->operator << (data);
00284 }
00285
00286 template <typename T>
00287 TContourSurface<T>::~TContourSurface()
00288 {
00289 }
00290
00291 template <typename T>
00292 TContourSurface<T>::TContourSurface(const TContourSurface<T>& from)
00293 : threshold_(from.threshold_)
00294 {
00295 }
00296
00297 template <typename T>
00298 void TContourSurface<T>::clear()
00299 {
00300 Surface::clear();
00301 cut_hash_map_.clear();
00302 }
00303
00304 template <typename T>
00305 const TContourSurface<T>& TContourSurface<T>::operator = (const TContourSurface<T>& data)
00306 {
00307
00308 if (&data != this)
00309 {
00310 threshold_ = data.threshold_;
00311 }
00312
00313 return *this;
00314 }
00315
00316 template <typename T>
00317 bool TContourSurface<T>:: operator == (const TContourSurface<T>& data) const
00318 {
00319 return ((threshold_ == data.threshold_)
00320 && Surface::operator == (data.data_));
00321 }
00322
00323 template <typename T>
00324 const TContourSurface<T>& TContourSurface<T>::operator << (const TRegularData3D<T>& data)
00325 {
00326
00327 clear();
00328
00329
00330
00331
00332
00333
00334 Vector3 origin = data.getOrigin();
00335 Size number_of_cells_x = (Size)data.getSize().x;
00336 Size number_of_cells_y = (Size)data.getSize().y;
00337 Size number_of_cells_z = (Size)data.getSize().z;
00338
00339
00340 const FacetArray& facet_data = getContourSurfaceFacetData(threshold_);
00341
00342
00343 Position current_index = 0;
00344 Cube cube(data);
00345 for (Position curr_cell_z = 0; curr_cell_z < (number_of_cells_z - 1); curr_cell_z++)
00346 {
00347
00348 current_index = curr_cell_z * number_of_cells_y * number_of_cells_x;
00349
00350
00351 for (Position curr_cell_y = 0; curr_cell_y < (number_of_cells_y - 1); curr_cell_y++)
00352 {
00353
00354
00355 cube.setTo(current_index);
00356
00357
00358 for (Position curr_cell_x = 0; (curr_cell_x < (number_of_cells_x - 2)); )
00359 {
00360
00361 addTriangles_(cube, facet_data);
00362
00363
00364
00365 curr_cell_x++;
00366 cube.shift();
00367 }
00368
00369
00370 addTriangles_(cube, facet_data);
00371
00372
00373 current_index += number_of_cells_x;
00374 }
00375 }
00376
00377
00378 for (Position i = 0; i < normal.size(); i++)
00379 {
00380 try
00381 {
00382 normal[i].normalize();
00383 }
00384 catch (...)
00385 {
00386 }
00387 }
00388
00389
00390 return *this;
00391 }
00392
00393 template <typename T>
00394 void TContourSurface<T>::addTriangles_
00395 (typename TContourSurface<T>::Cube& cube, const FacetArray& facet_data)
00396 {
00397
00398
00399
00400 static Triangle t;
00401 static std::pair<Position, Position> key;
00402 static std::pair<Position, Position> indices;
00403
00404
00405 static const Position edge_indices[12][2]
00406 = {{1, 0}, {1, 2}, {2, 3}, {0, 3}, {5, 4}, {5, 6},
00407 {6, 7}, {4, 7}, {0, 4}, {1, 5}, {2, 6}, {3, 7}
00408 };
00409
00410
00411
00412 static const Position edge_axis[12]
00413 = {2, 0, 2, 0, 2, 0, 2, 0, 1, 1, 1, 1};
00414
00415
00416 const Vector3& spacing = cube.getSpacing();
00417
00418
00419
00420 TVector3<Position> triangle_vertices;
00421
00422
00423 Size vertex_counter = 0;
00424
00425
00426 Position topology = cube.computeTopology(threshold_);
00427 if (topology == 0)
00428 {
00429 return;
00430 }
00431
00432
00433
00434 for (Position i = 0; i < 12; i++)
00435 {
00436
00437
00438 Index facet_index = facet_data[topology][i];
00439
00440
00441 if (facet_index != -1)
00442 {
00443
00444
00445
00446 Position edge = edge_axis[facet_index];
00447
00448 indices.first = edge_indices[facet_index][0];
00449 indices.second = edge_indices[facet_index][1];
00450 key.first = cube.getIndex(indices.first);
00451 key.second = cube.getIndex(indices.second);
00452
00453
00454 if (!cut_hash_map_.has(key))
00455 {
00456
00457
00458
00459 Vector3 pos = cube.getCoordinates(key.first);
00460
00461
00462 const double& d1 = cube.values[indices.first];
00463 const double& d2 = cube.values[indices.second];
00464 pos[edge] += ((double)threshold_ - d1) / (d2 - d1) * spacing[edge];
00465
00466
00467 triangle_vertices[vertex_counter++] = vertex.size();
00468
00469
00470
00471 cut_hash_map_.insert(std::pair<std::pair<Position, Position>, Position>(key, (Size)vertex.size()));
00472
00473
00474 vertex.push_back(pos);
00475 static Vector3 null_normal(0.0, 0.0, 0.0);
00476 normal.push_back(null_normal);
00477 }
00478 else
00479 {
00480
00481 triangle_vertices[vertex_counter++] = cut_hash_map_[key];
00482 }
00483
00484
00485 if (vertex_counter == 3)
00486 {
00487
00488 t.v1 = triangle_vertices.x;
00489 t.v2 = triangle_vertices.y;
00490 t.v3 = triangle_vertices.z;
00491 triangle.push_back(t);
00492
00493
00494 vertex_counter = 0;
00495
00496
00497
00498
00499 Vector3 h1(vertex[t.v1] - vertex[t.v2]);
00500 Vector3 h2(vertex[t.v3] - vertex[t.v2]);
00501 Vector3 current_normal(h1.y * h2.z - h1.z * h2.y,
00502 h1.z * h2.x - h2.z * h1.x,
00503 h1.x * h2.y - h1.y * h2.x);
00504 normal[t.v1] += current_normal;
00505 normal[t.v2] += current_normal;
00506 normal[t.v3] += current_normal;
00507 }
00508 }
00509 }
00510 }
00511 }
00512 #endif
00513