// Split hex (and hex only) along edgeI creating two prisms bool splitHex ( const polyMesh& mesh, const label celli, const label edgeI, DynamicList<label>& cutCells, DynamicList<labelList>& cellLoops, DynamicList<scalarField>& cellEdgeWeights ) { // cut handling functions edgeVertex ev(mesh); const edgeList& edges = mesh.edges(); const faceList& faces = mesh.faces(); const edge& e = edges[edgeI]; // Get faces on the side, i.e. faces not using edge but still using one of // the edge endpoints. label leftI = -1; label rightI = -1; label leftFp = -1; label rightFp = -1; const cell& cFaces = mesh.cells()[celli]; forAll(cFaces, i) { label facei = cFaces[i]; const face& f = faces[facei]; label fp0 = findIndex(f, e[0]); label fp1 = findIndex(f, e[1]); if (fp0 == -1) { if (fp1 != -1) { // Face uses e[1] but not e[0] rightI = facei; rightFp = fp1; if (leftI != -1) { // Have both faces so exit break; } } } else { if (fp1 != -1) { // Face uses both e[1] and e[0] } else { leftI = facei; leftFp = fp0; if (rightI != -1) { break; } } } }
// Naive feature detection. All boundary edges with angle > featureAngle become // feature edges. All points on feature edges become feature points. All // boundary faces become feature faces. void simpleMarkFeatures ( const polyMesh& mesh, const PackedBoolList& isBoundaryEdge, const scalar featureAngle, const bool concaveMultiCells, const bool doNotPreserveFaceZones, labelList& featureFaces, labelList& featureEdges, labelList& singleCellFeaturePoints, labelList& multiCellFeaturePoints ) { scalar minCos = Foam::cos(featureAngle * mathematicalConstant::pi/180.0); const polyBoundaryMesh& patches = mesh.boundaryMesh(); // Working sets labelHashSet featureEdgeSet; labelHashSet singleCellFeaturePointSet; labelHashSet multiCellFeaturePointSet; // 1. Mark all edges between patches // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ forAll(patches, patchI) { const polyPatch& pp = patches[patchI]; const labelList& meshEdges = pp.meshEdges(); // All patch corner edges. These need to be feature points & edges! for (label edgeI = pp.nInternalEdges(); edgeI < pp.nEdges(); edgeI++) { label meshEdgeI = meshEdges[edgeI]; featureEdgeSet.insert(meshEdgeI); singleCellFeaturePointSet.insert(mesh.edges()[meshEdgeI][0]); singleCellFeaturePointSet.insert(mesh.edges()[meshEdgeI][1]); } } // 2. Mark all geometric feature edges // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Make distinction between convex features where the boundary point becomes // a single cell and concave features where the boundary point becomes // multiple 'half' cells. // Addressing for all outside faces primitivePatch allBoundary ( SubList<face> ( mesh.faces(), mesh.nFaces()-mesh.nInternalFaces(), mesh.nInternalFaces() ), mesh.points() ); // Check for non-manifold points (surface pinched at point) allBoundary.checkPointManifold(false, &singleCellFeaturePointSet); // Check for non-manifold edges (surface pinched at edge) const labelListList& edgeFaces = allBoundary.edgeFaces(); const labelList& meshPoints = allBoundary.meshPoints(); forAll(edgeFaces, edgeI) { const labelList& eFaces = edgeFaces[edgeI]; if (eFaces.size() > 2) { const edge& e = allBoundary.edges()[edgeI]; //Info<< "Detected non-manifold boundary edge:" << edgeI // << " coords:" // << allBoundary.points()[meshPoints[e[0]]] // << allBoundary.points()[meshPoints[e[1]]] << endl; singleCellFeaturePointSet.insert(meshPoints[e[0]]); singleCellFeaturePointSet.insert(meshPoints[e[1]]); } } // Check for features. forAll(edgeFaces, edgeI) { const labelList& eFaces = edgeFaces[edgeI]; if (eFaces.size() == 2) { label f0 = eFaces[0]; label f1 = eFaces[1]; // check angle const vector& n0 = allBoundary.faceNormals()[f0]; const vector& n1 = allBoundary.faceNormals()[f1]; if ((n0 & n1) < minCos) { const edge& e = allBoundary.edges()[edgeI]; label v0 = meshPoints[e[0]]; label v1 = meshPoints[e[1]]; label meshEdgeI = meshTools::findEdge(mesh, v0, v1); featureEdgeSet.insert(meshEdgeI); // Check if convex or concave by looking at angle // between face centres and normal vector c1c0 ( allBoundary[f1].centre(allBoundary.points()) - allBoundary[f0].centre(allBoundary.points()) ); if (concaveMultiCells && (c1c0 & n0) > SMALL) { // Found concave edge. Make into multiCell features Info<< "Detected concave feature edge:" << edgeI << " cos:" << (c1c0 & n0) << " coords:" << allBoundary.points()[v0] << allBoundary.points()[v1] << endl; singleCellFeaturePointSet.erase(v0); multiCellFeaturePointSet.insert(v0); singleCellFeaturePointSet.erase(v1); multiCellFeaturePointSet.insert(v1); } else { // Convex. singleCell feature. if (!multiCellFeaturePointSet.found(v0)) { singleCellFeaturePointSet.insert(v0); } if (!multiCellFeaturePointSet.found(v1)) { singleCellFeaturePointSet.insert(v1); } } } } } // 3. Mark all feature faces // ~~~~~~~~~~~~~~~~~~~~~~~~~ // Face centres that need inclusion in the dual mesh labelHashSet featureFaceSet(mesh.nFaces()-mesh.nInternalFaces()); // A. boundary faces. for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++) { featureFaceSet.insert(faceI); } // B. face zones. const faceZoneMesh& faceZones = mesh.faceZones(); if (doNotPreserveFaceZones) { if (faceZones.size() > 0) { WarningIn("simpleMarkFeatures(..)") << "Detected " << faceZones.size() << " faceZones. These will not be preserved." << endl; } } else { if (faceZones.size() > 0) { Info<< "Detected " << faceZones.size() << " faceZones. Preserving these by marking their" << " points, edges and faces as features." << endl; } forAll(faceZones, zoneI) { const faceZone& fz = faceZones[zoneI]; Info<< "Inserting all faces in faceZone " << fz.name() << " as features." << endl; forAll(fz, i) { label faceI = fz[i]; const face& f = mesh.faces()[faceI]; const labelList& fEdges = mesh.faceEdges()[faceI]; featureFaceSet.insert(faceI); forAll(f, fp) { // Mark point as multi cell point (since both sides of // face should have different cells) singleCellFeaturePointSet.erase(f[fp]); multiCellFeaturePointSet.insert(f[fp]); // Make sure there are points on the edges. featureEdgeSet.insert(fEdges[fp]); } } }
//- Returns -1 or cartesian coordinate component (0=x, 1=y, 2=z) of normal // in case of 2D mesh label twoDNess(const polyMesh& mesh) { const pointField& ctrs = mesh.cellCentres(); if (ctrs.size() < 2) { return -1; } // // 1. All cell centres on single plane aligned with x, y or z // // Determine 3 points to base plane on. vector vec10 = ctrs[1] - ctrs[0]; vec10 /= mag(vec10); label otherCellI = -1; for (label cellI = 2; cellI < ctrs.size(); cellI++) { vector vec(ctrs[cellI] - ctrs[0]); vec /= mag(vec); if (mag(vec & vec10) < 0.9) { // ctrs[cellI] not in line with n otherCellI = cellI; break; } } if (otherCellI == -1) { // Cannot find cell to make decent angle with cell0-cell1 vector. // Note: what to do here? All cells (almost) in one line. Maybe 1D case? return -1; } plane cellPlane(ctrs[0], ctrs[1], ctrs[otherCellI]); forAll (ctrs, cellI) { const labelList& cEdges = mesh.cellEdges()[cellI]; scalar minLen = GREAT; forAll (cEdges, i) { minLen = min(minLen, mesh.edges()[cEdges[i]].mag(mesh.points())); } if (cellPlane.distance(ctrs[cellI]) > 1E-6*minLen) { // Centres not in plane return -1; } }