$treeview $search $mathjax
Palabos  Version 1.1
$projectbrief
$projectbrief
$searchbox

marchingCube.hh

Go to the documentation of this file.
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