$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 /* Main author: Orestis Malaspinas */ 00026 00027 #ifndef VOXELIZER_HH 00028 #define VOXELIZER_HH 00029 00030 #include "core/globalDefs.h" 00031 #include "offLattice/voxelizer.h" 00032 #include "atomicBlock/dataField3D.h" 00033 #include "multiBlock/multiBlockGenerator3D.h" 00034 00035 namespace plb { 00036 00037 namespace voxelFlag { 00038 inline int invert(int arg) { 00039 switch(arg) { 00040 case inside: return outside; 00041 case outside: return inside; 00042 case innerBorder: return outerBorder; 00043 case outerBorder: return innerBorder; 00044 case undetermined: return undetermined; 00045 default: 00046 PLB_ASSERT(false); 00047 } 00048 return undetermined; 00049 } 00050 inline int bulkFlag(int arg) { 00051 if (arg==innerBorder || arg==inside) { 00052 return inside; 00053 } 00054 else if (arg==outerBorder || arg==outside) { 00055 return outside; 00056 } 00057 else { 00058 return undetermined; 00059 } 00060 } 00061 inline int borderFlag(int arg) { 00062 if (arg==inside || arg==innerBorder) { 00063 return innerBorder; 00064 } 00065 else if (arg==outside || arg==outerBorder) { 00066 return outerBorder; 00067 } 00068 else { 00069 return undetermined; 00070 } 00071 } 00072 inline bool insideFlag(int arg) { 00073 return arg==inside || arg==innerBorder; 00074 } 00075 inline bool outsideFlag(int arg) { 00076 return arg==outside || arg==outerBorder; 00077 } 00078 00079 } // namespace voxelFlag 00080 00081 template<typename T> 00082 std::auto_ptr<MultiScalarField3D<int> > voxelize ( 00083 TriangularSurfaceMesh<T> const& mesh, 00084 plint symmetricLayer, plint borderWidth ) 00085 { 00086 Array<T,2> xRange, yRange, zRange; 00087 mesh.computeBoundingBox(xRange, yRange, zRange); 00088 // Creation of the multi-scalar field. The +1 is because if the resolution is N, 00089 // the number of nodes is N+1. 00090 plint nx = (plint)(xRange[1] - xRange[0]) + 1 + 2*symmetricLayer; 00091 plint ny = (plint)(yRange[1] - yRange[0]) + 1 + 2*symmetricLayer; 00092 plint nz = (plint)(zRange[1] - zRange[0]) + 1 + 2*symmetricLayer; 00093 00094 return voxelize(mesh, Box3D(0,nx-1, 0,ny-1, 0,nz-1), borderWidth); 00095 } 00096 00097 template<typename T> 00098 std::auto_ptr<MultiScalarField3D<int> > voxelize ( 00099 TriangularSurfaceMesh<T> const& mesh, 00100 Box3D const& domain, plint borderWidth ) 00101 { 00102 // As initial seed, a one-cell layer around the outer boundary is tagged 00103 // as ouside cells. 00104 plint envelopeWidth=1; 00105 std::auto_ptr<MultiScalarField3D<int> > voxelMatrix 00106 = generateMultiScalarField<int>(domain, voxelFlag::outside, envelopeWidth); 00107 setToConstant(*voxelMatrix, voxelMatrix->getBoundingBox().enlarge(-1), 00108 voxelFlag::undetermined); 00109 00110 MultiContainerBlock3D hashContainer(*voxelMatrix); 00111 std::vector<MultiBlock3D*> container_arg; 00112 container_arg.push_back(&hashContainer); 00113 applyProcessingFunctional ( 00114 new CreateTriangleHash<T>(mesh), 00115 hashContainer.getBoundingBox(), container_arg ); 00116 00117 std::vector<MultiBlock3D*> flag_hash_arg; 00118 flag_hash_arg.push_back(voxelMatrix.get()); 00119 flag_hash_arg.push_back(&hashContainer); 00120 00121 voxelMatrix->resetFlags(); // Flags are used internally by VoxelizeMeshFunctional3D. 00122 while (!allFlagsTrue(voxelMatrix.get())) { 00123 applyProcessingFunctional ( 00124 new VoxelizeMeshFunctional3D<T>(mesh), 00125 voxelMatrix->getBoundingBox(), flag_hash_arg ); 00126 } 00127 00128 detectBorderLine(*voxelMatrix, voxelMatrix->getBoundingBox(), borderWidth); 00129 00130 return std::auto_ptr<MultiScalarField3D<int> >(voxelMatrix); 00131 } 00132 00133 00134 template<typename T> 00135 std::auto_ptr<MultiScalarField3D<int> > revoxelize ( 00136 TriangularSurfaceMesh<T> const& mesh, 00137 MultiScalarField3D<int>& oldVoxelMatrix, 00138 MultiContainerBlock3D& hashContainer, plint borderWidth ) 00139 { 00140 // As initial seed, a one-cell layer around the outer boundary is tagged 00141 // as ouside cells. 00142 plint envelopeWidth=1; 00143 Box3D domain(oldVoxelMatrix.getBoundingBox()); 00144 std::auto_ptr<MultiScalarField3D<int> > voxelMatrix ( 00145 new MultiScalarField3D<int>((MultiBlock3D&)oldVoxelMatrix) ); 00146 setToConstant(*voxelMatrix, domain, voxelFlag::outside); 00147 setToConstant(*voxelMatrix, voxelMatrix->getBoundingBox().enlarge(-1), 00148 voxelFlag::undetermined); 00149 00150 std::vector<MultiBlock3D*> flag_hash_arg; 00151 flag_hash_arg.push_back(voxelMatrix.get()); 00152 flag_hash_arg.push_back(&hashContainer); 00153 00154 voxelMatrix->resetFlags(); // Flags are used internally by VoxelizeMeshFunctional3D. 00155 while (!allFlagsTrue(voxelMatrix.get())) { 00156 applyProcessingFunctional ( 00157 new VoxelizeMeshFunctional3D<T>(mesh), 00158 voxelMatrix->getBoundingBox(), flag_hash_arg ); 00159 } 00160 00161 detectBorderLine(*voxelMatrix, voxelMatrix->getBoundingBox(), borderWidth); 00162 00163 return std::auto_ptr<MultiScalarField3D<int> >(voxelMatrix); 00164 } 00165 00166 00167 /* ******** VoxelizeMeshFunctional3D ************************************* */ 00168 00169 template<typename T> 00170 VoxelizeMeshFunctional3D<T>::VoxelizeMeshFunctional3D ( 00171 TriangularSurfaceMesh<T> const& mesh_) 00172 : mesh(mesh_) 00173 { } 00174 00175 template<typename T> 00176 bool VoxelizeMeshFunctional3D<T>::distanceToSurface ( 00177 AtomicContainerBlock3D& hashContainer, 00178 Array<T,3> const& point, T& distance, bool& isBehind ) const 00179 { 00180 T maxDistance = sqrt(3); 00181 Array<T,2> xRange(point[0]-maxDistance, point[0]+maxDistance); 00182 Array<T,2> yRange(point[1]-maxDistance, point[1]+maxDistance); 00183 Array<T,2> zRange(point[2]-maxDistance, point[2]+maxDistance); 00184 TriangleHash<T> triangleHash(hashContainer); 00185 std::vector<plint> possibleTriangles; 00186 triangleHash.getTriangles(xRange, yRange, zRange, possibleTriangles); 00187 00188 T tmpDistance; 00189 bool tmpIsBehind; 00190 bool triangleFound = false; 00191 00192 for (pluint iPossible=0; iPossible<possibleTriangles.size(); ++iPossible) { 00193 plint iTriangle = possibleTriangles[iPossible]; 00194 mesh.distanceToTriangle ( 00195 point, iTriangle, tmpDistance, tmpIsBehind ); 00196 if( !triangleFound || tmpDistance<distance) { 00197 distance = tmpDistance; 00198 isBehind = tmpIsBehind; 00199 triangleFound = true; 00200 } 00201 } 00202 return triangleFound; 00203 } 00204 00205 template<typename T> 00206 bool VoxelizeMeshFunctional3D<T>::checkIfFacetsCrossed ( 00207 AtomicContainerBlock3D& hashContainer, 00208 Array<T,3> const& point1, Array<T,3> const& point2, 00209 T& distance, plint& whichTriangle ) 00210 { 00211 Array<T,2> xRange ( 00212 std::min(point1[0], point2[0]), 00213 std::max(point1[0], point2[0]) ); 00214 Array<T,2> yRange ( 00215 std::min(point1[1], point2[1]), 00216 std::max(point1[1], point2[1]) ); 00217 Array<T,2> zRange ( 00218 std::min(point1[2], point2[2]), 00219 std::max(point1[2], point2[2]) ); 00220 TriangleHash<T> triangleHash(hashContainer); 00221 std::vector<plint> possibleTriangles; 00222 triangleHash.getTriangles(xRange, yRange, zRange, possibleTriangles); 00223 00224 int flag = 0; // Check for crossings inside the point1-point2 segment. 00225 Array<T,3> intersection; // Dummy variable. 00226 Array<T,3> normal; // Dummy variable. 00227 T tmpDistance; // Dummy variable. 00228 00229 if (global::counter("voxelizer-debug").getCount()==1) { 00230 std::cout << "{"; 00231 } 00232 std::vector<T> crossings; 00233 for (pluint iPossible=0; iPossible<possibleTriangles.size(); ++iPossible) { 00234 plint iTriangle = possibleTriangles[iPossible]; 00235 if (mesh.pointOnTriangle(point1, point2, flag, iTriangle, intersection, normal, tmpDistance)==1) { 00236 if (global::counter("voxelizer-debug").getCount()==1) { 00237 std::cout << "(" << iTriangle << ";" << tmpDistance << ")"; 00238 } 00239 crossings.push_back(tmpDistance); 00240 if (crossings.size()==1 || tmpDistance<distance) { 00241 distance = tmpDistance; 00242 whichTriangle = iTriangle; 00243 } 00244 } 00245 } 00246 if (global::counter("voxelizer-debug").getCount()==1) { 00247 std::cout << "}"; 00248 } 00249 00250 if (crossings.size()==0) { 00251 return false; 00252 } 00253 else { 00254 bool hasCrossed = true; 00255 for (pluint iCrossing=1; iCrossing<crossings.size(); ++iCrossing) { 00256 //const T eps1 = std::numeric_limits<double>::epsilon()*1.e2; 00257 //if ( !util::fpequal(crossings[iCrossing], crossings[iCrossing-1], eps1) ) 00258 const T eps1 = std::numeric_limits<double>::epsilon()*1.e4; 00259 if ( fabs(crossings[iCrossing]-crossings[iCrossing-1])>eps1) 00260 { 00261 hasCrossed = !hasCrossed; 00262 } 00263 } 00264 return hasCrossed; 00265 } 00266 } 00267 00268 template<typename T> 00269 bool VoxelizeMeshFunctional3D<T>::createVoxelizationRange ( 00270 Box3D const& domain, ScalarField3D<int>& voxels, 00271 Array<plint,2>& xRange, Array<plint,2>& yRange, Array<plint,2>& zRange ) 00272 { 00273 // The purpose of the first three loops is to locate the eight 00274 // corners of the cube. One voxel per corner would be insufficient 00275 // because a potential seed is situated differently, depending on 00276 // whether it is on the boundary of the multi-block or somewhere inside. 00277 for (plint dx=0; dx<=+1; ++dx) { 00278 plint xMin = domain.x0+dx*domain.getNx()-1; 00279 plint xMax = domain.x0+dx*domain.getNx(); 00280 for (plint dy=0; dy<=+1; ++dy) { 00281 plint yMin = domain.y0+dy*domain.getNy()-1; 00282 plint yMax = domain.y0+dy*domain.getNy(); 00283 for (plint dz=0; dz<=+1; ++dz) { 00284 plint zMin = domain.z0+dz*domain.getNz()-1; 00285 plint zMax = domain.z0+dz*domain.getNz(); 00286 00287 // Locate a potential seed in one of the corners. 00288 for (plint iX=xMin; iX<=xMax; ++iX) { 00289 for (plint iY=yMin; iY<=yMax; ++iY) { 00290 for (plint iZ=zMin; iZ<=zMax; ++iZ) { 00291 if (voxels.get(iX,iY,iZ) != voxelFlag::undetermined) { 00292 xRange[0] = domain.x0+dx*(domain.getNx()-1); 00293 xRange[1] = domain.x0+(1-dx)*(domain.getNx()-1); 00294 yRange[0] = domain.y0+dy*(domain.getNy()-1); 00295 yRange[1] = domain.y0+(1-dy)*(domain.getNy()-1); 00296 zRange[0] = domain.z0+dz*(domain.getNz()-1); 00297 zRange[1] = domain.z0+(1-dz)*(domain.getNz()-1); 00298 return true; 00299 } 00300 } 00301 } 00302 } 00303 00304 } 00305 } 00306 } 00307 return false; 00308 } 00309 00310 template<typename T> 00311 void VoxelizeMeshFunctional3D<T>::printOffender ( 00312 ScalarField3D<int> const& voxels, 00313 AtomicContainerBlock3D& hashContainer, 00314 Dot3D pos ) 00315 { 00316 std::set<plint> triangles; 00317 Dot3D offset = voxels.getLocation(); 00318 Dot3D pos_ = pos+offset; 00319 std::cout << "Position (" << pos_.x << "," << pos_.y << "," << pos_.z << ")" << std::endl; 00320 for (plint dx=-1; dx<=+1; ++dx) { 00321 for (plint dy=-1; dy<=+1; ++dy) { 00322 for (plint dz=-1; dz<=+1; ++dz) { 00323 if (!(dx==0 && dy==0 && dz==0)) { 00324 Dot3D neigh = pos+offset+Dot3D(dx,dy,dz); 00325 int typeOfNeighbor = voxels.get(pos.x+dx,pos.y+dy,pos.z+dz); 00326 if (typeOfNeighbor!=voxelFlag::undetermined) { 00327 T distance; 00328 plint whichTriangle; 00329 Array<T,3> p1(pos_.x,pos_.y,pos_.z); 00330 Array<T,3> p2(neigh.x,neigh.y,neigh.z); 00331 global::counter("voxelizer-debug").increment(1); 00332 bool crossed = checkIfFacetsCrossed ( 00333 hashContainer, p1, p2, distance, whichTriangle); 00334 global::counter("voxelizer-debug").reset(); 00335 std::cout << "Neighbor (" 00336 << dx << "," << dy << "," << dz 00337 << "); is " 00338 << (voxelFlag::insideFlag(typeOfNeighbor) ? "inside" : "outside"); 00339 if (crossed) { 00340 triangles.insert(whichTriangle); 00341 std::cout 00342 << " inters. at distance " << distance 00343 << " with triangle " << whichTriangle << std::endl; 00344 } 00345 else { 00346 std::cout << " no inters." << std::endl; 00347 } 00348 } 00349 } 00350 } 00351 } 00352 } 00353 std::set<plint>::iterator it = triangles.begin(); 00354 for (; it!=triangles.end(); ++it) { 00355 std::cout << "Triangle " << *it << " [" << std::flush; 00356 Array<T,3> p0 = mesh.getVertex(*it, 0); 00357 Array<T,3> p1 = mesh.getVertex(*it, 1); 00358 Array<T,3> p2 = mesh.getVertex(*it, 2); 00359 std::cout << p0[0] << " " << p1[0] << " " << p2[0] << " " << p0[0] << "], [" 00360 << p0[1] << " " << p1[1] << " " << p2[1] << " " << p0[1] << "], [" 00361 << p0[2] << " " << p1[2] << " " << p2[2] << " " << p0[2] << "]" << std::endl; 00362 } 00363 } 00364 00365 template<typename T> 00366 bool VoxelizeMeshFunctional3D<T>::voxelizeFromNeighbor ( 00367 ScalarField3D<int> const& voxels, 00368 AtomicContainerBlock3D& hashContainer, 00369 Dot3D pos, Dot3D neighbor, int& voxelType ) 00370 { 00371 int verificationLevel = 0; 00372 Dot3D offset = voxels.getLocation(); 00373 int typeOfNeighbor = voxels.get(neighbor.x,neighbor.y,neighbor.z); 00374 if (typeOfNeighbor==voxelFlag::undetermined) { 00375 return true; 00376 } 00377 // If there is no verification and the voxel has already been voxelized, 00378 // it is not being re-voxelized here. 00379 if (verificationLevel==0) { 00380 if (voxelType!=voxelFlag::undetermined) { 00381 return true; 00382 } 00383 } 00384 Dot3D pos_ = pos+offset; 00385 Dot3D neighbor_ = neighbor+offset; 00386 Array<T,3> point1((T)pos_.x, (T)pos_.y, (T)pos_.z); 00387 Array<T,3> point2((T)neighbor_.x, (T)neighbor_.y, (T)neighbor_.z); 00388 int newVoxelType = voxelFlag::undetermined; 00389 T distance1, distance2, distance3, distance4; 00390 bool isBehind1, isBehind2; 00391 plint whichTriangle1, whichTriangle2; 00392 if (checkIfFacetsCrossed(hashContainer, point1, point2, distance1, whichTriangle1)) { 00393 newVoxelType = voxelFlag::invert(typeOfNeighbor); 00394 // Additional consistency checks only at the ultimate level of verification. 00395 if (verificationLevel==2) { 00396 PLB_ASSERT( distance1 < sqrt(3)+0.0001 ); 00397 bool ok = checkIfFacetsCrossed(hashContainer, point2, point1, distance2, whichTriangle2); 00398 PLB_ASSERT( ok ); 00399 PLB_ASSERT( distance2 < sqrt(3)+0.0001 ); 00400 00401 bool ok1 = distanceToSurface( hashContainer, point1, 00402 distance3, isBehind1 ); 00403 00404 PLB_ASSERT( ok1 ); 00405 PLB_ASSERT( distance1 < sqrt(3)+0.0001 ); 00406 // Attention: At this moment, the following consistency check fails sometimes, 00407 // god knows why. It might be that there is a bug in the method 00408 // mesh.distanceToSurface. 00409 PLB_ASSERT( (voxelFlag::insideFlag(newVoxelType) && isBehind1) || 00410 (voxelFlag::outsideFlag(newVoxelType) && !isBehind1) ); 00411 00412 bool ok2 = distanceToSurface( hashContainer, point2, 00413 distance4, isBehind2 ); 00414 PLB_ASSERT( ok2 ); 00415 PLB_ASSERT( distance2 < sqrt(3)+0.0001 ); 00416 PLB_ASSERT ( (voxelFlag::insideFlag(typeOfNeighbor) && isBehind2) || 00417 (voxelFlag::outsideFlag(typeOfNeighbor) && !isBehind2) ); 00418 } 00419 } 00420 else { 00421 newVoxelType = typeOfNeighbor; 00422 } 00423 int oldVoxelType = voxelType; 00424 voxelType = newVoxelType; 00425 if (oldVoxelType == voxelFlag::undetermined) { 00426 return true; 00427 } 00428 else { 00429 return oldVoxelType == newVoxelType; 00430 } 00431 } 00432 00433 template<typename T> 00434 void VoxelizeMeshFunctional3D<T>::processGenericBlocks ( 00435 Box3D domain, std::vector<AtomicBlock3D*> blocks ) 00436 { 00437 PLB_PRECONDITION( blocks.size()==2 ); 00438 ScalarField3D<int>* voxels = 00439 dynamic_cast<ScalarField3D<int>*>(blocks[0]); 00440 PLB_ASSERT( voxels ); 00441 AtomicContainerBlock3D* container = 00442 dynamic_cast<AtomicContainerBlock3D*>(blocks[1]); 00443 PLB_ASSERT( container ); 00444 00445 // Return if this block is already voxelized. 00446 if (voxels->getFlag()) { 00447 return; 00448 } 00449 00450 Array<plint,2> xRange, yRange, zRange; 00451 if (!createVoxelizationRange(domain, *voxels, xRange, yRange, zRange)) { 00452 // If no seed has been found in the envelope, just return and wait 00453 // for the next round. 00454 return; 00455 } 00456 00457 // Specify if the loops go in positive or negative direction. 00458 plint xIncr = xRange[1]>xRange[0] ? 1 : -1; 00459 plint yIncr = yRange[1]>yRange[0] ? 1 : -1; 00460 plint zIncr = zRange[1]>zRange[0] ? 1 : -1; 00461 // The ranges are closed on both ends. Here, the range[1] end 00462 // is converted to an open one so we can use != checks in the loops. 00463 xRange[1] += xIncr; 00464 yRange[1] += yIncr; 00465 zRange[1] += zIncr; 00466 for (plint iX=xRange[0]; iX!=xRange[1]; iX+=xIncr) { 00467 for (plint iY=yRange[0]; iY!=yRange[1]; iY+=yIncr) { 00468 for (plint iZ=zRange[0]; iZ!=zRange[1]; iZ+=zIncr) { 00469 Dot3D pos(iX,iY,iZ); 00470 int voxelType = voxels->get(iX,iY,iZ); 00471 if (voxelType==voxelFlag::undetermined) { 00472 for (plint dx=-1; dx<=+1; ++dx) { 00473 for (plint dy=-1; dy<=+1; ++dy) { 00474 for (plint dz=-1; dz<=+1; ++dz) { 00475 if (!(dx==0 && dy==0 && dz==0)) { 00476 Dot3D neighbor(iX+dx, iY+dy, iZ+dz); 00477 bool ok = voxelizeFromNeighbor ( 00478 *voxels, *container, 00479 pos, neighbor, voxelType ); 00480 if (!ok) { 00481 printOffender(*voxels, *container, pos); 00482 } 00483 PLB_ASSERT( ok ); 00484 } 00485 } 00486 } 00487 } 00488 voxels->get(iX,iY,iZ) = voxelType; 00489 } 00490 } 00491 } 00492 } 00493 // Indicate that this atomic-block has been voxelized. 00494 voxels->setFlag(true); 00495 } 00496 00497 template<typename T> 00498 VoxelizeMeshFunctional3D<T>* VoxelizeMeshFunctional3D<T>::clone() const { 00499 return new VoxelizeMeshFunctional3D<T>(*this); 00500 } 00501 00502 template<typename T> 00503 void VoxelizeMeshFunctional3D<T>::getTypeOfModification(std::vector<modif::ModifT>& modified) const { 00504 modified[0] = modif::staticVariables; // Voxels 00505 modified[1] = modif::nothing; // Hash Container 00506 } 00507 00508 template<typename T> 00509 BlockDomain::DomainT VoxelizeMeshFunctional3D<T>::appliesTo() const { 00510 return BlockDomain::bulk; 00511 } 00512 00513 00514 00515 /* ******** DetectBorderLineFunctional3D ************************************* */ 00516 00517 template<typename T> 00518 void detectBorderLine( MultiScalarField3D<T>& voxelMatrix, 00519 Box3D const& domain, plint borderWidth ) 00520 { 00521 applyProcessingFunctional( new DetectBorderLineFunctional3D<T>(borderWidth), 00522 domain, voxelMatrix ); 00523 } 00524 00525 template<typename T> 00526 DetectBorderLineFunctional3D<T>::DetectBorderLineFunctional3D(plint borderWidth_) 00527 : borderWidth(borderWidth_) 00528 { } 00529 00530 template<typename T> 00531 void DetectBorderLineFunctional3D<T>::process ( 00532 Box3D domain, ScalarField3D<T>& voxels ) 00533 { 00534 for (plint iX = domain.x0; iX <= domain.x1; ++iX) { 00535 for (plint iY = domain.y0; iY <= domain.y1; ++iY) { 00536 for (plint iZ = domain.z0; iZ <= domain.z1; ++iZ) { 00537 for (plint dx=-borderWidth; dx<=borderWidth; ++dx) 00538 for (plint dy=-borderWidth; dy<=borderWidth; ++dy) 00539 for (plint dz=-borderWidth; dz<=borderWidth; ++dz) 00540 if(!(dx==0 && dy==0 && dz==0)) { 00541 plint nextX = iX + dx; 00542 plint nextY = iY + dy; 00543 plint nextZ = iZ + dz; 00544 if (contained(Dot3D(nextX,nextY,nextZ),voxels.getBoundingBox())) { 00545 if ( voxelFlag::outsideFlag(voxels.get(iX,iY,iZ)) && 00546 voxelFlag::insideFlag(voxels.get(nextX,nextY,nextZ)) ) 00547 { 00548 voxels.get(iX,iY,iZ) = voxelFlag::outerBorder; 00549 } 00550 if ( voxelFlag::insideFlag(voxels.get(iX,iY,iZ)) && 00551 voxelFlag::outsideFlag(voxels.get(nextX,nextY,nextZ)) ) 00552 { 00553 voxels.get(iX,iY,iZ) = voxelFlag::innerBorder; 00554 } 00555 } 00556 } 00557 } 00558 } 00559 } 00560 } 00561 00562 template<typename T> 00563 DetectBorderLineFunctional3D<T>* DetectBorderLineFunctional3D<T>::clone() const { 00564 return new DetectBorderLineFunctional3D<T>(*this); 00565 } 00566 00567 template<typename T> 00568 void DetectBorderLineFunctional3D<T>::getTypeOfModification(std::vector<modif::ModifT>& modified) const { 00569 modified[0] = modif::staticVariables; 00570 } 00571 00572 template<typename T> 00573 BlockDomain::DomainT DetectBorderLineFunctional3D<T>::appliesTo() const { 00574 return BlockDomain::bulk; 00575 } 00576 00577 } // namespace plb 00578 00579 #endif // VOXELIZER_HH
1.6.3
1.6.3