void Foam::CV2D::writeTriangles(const fileName& fName, bool internalOnly) const { Info<< "Writing triangles to " << fName << nl << endl; OFstream str(fName); labelList vertexMap(number_of_vertices(), -2); label verti = 0; for ( Triangulation::Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit ) { if (!internalOnly || !vit->farPoint()) { vertexMap[vit->index()] = verti++; meshTools::writeOBJ(str, toPoint3D(vit->point())); } } for ( Triangulation::Finite_faces_iterator fit = finite_faces_begin(); fit != finite_faces_end(); ++fit ) { if ( !internalOnly || ( fit->vertex(0)->internalOrBoundaryPoint() || fit->vertex(1)->internalOrBoundaryPoint() || fit->vertex(2)->internalOrBoundaryPoint() ) ) { str << "f"; for (label i = 0; i < 3; ++i) { str << " " << vertexMap[fit->vertex(i)->index()] + 1; } str << nl; } } }
void Foam::CV2D::boundaryConform() { if (!meshControls().insertSurfaceNearestPointPairs()) { markNearBoundaryPoints(); } // Mark all the faces as SAVE_CHANGED for ( Triangulation::Finite_faces_iterator fit = finite_faces_begin(); fit != finite_faces_end(); fit++ ) { fit->faceIndex() = Fb::SAVE_CHANGED; } for (label iter=1; iter<=meshControls().maxBoundaryConformingIter(); iter++) { label nIntersections = insertBoundaryConformPointPairs ( "surfaceIntersections_" + Foam::name(iter) + ".obj" ); if (nIntersections == 0) { break; } else { Info<< "BC iteration " << iter << ": " << nIntersections << " point-pairs inserted" << endl; } // Any faces changed by insertBoundaryConformPointPairs will now // be marked CHANGED, mark those as SAVE_CHANGED and those that // remained SAVE_CHANGED as UNCHANGED for ( Triangulation::Finite_faces_iterator fit = finite_faces_begin(); fit != finite_faces_end(); fit++ ) { if (fit->faceIndex() == Fb::SAVE_CHANGED) { fit->faceIndex() = Fb::UNCHANGED; } else if (fit->faceIndex() == Fb::CHANGED) { fit->faceIndex() = Fb::SAVE_CHANGED; } } } Info<< nl; write("boundary"); }
void Foam::CV2D::calcDual ( point2DField& dualPoints, faceList& dualFaces, wordList& patchNames, labelList& patchSizes, EdgeMap<label>& mapEdgesRegion, EdgeMap<label>& indirectPatchEdge ) const { // Dual points stored in triangle order. dualPoints.setSize(number_of_faces()); label dualVerti = 0; for ( Triangulation::Finite_faces_iterator fit = finite_faces_begin(); fit != finite_faces_end(); ++fit ) { if ( fit->vertex(0)->internalOrBoundaryPoint() || fit->vertex(1)->internalOrBoundaryPoint() || fit->vertex(2)->internalOrBoundaryPoint() ) { fit->faceIndex() = dualVerti; dualPoints[dualVerti++] = toPoint2D(circumcenter(fit)); } else { fit->faceIndex() = -1; } } dualPoints.setSize(dualVerti); extractPatches(patchNames, patchSizes, mapEdgesRegion, indirectPatchEdge); forAll(patchNames, patchi) { Info<< "Patch " << patchNames[patchi] << " has size " << patchSizes[patchi] << endl; } // Create dual faces // ~~~~~~~~~~~~~~~~~ dualFaces.setSize(number_of_vertices()); label dualFacei = 0; labelList faceVerts(maxNvert); for ( Triangulation::Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit ) { if (vit->internalOrBoundaryPoint()) { Face_circulator fcStart = incident_faces(vit); Face_circulator fc = fcStart; label verti = 0; do { if (!is_infinite(fc)) { if (fc->faceIndex() < 0) { FatalErrorInFunction << "Dual face uses vertex defined by a triangle" " defined by an external point" << exit(FatalError); } // Look up the index of the triangle faceVerts[verti++] = fc->faceIndex(); } } while (++fc != fcStart); if (faceVerts.size() > 2) { dualFaces[dualFacei++] = face(labelList::subList(faceVerts, verti)); } else { Info<< "From triangle point:" << vit->index() << " coord:" << toPoint2D(vit->point()) << " generated illegal dualFace:" << faceVerts << endl; } } } dualFaces.setSize(dualFacei); }
void Foam::CV2D::writeFaces(const fileName& fName, bool internalOnly) const { Info<< "Writing dual faces to " << fName << nl << endl; OFstream str(fName); label dualVerti = 0; for ( Triangulation::Finite_faces_iterator fit = finite_faces_begin(); fit != finite_faces_end(); ++fit ) { if ( !internalOnly || ( fit->vertex(0)->internalOrBoundaryPoint() || fit->vertex(1)->internalOrBoundaryPoint() || fit->vertex(2)->internalOrBoundaryPoint() ) ) { fit->faceIndex() = dualVerti++; meshTools::writeOBJ(str, toPoint3D(circumcenter(fit))); } else { fit->faceIndex() = -1; } } for ( Triangulation::Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit ) { if (!internalOnly || vit->internalOrBoundaryPoint()) { Face_circulator fcStart = incident_faces(vit); Face_circulator fc = fcStart; str<< 'f'; do { if (!is_infinite(fc)) { if (fc->faceIndex() < 0) { FatalErrorInFunction << "Dual face uses vertex defined by a triangle" " defined by an external point" << exit(FatalError); } str<< ' ' << fc->faceIndex() + 1; } } while (++fc != fcStart); str<< nl; } } }
void Foam::CV2D::newPoints() { const scalar relaxation = relaxationModel_->relaxation(); Info<< "Relaxation = " << relaxation << endl; Field<point2D> dualVertices(number_of_faces()); label dualVerti = 0; // Find the dual point of each tetrahedron and assign it an index. for ( Triangulation::Finite_faces_iterator fit = finite_faces_begin(); fit != finite_faces_end(); ++fit ) { fit->faceIndex() = -1; if ( fit->vertex(0)->internalOrBoundaryPoint() || fit->vertex(1)->internalOrBoundaryPoint() || fit->vertex(2)->internalOrBoundaryPoint() ) { fit->faceIndex() = dualVerti; dualVertices[dualVerti] = toPoint2D(circumcenter(fit)); dualVerti++; } } dualVertices.setSize(dualVerti); Field<vector2D> displacementAccumulator ( startOfSurfacePointPairs_, vector2D::zero ); // Calculate target size and alignment for vertices scalarField sizes ( number_of_vertices(), meshControls().minCellSize() ); Field<vector2D> alignments ( number_of_vertices(), vector2D(1, 0) ); for ( Triangulation::Finite_vertices_iterator vit = finite_vertices_begin(); vit != finite_vertices_end(); ++vit ) { if (vit->internalOrBoundaryPoint()) { point2D vert = toPoint2D(vit->point()); // alignment and size determination pointIndexHit pHit; label hitSurface = -1; qSurf_.findSurfaceNearest ( toPoint3D(vert), meshControls().span2(), pHit, hitSurface ); if (pHit.hit()) { vectorField norm(1); allGeometry_[hitSurface].getNormal ( List<pointIndexHit>(1, pHit), norm ); alignments[vit->index()] = toPoint2D(norm[0]); sizes[vit->index()] = cellSizeControl_.cellSize ( toPoint3D(vit->point()) ); } } } // Info<< "Calculated alignments" << endl; scalar cosAlignmentAcceptanceAngle = 0.68; // Upper and lower edge length ratios for weight scalar u = 1.0; scalar l = 0.7; PackedBoolList pointToBeRetained(startOfSurfacePointPairs_, true); std::list<Point> pointsToInsert; for ( Triangulation::Finite_edges_iterator eit = finite_edges_begin(); eit != finite_edges_end(); eit++ ) { Vertex_handle vA = eit->first->vertex(cw(eit->second)); Vertex_handle vB = eit->first->vertex(ccw(eit->second)); if (!vA->internalOrBoundaryPoint() || !vB->internalOrBoundaryPoint()) { continue; } const point2D& dualV1 = dualVertices[eit->first->faceIndex()]; const point2D& dualV2 = dualVertices[eit->first->neighbor(eit->second)->faceIndex()]; scalar dualEdgeLength = mag(dualV1 - dualV2); point2D dVA = toPoint2D(vA->point()); point2D dVB = toPoint2D(vB->point()); Field<vector2D> alignmentDirsA(2); alignmentDirsA[0] = alignments[vA->index()]; alignmentDirsA[1] = vector2D ( -alignmentDirsA[0].y(), alignmentDirsA[0].x() ); Field<vector2D> alignmentDirsB(2); alignmentDirsB[0] = alignments[vB->index()]; alignmentDirsB[1] = vector2D ( -alignmentDirsB[0].y(), alignmentDirsB[0].x() ); Field<vector2D> alignmentDirs(alignmentDirsA); forAll(alignmentDirsA, aA) { const vector2D& a(alignmentDirsA[aA]); scalar maxDotProduct = 0.0; forAll(alignmentDirsB, aB) { const vector2D& b(alignmentDirsB[aB]); scalar dotProduct = a & b; if (mag(dotProduct) > maxDotProduct) { maxDotProduct = mag(dotProduct); alignmentDirs[aA] = a + sign(dotProduct)*b; alignmentDirs[aA] /= mag(alignmentDirs[aA]); } } } vector2D rAB = dVA - dVB; scalar rABMag = mag(rAB); forAll(alignmentDirs, aD) { vector2D& alignmentDir = alignmentDirs[aD]; if ((rAB & alignmentDir) < 0) { // swap the direction of the alignment so that has the // same sense as rAB alignmentDir *= -1; } scalar alignmentDotProd = ((rAB/rABMag) & alignmentDir); if (alignmentDotProd > cosAlignmentAcceptanceAngle) { scalar targetFaceSize = 0.5*(sizes[vA->index()] + sizes[vB->index()]); // Test for changing aspect ratio on second alignment (first // alignment is neartest surface normal) // if (aD == 1) // { // targetFaceSize *= 2.0; // } alignmentDir *= 0.5*targetFaceSize; vector2D delta = alignmentDir - 0.5*rAB; if (dualEdgeLength < 0.7*targetFaceSize) { delta *= 0; } else if (dualEdgeLength < targetFaceSize) { delta *= ( dualEdgeLength /(targetFaceSize*(u - l)) - 1/((u/l) - 1) ); } if ( vA->internalPoint() && vB->internalPoint() && rABMag > 1.75*targetFaceSize && dualEdgeLength > 0.05*targetFaceSize && alignmentDotProd > 0.93 ) { // Point insertion pointsToInsert.push_back(toPoint(0.5*(dVA + dVB))); } else if ( (vA->internalPoint() || vB->internalPoint()) && rABMag < 0.65*targetFaceSize ) { // Point removal // Only insert a point at the midpoint of the short edge // if neither attached point has already been identified // to be removed. if ( pointToBeRetained[vA->index()] == true && pointToBeRetained[vB->index()] == true ) { pointsToInsert.push_back(toPoint(0.5*(dVA + dVB))); } if (vA->internalPoint()) { pointToBeRetained[vA->index()] = false; } if (vB->internalPoint()) { pointToBeRetained[vB->index()] = false; } } else { if (vA->internalPoint()) { displacementAccumulator[vA->index()] += delta; } if (vB->internalPoint()) { displacementAccumulator[vB->index()] += -delta; } } } } }
// // Retriangulates a hole within the mesh. The hole is specified through an edgeloop(closed sequence of edges). // In addition an optional number of points can be specified which will be included in the triangulation. // void MeshEx::retriangulateHole( std::vector<MeshEx::Edge *> &boundaryEdges, std::map<MeshEx::Vertex *, math::Vec2f> &boundaryVertexProjections, std::vector<std::pair<math::Vec3f, math::Vec2f> > &interiorPoints ) { std::map<Vertex_handle, MeshEx::Vertex*> vertexMap; // used to map cgal vertex_handles to vertices std::vector<MeshEx::Edge *> edges; // this vector will hold all edges which were involved (for faster edge search) // algorithm: // - prepare data // - find all boundary vertices // - prepare CGAL constrained triangulation // - insert boundary vertices into triangulation and build mapping from Triangulation vertices to MeshEx::Vertices // - use the boundary edges as constrained edges // - insert points into triangulation from interiorPoints and build mapping from Triangulation vertices to MeshEx::Vertices // - extract triangulation results // - ? // prepare algorithm ---------------------------------------------------------- /* // obsolete since we get the boundary vertices with the boundaryVertexProjections // find boundary vertices for( std::vector<MeshEx::Edge *>::iterator it = boundaryEdges.begin(); it != boundaryEdges.end(); ++it ) { MeshEx::Edge *e = *it; boundaryVertices.push_back( e->v1 ); boundaryVertices.push_back( e->v2 ); } // remove duplicate entries std::sort( boundaryVertices.begin(), boundaryVertices.end() ); boundaryVertices.erase( std::unique( boundaryVertices.begin(), boundaryVertices.end() ), boundaryVertices.end() ); */ // algorithm ------------------------------------------------------------------ Triangulation t; // constrain triangulation with the boundary edges // iterate over all boundary vertices for( std::map<MeshEx::Vertex *, math::Vec2f>::iterator it = boundaryVertexProjections.begin(); it != boundaryVertexProjections.end(); ++it ) { MeshEx::Vertex *v = it->first; // add boundary vertex to triangulation Vertex_handle vh = t.insert( Point( it->second.x, it->second.y ) ); // we dont need to create the vertex vertexMap[vh] = v; } // iterate over all boundary edges for( std::vector<MeshEx::Edge *>::iterator it = boundaryEdges.begin(); it != boundaryEdges.end(); ++it ) { MeshEx::Edge *e = *it; Vertex_handle v1, v2; bool v1_found = false; bool v2_found = false; // find vertex_handles for the given edge vertices for( std::map<Vertex_handle, MeshEx::Vertex*>::iterator vmit = vertexMap.begin(); vmit != vertexMap.end(); ++vmit ) { if( e->v1 == vmit->second ) { v1 = vmit->first; v1_found = true; } if( e->v2 == vmit->second ) { v2 = vmit->first; v2_found = true; } } // add constrainedge to the triangulation t.insert_constraint( v1, v2 ); // add edge to the list of created/existing edges edges.push_back( e ); } // add additional and optional interior points for( std::vector<std::pair<math::Vec3f, math::Vec2f> >::iterator it = interiorPoints.begin(); it != interiorPoints.end(); ++it ) { // update triangulation Vertex_handle v = t.insert( Point( it->second.x, it->second.y ) ); // insertion may return a vertex which already exists (when the position is the same) if( vertexMap.find( v ) == vertexMap.end() ) // create according MeshEx::Vertex and keep mapping to the CGAL vertices vertexMap[v] = createVertex( it->first ); } // extract results and create triangles ---------------------------------------- // now we have the triangulation of the convex hull of the whole problem, now we // have to find the faces which are inside the polygon - we mark each face with a // segment(inside or outside) property and by finding a face which is adjacent to // a infinite face, we find the segment which is outside // we employ some floodfilling scheme for( Triangulation::Finite_faces_iterator it = t.finite_faces_begin(); it != t.finite_faces_end(); ++it ) // reset info to -1 it->info() = -1; int outsideSegment = -1; findOutsideSegment( t, t.finite_faces_begin(), 0, -1, outsideSegment ); if( outsideSegment == -1 ) printf( "error : outsideSegment not found during triangulation\n" ); for( Triangulation::Finite_faces_iterator it = t.finite_faces_begin(); it != t.finite_faces_end(); ++it ) if( (it->info() == -1) && (!t.is_infinite(it)) ) printf( "triangle not touched!\n" ); // iterate over all faces of the triangulation and create edges/triangles for( Triangulation::Finite_faces_iterator it = t.finite_faces_begin(); it != t.finite_faces_end(); ++it ) { Face_handle fh = it; // we are only interested in interior triangles if( fh->info() == outsideSegment ) continue; MeshEx::Vertex *v0, *v1, *v2; v0 = vertexMap[ fh->vertex(0) ]; v1 = vertexMap[ fh->vertex(1) ]; v2 = vertexMap[ fh->vertex(2) ]; MeshEx::Edge *e0, *e1, *e2; e0 = e1 = e2 = 0; // look for the edges in the edge vector for( std::vector<MeshEx::Edge*>::iterator eit = edges.begin(); eit != edges.end(); ++eit ) { MeshEx::Edge *e = *eit; if( e->contains(v0) && e->contains(v1) ) e0 = e; else if( e->contains(v1) && e->contains(v2) ) e1 = e; else if( e->contains(v2) && e->contains(v0) ) e2 = e; } // create the edges which could not be found if( !e0 ) { e0 = createEdge( v0, v1 ); edges.push_back(e0); } if( !e1 ) { e1 = createEdge( v1, v2 ); edges.push_back(e1); } if( !e2 ) { e2 = createEdge( v2, v0 ); edges.push_back(e2); } // create triangle MeshEx::Triangle *tri = createTriangle( v0, v1, v2, e0, e1, e2 ); } }