$treeview $search $mathjax
|
Palabos
Version 1.1
$projectbrief
|
$projectbrief
|
$searchbox |
00001 /* This file is part of the Palabos library. 00002 * 00003 * Copyright (C) 2011 FlowKit Sarl 00004 * Avenue de Chailly 23 00005 * 1012 Lausanne, Switzerland 00006 * E-mail contact: contact@flowkit.com 00007 * 00008 * The most recent release of Palabos can be downloaded at 00009 * <http://www.palabos.org/> 00010 * 00011 * The library Palabos is free software: you can redistribute it and/or 00012 * modify it under the terms of the GNU Affero General Public License as 00013 * published by the Free Software Foundation, either version 3 of the 00014 * License, or (at your option) any later version. 00015 * 00016 * The library is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Affero General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Affero General Public License 00022 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00023 */ 00024 00025 #ifndef MARCHING_CUBE_HH 00026 #define MARCHING_CUBE_HH 00027 00028 #include "core/globalDefs.h" 00029 #include "offLattice/marchingCube.h" 00030 00031 namespace plb { 00032 00033 /* ****** class IsoSurfaceDefinition3D ***************** */ 00034 00035 template<typename T> 00036 bool IsoSurfaceDefinition3D<T>::edgeIsValid(plint iX, plint iY, plint iZ, int edge) const 00037 { 00038 switch(edge) { 00039 case 0: { 00040 Array<plint,3> p0(iX ,iY+1,iZ ); 00041 Array<plint,3> p1(iX+1,iY+1,iZ ); 00042 return this->isValid(p0) && this->isValid(p1); // x-edge of y-neighbor. 00043 } 00044 case 1: { 00045 Array<plint,3> p1(iX+1,iY+1,iZ ); 00046 Array<plint,3> p2(iX+1,iY ,iZ ); 00047 return this->isValid(p1) && this->isValid(p2); // y-edge of x-neighbor. 00048 } 00049 case 2: { 00050 Array<plint,3> p2(iX+1,iY ,iZ ); 00051 Array<plint,3> p3(iX ,iY ,iZ ); 00052 return this->isValid(p2) && this->isValid(p3); // x-edge of current cell. 00053 } 00054 case 3: { 00055 Array<plint,3> p3(iX ,iY ,iZ ); 00056 Array<plint,3> p0(iX ,iY+1,iZ ); 00057 return this->isValid(p3) && this->isValid(p0); // y-edge of current cell. 00058 } 00059 case 4: { 00060 Array<plint,3> p4(iX ,iY+1,iZ+1); 00061 Array<plint,3> p5(iX+1,iY+1,iZ+1); 00062 return this->isValid(p4) && this->isValid(p5); // x-edge of y-z-neighbor. 00063 } 00064 case 5: { 00065 Array<plint,3> p5(iX+1,iY+1,iZ+1); 00066 Array<plint,3> p6(iX+1,iY ,iZ+1); 00067 return this->isValid(p5) && this->isValid(p6); // y-edge of x-z-neighbor. 00068 } 00069 case 6: { 00070 Array<plint,3> p6(iX+1,iY ,iZ+1); 00071 Array<plint,3> p7(iX ,iY ,iZ+1); 00072 return this->isValid(p6) && this->isValid(p7); // x-edge of z-neighbor. 00073 } 00074 case 7: { 00075 Array<plint,3> p7(iX ,iY ,iZ+1); 00076 Array<plint,3> p4(iX ,iY+1,iZ+1); 00077 return this->isValid(p7) && this->isValid(p4); // y-edge of z-neighbor. 00078 } 00079 case 8: { 00080 Array<plint,3> p0(iX ,iY+1,iZ ); 00081 Array<plint,3> p4(iX ,iY+1,iZ+1); 00082 return this->isValid(p0) && this->isValid(p4); // z-edge of y-neighbor. 00083 } 00084 case 9: { 00085 Array<plint,3> p1(iX+1,iY+1,iZ ); 00086 Array<plint,3> p5(iX+1,iY+1,iZ+1); 00087 return this->isValid(p1) && this->isValid(p5); // z-edge of x-y-neighbor. 00088 } 00089 case 10: { 00090 Array<plint,3> p2(iX+1,iY ,iZ ); 00091 Array<plint,3> p6(iX+1,iY ,iZ+1); 00092 return this->isValid(p2) && this->isValid(p6); // z-edge of x-neighbor. 00093 } 00094 case 11: { 00095 Array<plint,3> p3(iX ,iY ,iZ ); 00096 Array<plint,3> p7(iX ,iY ,iZ+1); 00097 return this->isValid(p3) && this->isValid(p7); // z-edge of current cell. 00098 } 00099 default: 00100 PLB_ASSERT(false); 00101 return false; 00102 } 00103 } 00104 00105 /* ****** class ScalarFieldIsoSurface3D ***************** */ 00106 00107 template<typename T> 00108 ScalarFieldIsoSurface3D<T>::ScalarFieldIsoSurface3D(std::vector<T> const& isoValues_) 00109 : isoValues(isoValues_), 00110 scalar(0), 00111 location(0,0,0) 00112 { } 00113 00114 template<typename T> 00115 void ScalarFieldIsoSurface3D<T>::setArguments ( 00116 std::vector<AtomicBlock3D*> const& arguments ) 00117 { 00118 PLB_ASSERT( arguments.size() >= 1 ); 00119 scalar = dynamic_cast<ScalarField3D<T>*>(arguments[0]); 00120 PLB_ASSERT(scalar); 00121 location = scalar->getLocation(); 00122 } 00123 00124 template<typename T> 00125 bool ScalarFieldIsoSurface3D<T>::isInside ( 00126 plint surfaceId, Array<plint,3> const& position ) const 00127 { 00128 PLB_ASSERT(scalar); 00129 PLB_ASSERT(surfaceId < (plint)isoValues.size()); 00130 return scalar->get(position[0]-location.x, position[1]-location.y, position[2]-location.z) < isoValues[surfaceId]; 00131 } 00132 00133 template<typename T> 00134 Array<T,3> ScalarFieldIsoSurface3D<T>::getSurfacePosition ( 00135 plint surfaceId, Array<plint,3> const& p1, Array<plint,3> const& p2 ) const 00136 { 00137 static const T epsilon = 1.e-5; 00138 PLB_ASSERT(scalar); 00139 PLB_ASSERT(surfaceId < (plint)isoValues.size()); 00140 T valp1 = scalar->get(p1[0]-location.x, p1[1]-location.y, p1[2]-location.z); 00141 T valp2 = scalar->get(p2[0]-location.x, p2[1]-location.y, p2[2]-location.z); 00142 00143 T isolevel = isoValues[surfaceId]; 00144 if (fabs(isolevel-valp1) < epsilon) return(p1); 00145 if (fabs(isolevel-valp2) < epsilon) return(p2); 00146 if (fabs(valp1-valp2) < epsilon) return(p1); 00147 T mu = (isolevel - valp1) / (valp2 - valp1); 00148 return Array<T,3> ( 00149 (T)p1[0] + mu * (p2[0] - p1[0]), 00150 (T)p1[1] + mu * (p2[1] - p1[1]), 00151 (T)p1[2] + mu * (p2[2] - p1[2]) ); 00152 } 00153 00154 template<typename T> 00155 ScalarFieldIsoSurface3D<T>* ScalarFieldIsoSurface3D<T>::clone() const { 00156 return new ScalarFieldIsoSurface3D<T>(*this); 00157 } 00158 00159 template<typename T> 00160 std::vector<plint> ScalarFieldIsoSurface3D<T>::getSurfaceIds() const { 00161 std::vector<plint> surfaceIds; 00162 for (plint i=0; i<(plint)isoValues.size(); ++i) { 00163 surfaceIds.push_back(i); 00164 } 00165 return surfaceIds; 00166 } 00167 00168 00169 /* ****** class BoundaryShapeIsoSurface3D ***************** */ 00170 00171 template<typename T, class SurfaceData> 00172 BoundaryShapeIsoSurface3D<T,SurfaceData>::BoundaryShapeIsoSurface3D(BoundaryShape3D<T,SurfaceData>* shape_) 00173 : shape(shape_) 00174 { } 00175 00176 template<typename T, class SurfaceData> 00177 BoundaryShapeIsoSurface3D<T,SurfaceData>::~BoundaryShapeIsoSurface3D() { 00178 delete shape; 00179 } 00180 00181 template<typename T, class SurfaceData> 00182 BoundaryShapeIsoSurface3D<T,SurfaceData>::BoundaryShapeIsoSurface3D(BoundaryShapeIsoSurface3D<T,SurfaceData> const& rhs) 00183 : shape(rhs.shape->clone()) 00184 { } 00185 00186 template<typename T, class SurfaceData> 00187 BoundaryShapeIsoSurface3D<T,SurfaceData>& BoundaryShapeIsoSurface3D<T,SurfaceData>::operator= ( 00188 BoundaryShapeIsoSurface3D<T,SurfaceData> const& rhs ) 00189 { 00190 BoundaryShapeIsoSurface3D<T,SurfaceData>(rhs).swap(*this); 00191 } 00192 00193 template<typename T, class SurfaceData> 00194 void BoundaryShapeIsoSurface3D<T,SurfaceData>::swap(BoundaryShapeIsoSurface3D<T,SurfaceData>& rhs) { 00195 std::swap(shape, rhs.shape); 00196 } 00197 00198 template<typename T, class SurfaceData> 00199 void BoundaryShapeIsoSurface3D<T,SurfaceData>::setArguments(std::vector<AtomicBlock3D*> const& arguments) 00200 { 00201 BoundaryShape3D<T,SurfaceData>* newShape = shape->clone(arguments); 00202 std::swap(shape,newShape); 00203 delete newShape; 00204 } 00205 00206 template<typename T, class SurfaceData> 00207 BoundaryShapeIsoSurface3D<T,SurfaceData>* BoundaryShapeIsoSurface3D<T,SurfaceData>::clone() const { 00208 return new BoundaryShapeIsoSurface3D<T,SurfaceData>(*this); 00209 } 00210 00211 template<typename T, class SurfaceData> 00212 std::vector<plint> BoundaryShapeIsoSurface3D<T,SurfaceData>::getSurfaceIds() const { 00213 std::vector<plint> surfaceIds; 00214 surfaceIds.push_back(0); // Only one surface can be produced, ID does not matter. 00215 return surfaceIds; 00216 } 00217 00218 template<typename T, class SurfaceData> 00219 bool BoundaryShapeIsoSurface3D<T,SurfaceData>::isInside ( 00220 plint surfaceId, Array<plint,3> const& position ) const 00221 { 00222 return shape->isInside(Dot3D(position[0],position[1],position[2])); 00223 } 00224 00225 template<typename T, class SurfaceData> 00226 Array<T,3> BoundaryShapeIsoSurface3D<T,SurfaceData>::getSurfacePosition ( 00227 plint surfaceId, Array<plint,3> const& p1, Array<plint,3> const& p2 ) const 00228 { 00229 Array<T,3> realP1(p1), realP2(p2); 00230 Array<T,3> surfacePosition, wallNormal; 00231 T distance; 00232 SurfaceData surfaceData; 00233 OffBoundary::Type bdType; 00234 plint id=-1; 00235 bool ok = 00236 shape->pointOnSurface( realP1, realP2-realP1, surfacePosition, 00237 distance, wallNormal, surfaceData, bdType, id ); 00238 PLB_ASSERT( ok ); 00239 return surfacePosition; 00240 } 00241 00242 00243 /* ****** class MarchingCubeSurfaces3D ***************** */ 00244 00245 template<typename T> 00246 MarchingCubeSurfaces3D<T>::MarchingCubeSurfaces3D ( 00247 std::vector<plint> surfaceIds_, IsoSurfaceDefinition3D<T>* isoSurface_, 00248 bool edgeOrientedData_ ) 00249 : surfaceIds(surfaceIds_), 00250 isoSurface(isoSurface_), 00251 edgeOrientedData(edgeOrientedData_), 00252 edgeOrientedEnvelope(1) 00253 { } 00254 00255 template<typename T> 00256 MarchingCubeSurfaces3D<T>::~MarchingCubeSurfaces3D() { 00257 delete isoSurface; 00258 } 00259 00260 template<typename T> 00261 void MarchingCubeSurfaces3D<T>::getTypeOfModification(std::vector<modif::ModifT>& modified) const { 00262 modified[0] = modif::staticVariables; 00263 for (pluint i=1; i<modified.size(); ++i) { 00264 modified[i] = modif::nothing; 00265 } 00266 } 00267 00268 template<typename T> 00269 MarchingCubeSurfaces3D<T>::MarchingCubeSurfaces3D(MarchingCubeSurfaces3D<T> const& rhs) 00270 : surfaceIds(rhs.surfaceIds), 00271 isoSurface(rhs.isoSurface->clone()), 00272 edgeOrientedData(rhs.edgeOrientedData), 00273 edgeOrientedEnvelope(rhs.edgeOrientedEnvelope) 00274 { } 00275 00276 template<typename T> 00277 MarchingCubeSurfaces3D<T>& MarchingCubeSurfaces3D<T>::operator=(MarchingCubeSurfaces3D<T> const& rhs) 00278 { 00279 MarchingCubeSurfaces3D<T>(rhs).swap(*this); 00280 } 00281 00282 template<typename T> 00283 MarchingCubeSurfaces3D<T>* MarchingCubeSurfaces3D<T>::clone() const 00284 { 00285 return new MarchingCubeSurfaces3D<T>(*this); 00286 } 00287 00288 template<typename T> 00289 void MarchingCubeSurfaces3D<T>::swap(MarchingCubeSurfaces3D<T>& rhs) 00290 { 00291 surfaceIds.swap(rhs.surfaceIds); 00292 std::swap(isoSurface, rhs.isoSurface); 00293 std::swap(edgeOrientedData, rhs.edgeOrientedData); 00294 std::swap(edgeOrientedEnvelope, rhs.edgeOrientedEnvelope); 00295 } 00296 00297 template<typename T> 00298 void MarchingCubeSurfaces3D<T>::processGenericBlocks ( 00299 Box3D domain, std::vector<AtomicBlock3D*> fields ) 00300 { 00301 PLB_PRECONDITION( (plint)fields.size() == 1 + isoSurface->getNumArgs() ); 00302 AtomicContainerBlock3D* triangleContainer = 00303 dynamic_cast<AtomicContainerBlock3D*>(fields[0]); 00304 PLB_ASSERT( triangleContainer ); 00305 00306 if (isoSurface->getNumArgs()>0) { 00307 std::vector<AtomicBlock3D*> isoSurfaceParameters(isoSurface->getNumArgs()); 00308 for (plint i=0; i<isoSurface->getNumArgs(); ++i) { 00309 isoSurfaceParameters[i] = fields[i+1]; 00310 } 00311 isoSurface->setArguments(isoSurfaceParameters); 00312 } 00313 if (edgeOrientedData) { 00314 edgeOriented(domain, triangleContainer); 00315 } 00316 else { 00317 defaultImplementation(domain, triangleContainer); 00318 } 00319 } 00320 00321 template<typename T> 00322 void MarchingCubeSurfaces3D<T>::defaultImplementation ( 00323 Box3D domain, AtomicContainerBlock3D* triangleContainer ) 00324 { 00325 std::vector<Triangle> triangles; 00326 Dot3D location = triangleContainer->getLocation(); 00327 00328 for (plint iX=domain.x0; iX<=domain.x1; ++iX) { 00329 for (plint iY=domain.y0; iY<=domain.y1; ++iY) { 00330 for (plint iZ=domain.z0; iZ<=domain.z1; ++iZ) { 00331 for (pluint i=0; i<surfaceIds.size(); ++i) { 00332 polygonize(iX+location.x,iY+location.y,iZ+location.z, surfaceIds[i], triangles); 00333 } 00334 } 00335 } 00336 } 00337 00338 TriangleSetData* data = new TriangleSetData; 00339 data->triangles = triangles; 00340 triangleContainer -> setData(data); 00341 } 00342 00343 template<typename T> 00344 void MarchingCubeSurfaces3D<T>::edgeOriented ( 00345 Box3D domain, AtomicContainerBlock3D* triangleContainer ) 00346 { 00347 EdgeOrientedTriangleSetData* data = new EdgeOrientedTriangleSetData ( 00348 triangleContainer -> getNx(), triangleContainer -> getNy(), 00349 triangleContainer -> getNz() ); 00350 Dot3D location = triangleContainer->getLocation(); 00351 00352 // Include at least one envelope layer, so the outer edges get the full information 00353 // from all surrounding triangles. 00354 plint env=edgeOrientedEnvelope; 00355 for (plint iX=domain.x0-env; iX<=domain.x1+env; ++iX) { 00356 for (plint iY=domain.y0-env; iY<=domain.y1+env; ++iY) { 00357 for (plint iZ=domain.z0-env; iZ<=domain.z1+env; ++iZ) { 00358 for (pluint iSurf=0; iSurf<surfaceIds.size(); ++iSurf) { 00359 std::vector<Triangle> triangles; 00360 std::vector<Array<plint,4> > edgeAttributions; 00361 // Get all triangles computed by the marching-cube algorithm for 00362 // the current cell. 00363 polygonize(iX+location.x,iY+location.y,iZ+location.z, surfaceIds[iSurf], 00364 triangles, edgeAttributions); 00365 // Additionally to the triangle coordinates, the algorithm returns 00366 // the coordinates of the edges on which the triangle vertices are placed. 00367 // There's an edge attribution for every triangle vertex, as it is checked by the 00368 // following assertion: 00369 PLB_ASSERT( edgeAttributions.size() == 3*triangles.size() ); 00370 plint i=0; // i runs over the edge-attribution index. 00371 for (pluint iTriangle=0; iTriangle<triangles.size(); ++iTriangle) { 00372 Triangle triangle = triangles[iTriangle]; 00373 // Turn the cell coordinates of the edge attribution into coordinates 00374 // that are local to the current atomic-block. 00375 Array<Array<plint,4>,3> localEdgeAttribution; 00376 // Do the conversion for each of the three vertices of the current triangle. 00377 for (int j=0; j<3; ++j, ++i) { 00378 localEdgeAttribution[j] = Array<plint,4> ( 00379 edgeAttributions[i][0] - location.x, 00380 edgeAttributions[i][1] - location.y, 00381 edgeAttributions[i][2] - location.z, 00382 edgeAttributions[i][3] ); 00383 } 00384 // Add the triangle to the data structure. Each triangle is added three 00385 // times, once on each edge on which it has a vertex. 00386 for (int j=0; j<3; ++j) { 00387 typename EdgeOrientedTriangleSetData::OnEdgeTriangle onEdgeTriangle; 00388 // The first vertex is always the one which is on the current edge. 00389 // The two subsequent vertices are defined so as to preserve the 00390 // triangle orientation. 00391 onEdgeTriangle.vertex1 = localEdgeAttribution[(j+1)%3]; 00392 onEdgeTriangle.vertex2 = localEdgeAttribution[(j+2)%3]; 00393 plint iX=localEdgeAttribution[j][0]; 00394 plint iY=localEdgeAttribution[j][1]; 00395 plint iZ=localEdgeAttribution[j][2]; 00396 plint edgeId = localEdgeAttribution[j][3]; 00397 data->addTriangle(iX,iY,iZ, edgeId, onEdgeTriangle); 00398 // In the end, the edge vertex position will be set multiple times (once for each 00399 // triangle that has a vertex on the edge). This doesn't matter, because the 00400 // marching-cube algorithm in every case produces the same vertex position. 00401 data->setVertex(iX,iY,iZ, edgeId, triangle[j]); 00402 } 00403 } 00404 } 00405 } 00406 } 00407 } 00408 00409 triangleContainer -> setData(data); 00410 } 00411 00412 template<typename T> 00413 void MarchingCubeSurfaces3D<T>::marchingCubeImpl ( 00414 plint iX, plint iY, plint iZ, plint surfaceId, 00415 std::vector<Triangle>& triangles, 00416 int& cubeindex, std::vector<Array<T,3> >& vertlist ) 00417 { 00418 typedef MarchingCubeConstants mcc; 00419 00420 Array<plint,3> p0(iX ,iY+1,iZ ); 00421 Array<plint,3> p1(iX+1,iY+1,iZ ); 00422 Array<plint,3> p2(iX+1,iY ,iZ ); 00423 Array<plint,3> p3(iX ,iY ,iZ ); 00424 Array<plint,3> p4(iX ,iY+1,iZ+1); 00425 Array<plint,3> p5(iX+1,iY+1,iZ+1); 00426 Array<plint,3> p6(iX+1,iY ,iZ+1); 00427 Array<plint,3> p7(iX ,iY ,iZ+1); 00428 00429 cubeindex = 0; 00430 if (isoSurface->isInside(surfaceId,p0)) cubeindex |= 1; // Point 0 00431 if (isoSurface->isInside(surfaceId,p1)) cubeindex |= 2; // Point 1 00432 if (isoSurface->isInside(surfaceId,p2)) cubeindex |= 4; // Point 2 00433 if (isoSurface->isInside(surfaceId,p3)) cubeindex |= 8; // Point 3 00434 if (isoSurface->isInside(surfaceId,p4)) cubeindex |= 16; // Point 4 00435 if (isoSurface->isInside(surfaceId,p5)) cubeindex |= 32; // Point 5 00436 if (isoSurface->isInside(surfaceId,p6)) cubeindex |= 64; // Point 6 00437 if (isoSurface->isInside(surfaceId,p7)) cubeindex |= 128; // Point 7 00438 00439 vertlist.resize(12); 00440 00441 /* Cube is entirely in/out of the surface */ 00442 if (mcc::edgeTable[cubeindex] == 0) return; 00443 00444 /* Find the vertices where the surface intersects the cube */ 00445 if (mcc::edgeTable[cubeindex] & 1) 00446 vertlist[0] = isoSurface->getSurfacePosition(surfaceId, p0, p1); // x-edge of y-neighbor. 00447 if (mcc::edgeTable[cubeindex] & 2) 00448 vertlist[1] = isoSurface->getSurfacePosition(surfaceId, p1, p2); // y-edge of x-neighbor. 00449 if (mcc::edgeTable[cubeindex] & 4) 00450 vertlist[2] = isoSurface->getSurfacePosition(surfaceId, p2, p3); // x-edge of current cell. 00451 if (mcc::edgeTable[cubeindex] & 8) 00452 vertlist[3] = isoSurface->getSurfacePosition(surfaceId, p3, p0); // y-edge of current cell. 00453 if (mcc::edgeTable[cubeindex] & 16) 00454 vertlist[4] = isoSurface->getSurfacePosition(surfaceId, p4, p5); // x-edge of y-z-neighbor. 00455 if (mcc::edgeTable[cubeindex] & 32) 00456 vertlist[5] = isoSurface->getSurfacePosition(surfaceId, p5, p6); // y-edge of x-z-neighbor. 00457 if (mcc::edgeTable[cubeindex] & 64) 00458 vertlist[6] = isoSurface->getSurfacePosition(surfaceId, p6, p7); // x-edge of z-neighbor. 00459 if (mcc::edgeTable[cubeindex] & 128) 00460 vertlist[7] = isoSurface->getSurfacePosition(surfaceId, p7, p4); // y-edge of z-neighbor. 00461 if (mcc::edgeTable[cubeindex] & 256) 00462 vertlist[8] = isoSurface->getSurfacePosition(surfaceId, p0, p4); // z-edge of y-neighbor. 00463 if (mcc::edgeTable[cubeindex] & 512) 00464 vertlist[9] = isoSurface->getSurfacePosition(surfaceId, p1, p5); // z-edge of x-y-neighbor. 00465 if (mcc::edgeTable[cubeindex] & 1024) 00466 vertlist[10] = isoSurface->getSurfacePosition(surfaceId, p2, p6); // z-edge of x-neighbor. 00467 if (mcc::edgeTable[cubeindex] & 2048) 00468 vertlist[11] = isoSurface->getSurfacePosition(surfaceId, p3, p7); // z-edge of current cell. 00469 } 00470 00471 template<typename T> 00472 void MarchingCubeSurfaces3D<T>::polygonize ( 00473 plint iX, plint iY, plint iZ, plint surfaceId, 00474 std::vector<Triangle>& triangles ) 00475 { 00476 typedef MarchingCubeConstants mcc; 00477 int cubeindex; 00478 std::vector<Array<T,3> > vertlist(12); 00479 marchingCubeImpl(iX,iY,iZ, surfaceId, triangles, cubeindex, vertlist); 00480 00481 /* Create the triangle */ 00482 for (plint i=0;mcc::triTable[cubeindex][i]!=-1;i+=3) { 00483 int edge1 = mcc::triTable[cubeindex][i ]; 00484 int edge2 = mcc::triTable[cubeindex][i+1]; 00485 int edge3 = mcc::triTable[cubeindex][i+2]; 00486 if (isoSurface->edgeIsValid(iX,iY,iZ, edge1) && 00487 isoSurface->edgeIsValid(iX,iY,iZ, edge2) && 00488 isoSurface->edgeIsValid(iX,iY,iZ, edge3) ) 00489 { 00490 Triangle triangle; 00491 triangle[0] = vertlist[edge1]; 00492 triangle[1] = vertlist[edge2]; 00493 triangle[2] = vertlist[edge3]; 00494 triangles.push_back(triangle); 00495 } 00496 } 00497 } 00498 00499 template<typename T> 00500 void MarchingCubeSurfaces3D<T>::polygonize ( 00501 plint iX, plint iY, plint iZ, plint surfaceId, 00502 std::vector<Triangle>& triangles, 00503 std::vector<Array<plint,4> >& edgeAttributions ) 00504 { 00505 typedef MarchingCubeConstants mcc; 00506 int cubeindex; 00507 std::vector<Array<T,3> > vertlist(12); 00508 marchingCubeImpl(iX,iY,iZ, surfaceId, triangles, cubeindex, vertlist); 00509 00510 /* Create the triangle */ 00511 for (plint i=0;mcc::triTable[cubeindex][i]!=-1;i+=3) { 00512 int edge1 = mcc::triTable[cubeindex][i ]; 00513 int edge2 = mcc::triTable[cubeindex][i+1]; 00514 int edge3 = mcc::triTable[cubeindex][i+2]; 00515 if (isoSurface->edgeIsValid(iX,iY,iZ, edge1) && 00516 isoSurface->edgeIsValid(iX,iY,iZ, edge2) && 00517 isoSurface->edgeIsValid(iX,iY,iZ, edge3) ) 00518 { 00519 Triangle triangle; 00520 triangle[0] = vertlist[edge1]; 00521 triangle[1] = vertlist[edge2]; 00522 triangle[2] = vertlist[edge3]; 00523 triangles.push_back(triangle); 00524 edgeAttributions.push_back ( 00525 Array<plint,4>(iX+mcc::edgeNeighb[edge1][0], 00526 iY+mcc::edgeNeighb[edge1][1], 00527 iZ+mcc::edgeNeighb[edge1][2], 00528 mcc::edgeOrient[edge1]) ); 00529 edgeAttributions.push_back ( 00530 Array<plint,4>(iX+mcc::edgeNeighb[edge2][0], 00531 iY+mcc::edgeNeighb[edge2][1], 00532 iZ+mcc::edgeNeighb[edge2][2], 00533 mcc::edgeOrient[edge2] ) ); 00534 edgeAttributions.push_back ( 00535 Array<plint,4>(iX+mcc::edgeNeighb[edge3][0], 00536 iY+mcc::edgeNeighb[edge3][1], 00537 iZ+mcc::edgeNeighb[edge3][2], 00538 mcc::edgeOrient[edge3] ) ); 00539 } 00540 } 00541 } 00542 00543 /* ****** Free Functions ***************** */ 00544 00545 00554 template<typename T> 00555 void isoSurfaceMarchingCube ( 00556 std::vector<typename TriangleSet<T>::Triangle>& triangles, 00557 std::vector<MultiBlock3D*> surfDefinitionArgs, 00558 IsoSurfaceDefinition3D<T>* isoSurfaceDefinition, Box3D const& domain, 00559 std::vector<plint> surfaceIds ) 00560 { 00561 typedef typename TriangleSet<T>::Triangle Triangle; 00562 PLB_ASSERT( surfDefinitionArgs.size()>0 ); 00563 if (surfaceIds.empty()) { 00564 surfaceIds = isoSurfaceDefinition->getSurfaceIds(); 00565 } 00566 MultiContainerBlock3D triangleContainer(*surfDefinitionArgs[0]); 00567 std::vector<MultiBlock3D*> args; 00568 args.push_back(&triangleContainer); 00569 for (pluint i=0; i<surfDefinitionArgs.size(); ++i) { 00570 args.push_back(surfDefinitionArgs[i]); 00571 } 00572 applyProcessingFunctional ( 00573 new MarchingCubeSurfaces3D<T>(surfaceIds, isoSurfaceDefinition), domain, args ); 00574 00575 MultiBlockManagement3D const& management = triangleContainer.getMultiBlockManagement(); 00576 ThreadAttribution const& threadAttribution = management.getThreadAttribution(); 00577 SparseBlockStructure3D const& sparseBlock = management.getSparseBlockStructure(); 00578 00579 std::map<plint,Box3D> const& domains = sparseBlock.getBulks(); 00580 std::vector<plint> numTriangles(domains.size()); 00581 00582 std::vector<plint> myPositions; 00583 std::vector<std::vector<Triangle> > myTriangles; 00584 00585 std::map<plint,Box3D>::const_iterator it = domains.begin(); 00586 plint pos = 0; 00587 for (; it != domains.end(); ++it) { 00588 plint id = it->first; 00589 if (threadAttribution.isLocal(id)) { 00590 myPositions.push_back(pos); 00591 AtomicContainerBlock3D const& atomicContainer = triangleContainer.getComponent(id); 00592 typename MarchingCubeSurfaces3D<T>::TriangleSetData const* data = 00593 dynamic_cast<typename MarchingCubeSurfaces3D<T>::TriangleSetData const*> (atomicContainer.getData()); 00594 if (data) { 00595 PLB_ASSERT((plint)numTriangles.size()>pos); 00596 numTriangles[pos] = data->triangles.size(); 00597 myTriangles.push_back(data->triangles); 00598 } 00599 else { 00600 PLB_ASSERT((plint)numTriangles.size()>pos); 00601 numTriangles[pos] = 0; 00602 myTriangles.push_back(std::vector<Triangle>()); 00603 } 00604 } 00605 else { 00606 PLB_ASSERT((plint)numTriangles.size()>pos); 00607 numTriangles[pos] = 0; 00608 } 00609 ++pos; 00610 } 00611 #ifdef PLB_MPI_PARALLEL 00612 if (numTriangles.size()>0) { 00613 std::vector<plint> tmp(numTriangles.size()); 00614 global::mpi().reduceVect(numTriangles, tmp, MPI_SUM); 00615 PLB_ASSERT(tmp.size()>0); 00616 global::mpi().bCast(&tmp[0], tmp.size()); 00617 tmp.swap(numTriangles); 00618 } 00619 #endif 00620 std::vector<plint> cumNumTriangles(numTriangles.size()+1); 00621 PLB_ASSERT(cumNumTriangles.size()>0); 00622 cumNumTriangles[0] = 0; 00623 std::partial_sum(numTriangles.begin(), numTriangles.end(), cumNumTriangles.begin()+1); 00624 plint totNumTriangles = cumNumTriangles.back(); 00625 00626 triangles.clear(); 00627 if (global::mpi().isMainProcessor()) { 00628 triangles.resize(totNumTriangles); 00629 std::map<plint,Box3D>::const_iterator it = domains.begin(); 00630 plint iDomain=0; 00631 plint iMyPositions=0; 00632 for (; it != domains.end(); ++it, ++iDomain) { 00633 PLB_ASSERT((plint)cumNumTriangles.size()>iDomain); 00634 plint startPos = cumNumTriangles[iDomain]; 00635 PLB_ASSERT((plint)cumNumTriangles.size()>iDomain+1); 00636 plint endPos = cumNumTriangles[iDomain+1]; 00637 plint id = it->first; 00638 int mpiThread = threadAttribution.getMpiProcess(id); 00639 if (mpiThread==0) { 00640 PLB_ASSERT((plint)myTriangles.size()>iMyPositions); 00641 PLB_ASSERT((plint)triangles.size()>= (plint)myTriangles[iMyPositions].size()+startPos); 00642 std::copy(myTriangles[iMyPositions].begin(), myTriangles[iMyPositions].end(), 00643 triangles.begin()+startPos); 00644 ++iMyPositions; 00645 } 00646 else { 00647 PLB_ASSERT(endPos>=startPos); 00648 std::vector<T> receiveVect(9*(endPos-startPos)); 00649 #ifdef PLB_MPI_PARALLEL 00650 if (receiveVect.empty()) receiveVect.resize(1); 00651 global::mpi().receive(&receiveVect[0], receiveVect.size(), mpiThread); 00652 #endif 00653 for (plint i=startPos; i<endPos; ++i) { 00654 plint k=0; 00655 for (pluint iVertex=0; iVertex<3; ++iVertex) { 00656 for (pluint iCoord=0; iCoord<3; ++iCoord) { 00657 PLB_ASSERT((plint)triangles.size()>i); 00658 PLB_ASSERT((plint)receiveVect.size()>9*(i-startPos)+k); 00659 triangles[i][iVertex][iCoord] = receiveVect[9*(i-startPos)+k]; 00660 ++k; 00661 } 00662 } 00663 } 00664 } 00665 } 00666 } 00667 else { // isMainProcessor 00668 for (pluint iPos=0; iPos<myPositions.size(); ++iPos) { 00669 plint myPos = myPositions[iPos]; 00670 PLB_ASSERT((plint)cumNumTriangles.size()>myPos); 00671 plint startPos = cumNumTriangles[myPos]; 00672 PLB_ASSERT((plint)cumNumTriangles.size()>myPos+1); 00673 plint endPos = cumNumTriangles[myPos+1]; 00674 std::vector<T> sendVect(9*(endPos-startPos)); 00675 for (plint i=0; i<endPos-startPos; ++i) { 00676 plint k=0; 00677 for (pluint iVertex=0; iVertex<3; ++iVertex) { 00678 for (pluint iCoord=0; iCoord<3; ++iCoord) { 00679 PLB_ASSERT((plint)sendVect.size()>9*i+k); 00680 PLB_ASSERT(myTriangles.size()>iPos); 00681 PLB_ASSERT((plint)myTriangles[iPos].size()>i); 00682 sendVect[9*i+k] = myTriangles[iPos][i][iVertex][iCoord]; 00683 ++k; 00684 } 00685 } 00686 } 00687 #ifdef PLB_MPI_PARALLEL 00688 if (sendVect.empty()) sendVect.resize(1); 00689 global::mpi().send(&sendVect[0], sendVect.size(), 0); 00690 #endif 00691 } 00692 } 00693 } 00694 00695 template<typename T> 00696 void isoSurfaceMarchingCube ( 00697 std::vector<typename TriangleSet<T>::Triangle>& triangles, 00698 VoxelizedDomain3D<T>& voxelizedDomain, Box3D const& domain ) 00699 { 00700 BoundaryProfiles3D<T,Array<T,3> > profiles; 00701 TriangleFlowShape3D<T,Array<T,3> >* flowShape = 00702 new TriangleFlowShape3D<T,Array<T,3> >(voxelizedDomain.getBoundary(), profiles); 00703 std::vector<MultiBlock3D*> triangleShapeArg; 00704 triangleShapeArg.push_back(&voxelizedDomain.getVoxelMatrix()); 00705 triangleShapeArg.push_back(&voxelizedDomain.getTriangleHash()); 00706 triangleShapeArg.push_back(&voxelizedDomain.getVoxelMatrix()); // dummy argument. 00707 isoSurfaceMarchingCube(triangles, triangleShapeArg, new BoundaryShapeIsoSurface3D<T,Array<T,3> >(flowShape), domain); 00708 } 00709 00710 template<typename T> 00711 void isoSurfaceMarchingCube ( 00712 std::vector<typename TriangleSet<T>::Triangle>& triangles, 00713 MultiScalarField3D<T>& scalarField, std::vector<T> const& isoLevels, Box3D const& domain ) 00714 { 00715 std::vector<MultiBlock3D*> scalarFieldArg; 00716 scalarFieldArg.push_back(&scalarField); 00717 isoSurfaceMarchingCube(triangles, scalarFieldArg, new ScalarFieldIsoSurface3D<T>(isoLevels), domain); 00718 } 00719 00720 } // namespace plb 00721 00722 #endif // MARCHING_CUBE_HH
1.6.3
1.6.3