bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { netgen::multithread.terminate = 0; netgen::multithread.task = "Volume meshing"; _progressByTic = -1.; SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); SMESH_MesherHelper helper(aMesh); bool _quadraticMesh = helper.IsQuadraticSubMesh(aShape); helper.SetElementsOnShape( true ); int Netgen_NbOfNodes = 0; double Netgen_point[3]; int Netgen_triangle[3]; NETGENPlugin_NetgenLibWrapper ngLib; Ng_Mesh * Netgen_mesh = ngLib._ngMesh; // vector of nodes in which node index == netgen ID vector< const SMDS_MeshNode* > nodeVec; { const int invalid_ID = -1; SMESH::Controls::Area areaControl; SMESH::Controls::TSequenceOfXYZ nodesCoords; // maps nodes to ng ID typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap; typedef TNodeToIDMap::value_type TN2ID; TNodeToIDMap nodeToNetgenID; // find internal shapes NETGENPlugin_Internals internals( aMesh, aShape, /*is3D=*/true ); // --------------------------------- // Feed the Netgen with surface mesh // --------------------------------- TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType(); bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID ); SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh )); if ( _viscousLayersHyp ) { netgen::multithread.percent = 3; proxyMesh = _viscousLayersHyp->Compute( aMesh, aShape ); if ( !proxyMesh ) return false; } if ( aMesh.NbQuadrangles() > 0 ) { netgen::multithread.percent = 6; StdMeshers_QuadToTriaAdaptor* Adaptor = new StdMeshers_QuadToTriaAdaptor; Adaptor->Compute(aMesh,aShape,proxyMesh.get()); proxyMesh.reset( Adaptor ); } for ( TopExp_Explorer exFa( aShape, TopAbs_FACE ); exFa.More(); exFa.Next()) { const TopoDS_Shape& aShapeFace = exFa.Current(); int faceID = meshDS->ShapeToIndex( aShapeFace ); bool isInternalFace = internals.isInternalShape( faceID ); bool isRev = false; if ( checkReverse && !isInternalFace && helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 ) // IsReversedSubMesh() can work wrong on strongly curved faces, // so we use it as less as possible isRev = helper.IsReversedSubMesh( TopoDS::Face( aShapeFace )); const SMESHDS_SubMesh * aSubMeshDSFace = proxyMesh->GetSubMesh( aShapeFace ); if ( !aSubMeshDSFace ) continue; SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); while ( iteratorElem->more() ) // loop on elements on a geom face { // check mesh face const SMDS_MeshElement* elem = iteratorElem->next(); if ( !elem ) return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); if ( elem->NbCornerNodes() != 3 ) return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters"); // Add nodes of triangles and triangles them-selves to netgen mesh // add three nodes of triangle bool hasDegen = false; for ( int iN = 0; iN < 3; ++iN ) { const SMDS_MeshNode* node = elem->GetNode( iN ); const int shapeID = node->getshapeId(); if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE && helper.IsDegenShape( shapeID )) { // ignore all nodes on degeneraged edge and use node on its vertex instead TopoDS_Shape vertex = TopoDS_Iterator( meshDS->IndexToShape( shapeID )).Value(); node = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), meshDS ); hasDegen = true; } int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second; if ( ngID == invalid_ID ) { ngID = ++Netgen_NbOfNodes; Netgen_point [ 0 ] = node->X(); Netgen_point [ 1 ] = node->Y(); Netgen_point [ 2 ] = node->Z(); Ng_AddPoint(Netgen_mesh, Netgen_point); } Netgen_triangle[ isRev ? 2-iN : iN ] = ngID; } // add triangle if ( hasDegen && (Netgen_triangle[0] == Netgen_triangle[1] || Netgen_triangle[0] == Netgen_triangle[2] || Netgen_triangle[2] == Netgen_triangle[1] )) continue; Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); if ( isInternalFace && !proxyMesh->IsTemporary( elem )) { swap( Netgen_triangle[1], Netgen_triangle[2] ); Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); } } // loop on elements on a face } // loop on faces of a SOLID or SHELL // insert old nodes into nodeVec nodeVec.resize( nodeToNetgenID.size() + 1, 0 ); TNodeToIDMap::iterator n_id = nodeToNetgenID.begin(); for ( ; n_id != nodeToNetgenID.end(); ++n_id ) nodeVec[ n_id->second ] = n_id->first; nodeToNetgenID.clear(); if ( internals.hasInternalVertexInSolid() ) { netgen::OCCGeometry occgeo; NETGENPlugin_Mesher::AddIntVerticesInSolids( occgeo, (netgen::Mesh&) *Netgen_mesh, nodeVec, internals); } } // ------------------------- // Generate the volume mesh // ------------------------- return ( ngLib._isComputeOk = compute( aMesh, helper, nodeVec, Netgen_mesh)); }
bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { MESSAGE("NETGENPlugin_NETGEN_3D::Compute with maxElmentsize = " << _maxElementVolume); SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); const int invalid_ID = -1; SMESH::Controls::Area areaControl; SMESH::Controls::TSequenceOfXYZ nodesCoords; // ------------------------------------------------------------------- // get triangles on aShell and make a map of nodes to Netgen node IDs // ------------------------------------------------------------------- SMESH_MesherHelper helper(aMesh); SMESH_MesherHelper* myTool = &helper; bool _quadraticMesh = myTool->IsQuadraticSubMesh(aShape); typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap; TNodeToIDMap nodeToNetgenID; list< const SMDS_MeshElement* > triangles; list< bool > isReversed; // orientation of triangles TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType(); bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID ); // for the degeneraged edge: ignore all but one node on it; // map storing ids of degen edges and vertices and their netgen id: map< int, int* > degenShapeIdToPtrNgId; map< int, int* >::iterator shId_ngId; list< int > degenNgIds; StdMeshers_QuadToTriaAdaptor Adaptor; Adaptor.Compute(aMesh,aShape); for (TopExp_Explorer exp(aShape,TopAbs_FACE); exp.More(); exp.Next()) { const TopoDS_Shape& aShapeFace = exp.Current(); const SMESHDS_SubMesh * aSubMeshDSFace = meshDS->MeshElements( aShapeFace ); if ( aSubMeshDSFace ) { bool isRev = false; if ( checkReverse && helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 ) // IsReversedSubMesh() can work wrong on strongly curved faces, // so we use it as less as possible isRev = SMESH_Algo::IsReversedSubMesh( TopoDS::Face(aShapeFace), meshDS ); SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements(); while ( iteratorElem->more() ) // loop on elements on a face { // check element const SMDS_MeshElement* elem = iteratorElem->next(); if ( !elem ) return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); bool isTraingle = ( elem->NbNodes()==3 || (_quadraticMesh && elem->NbNodes()==6 )); if ( !isTraingle ) { //return error( COMPERR_BAD_INPUT_MESH, // SMESH_Comment("Not triangle element ")<<elem->GetID()); // using adaptor const list<const SMDS_FaceOfNodes*>* faces = Adaptor.GetTriangles(elem); if(faces==0) { return error( COMPERR_BAD_INPUT_MESH, SMESH_Comment("Not triangles in adaptor for element ")<<elem->GetID()); } list<const SMDS_FaceOfNodes*>::const_iterator itf = faces->begin(); for(; itf!=faces->end(); itf++ ) { triangles.push_back( (*itf) ); isReversed.push_back( isRev ); // put triange's nodes to nodeToNetgenID map SMDS_ElemIteratorPtr triangleNodesIt = (*itf)->nodesIterator(); while ( triangleNodesIt->more() ) { const SMDS_MeshNode * node = static_cast<const SMDS_MeshNode *>(triangleNodesIt->next()); if(myTool->IsMedium(node)) continue; nodeToNetgenID.insert( make_pair( node, invalid_ID )); } } } else { // keep a triangle triangles.push_back( elem ); isReversed.push_back( isRev ); // put elem nodes to nodeToNetgenID map SMDS_ElemIteratorPtr triangleNodesIt = elem->nodesIterator(); while ( triangleNodesIt->more() ) { const SMDS_MeshNode * node = static_cast<const SMDS_MeshNode *>(triangleNodesIt->next()); if(myTool->IsMedium(node)) continue; nodeToNetgenID.insert( make_pair( node, invalid_ID )); } } #ifdef _DEBUG_ // check if a trainge is degenerated areaControl.GetPoints( elem, nodesCoords ); double area = areaControl.GetValue( nodesCoords ); if ( area <= DBL_MIN ) { MESSAGE( "Warning: Degenerated " << elem ); } #endif } // look for degeneraged edges and vetices for (TopExp_Explorer expE(aShapeFace,TopAbs_EDGE); expE.More(); expE.Next()) { TopoDS_Edge aShapeEdge = TopoDS::Edge( expE.Current() ); if ( BRep_Tool::Degenerated( aShapeEdge )) { degenNgIds.push_back( invalid_ID ); int* ptrIdOnEdge = & degenNgIds.back(); // remember edge id int edgeID = meshDS->ShapeToIndex( aShapeEdge ); degenShapeIdToPtrNgId.insert( make_pair( edgeID, ptrIdOnEdge )); // remember vertex id int vertexID = meshDS->ShapeToIndex( TopExp::FirstVertex( aShapeEdge )); degenShapeIdToPtrNgId.insert( make_pair( vertexID, ptrIdOnEdge )); } } } } // --------------------------------- // Feed the Netgen with surface mesh // --------------------------------- int Netgen_NbOfNodes = 0; int Netgen_param2ndOrder = 0; double Netgen_paramFine = 1.; double Netgen_paramSize = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. ); double Netgen_point[3]; int Netgen_triangle[3]; int Netgen_tetrahedron[4]; Ng_Init(); Ng_Mesh * Netgen_mesh = Ng_NewMesh(); // set nodes and remember thier netgen IDs bool isDegen = false, hasDegen = !degenShapeIdToPtrNgId.empty(); TNodeToIDMap::iterator n_id = nodeToNetgenID.begin(); for ( ; n_id != nodeToNetgenID.end(); ++n_id ) { const SMDS_MeshNode* node = n_id->first; // ignore nodes on degenerated edge if ( hasDegen ) { int shapeId = node->GetPosition()->GetShapeId(); shId_ngId = degenShapeIdToPtrNgId.find( shapeId ); isDegen = ( shId_ngId != degenShapeIdToPtrNgId.end() ); if ( isDegen && *(shId_ngId->second) != invalid_ID ) { n_id->second = *(shId_ngId->second); continue; } } Netgen_point [ 0 ] = node->X(); Netgen_point [ 1 ] = node->Y(); Netgen_point [ 2 ] = node->Z(); Ng_AddPoint(Netgen_mesh, Netgen_point); n_id->second = ++Netgen_NbOfNodes; // set netgen ID if ( isDegen ) // all nodes on a degen edge get one netgen ID *(shId_ngId->second) = n_id->second; } // set triangles list< const SMDS_MeshElement* >::iterator tria = triangles.begin(); list< bool >::iterator reverse = isReversed.begin(); for ( ; tria != triangles.end(); ++tria, ++reverse ) { int i = 0; SMDS_ElemIteratorPtr triangleNodesIt = (*tria)->nodesIterator(); while ( triangleNodesIt->more() ) { const SMDS_MeshNode * node = static_cast<const SMDS_MeshNode *>(triangleNodesIt->next()); if(myTool->IsMedium(node)) continue; Netgen_triangle[ *reverse ? 2 - i : i ] = nodeToNetgenID[ node ]; ++i; } if ( !hasDegen || // ignore degenerated triangles, they have 2 or 3 same ids (Netgen_triangle[0] != Netgen_triangle[1] && Netgen_triangle[0] != Netgen_triangle[2] && Netgen_triangle[2] != Netgen_triangle[1] )) { Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); } } // ------------------------- // Generate the volume mesh // ------------------------- Ng_Meshing_Parameters Netgen_param; Netgen_param.secondorder = Netgen_param2ndOrder; Netgen_param.fineness = Netgen_paramFine; Netgen_param.maxh = Netgen_paramSize; Ng_Result status; try { #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 OCC_CATCH_SIGNALS; #endif status = Ng_GenerateVolumeMesh(Netgen_mesh, &Netgen_param); } catch (Standard_Failure& exc) { error(COMPERR_OCC_EXCEPTION, exc.GetMessageString()); status = NG_VOLUME_FAILURE; } catch (...) { error("Exception in Ng_GenerateVolumeMesh()"); status = NG_VOLUME_FAILURE; } if ( GetComputeError()->IsOK() ) { switch ( status ) { case NG_SURFACE_INPUT_ERROR: error( status, "NG_SURFACE_INPUT_ERROR"); case NG_VOLUME_FAILURE: error( status, "NG_VOLUME_FAILURE"); case NG_STL_INPUT_ERROR: error( status, "NG_STL_INPUT_ERROR"); case NG_SURFACE_FAILURE: error( status, "NG_SURFACE_FAILURE"); case NG_FILE_NOT_FOUND: error( status, "NG_FILE_NOT_FOUND"); }; } int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh); int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh); MESSAGE("End of Volume Mesh Generation. status=" << status << ", nb new nodes: " << Netgen_NbOfNodesNew - Netgen_NbOfNodes << ", nb tetra: " << Netgen_NbOfTetra); // ------------------------------------------------------------------- // Feed back the SMESHDS with the generated Nodes and Volume Elements // ------------------------------------------------------------------- bool isOK = ( /*status == NG_OK &&*/ Netgen_NbOfTetra > 0 );// get whatever built if ( isOK ) { // vector of nodes in which node index == netgen ID vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 ); // insert old nodes into nodeVec for ( n_id = nodeToNetgenID.begin(); n_id != nodeToNetgenID.end(); ++n_id ) { nodeVec.at( n_id->second ) = n_id->first; } // create and insert new nodes into nodeVec int nodeIndex = Netgen_NbOfNodes + 1; int shapeID = meshDS->ShapeToIndex( aShape ); for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex ) { Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point ); SMDS_MeshNode * node = meshDS->AddNode(Netgen_point[0], Netgen_point[1], Netgen_point[2]); meshDS->SetNodeInVolume(node, shapeID); nodeVec.at(nodeIndex) = node; } // create tetrahedrons for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex ) { Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron); SMDS_MeshVolume * elt = myTool->AddVolume (nodeVec.at( Netgen_tetrahedron[0] ), nodeVec.at( Netgen_tetrahedron[1] ), nodeVec.at( Netgen_tetrahedron[2] ), nodeVec.at( Netgen_tetrahedron[3] )); meshDS->SetMeshElementOnShape(elt, shapeID ); } } Ng_DeleteMesh(Netgen_mesh); Ng_Exit(); NETGENPlugin_Mesher::RemoveTmpFiles(); return (status == NG_OK); }
bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { MESSAGE("NETGENPlugin_NETGEN_2D_ONLY::Compute()"); SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); int faceID = meshDS->ShapeToIndex( aShape ); SMESH_MesherHelper helper(aMesh); _quadraticMesh = helper.IsQuadraticSubMesh(aShape); helper.SetElementsOnShape( true ); const bool ignoreMediumNodes = _quadraticMesh; // ------------------------ // get all edges of a face // ------------------------ const TopoDS_Face F = TopoDS::Face( aShape.Oriented( TopAbs_FORWARD )); TError problem; TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, problem ); if ( problem && !problem->IsOK() ) return error( problem ); int nbWires = wires.size(); if ( nbWires == 0 ) return error( "Problem in StdMeshers_FaceSide::GetFaceWires()"); if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments return error(COMPERR_BAD_INPUT_MESH, SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments()); // ------------------------- // Make input netgen mesh // ------------------------- Ng_Init(); netgen::Mesh * ngMesh = new netgen::Mesh (); netgen::OCCGeometry occgeo; NETGENPlugin_Mesher::PrepareOCCgeometry( occgeo, F, aMesh ); occgeo.fmap.Clear(); // face can be reversed, which is wrong in this case (issue 19978) occgeo.fmap.Add( F ); vector< const SMDS_MeshNode* > nodeVec; problem = AddSegmentsToMesh( *ngMesh, occgeo, wires, helper, nodeVec ); if ( problem && !problem->IsOK() ) { delete ngMesh; Ng_Exit(); return error( problem ); } // -------------------- // compute edge length // -------------------- double edgeLength = 0; if (_hypLengthFromEdges || (!_hypLengthFromEdges && !_hypMaxElementArea)) { int nbSegments = 0; for ( int iW = 0; iW < nbWires; ++iW ) { edgeLength += wires[ iW ]->Length(); nbSegments += wires[ iW ]->NbSegments(); } if ( nbSegments ) edgeLength /= nbSegments; } if ( _hypMaxElementArea ) { double maxArea = _hypMaxElementArea->GetMaxArea(); edgeLength = sqrt(2. * maxArea/sqrt(3.0)); } if ( edgeLength < DBL_MIN ) edgeLength = occgeo.GetBoundingBox().Diam(); //cout << " edgeLength = " << edgeLength << endl; netgen::mparam.maxh = edgeLength; netgen::mparam.quad = _hypQuadranglePreference ? 1 : 0; //ngMesh->SetGlobalH ( edgeLength ); // ------------------------- // Generate surface mesh // ------------------------- char *optstr = 0; int startWith = MESHCONST_MESHSURFACE; int endWith = MESHCONST_OPTSURFACE; int err = 1; try { #if (OCC_VERSION_MAJOR << 16 | OCC_VERSION_MINOR << 8 | OCC_VERSION_MAINTENANCE) > 0x060100 OCC_CATCH_SIGNALS; #endif #ifdef NETGEN_V5 err = netgen::OCCGenerateMesh(occgeo, ngMesh,netgen::mparam, startWith, endWith); #else err = netgen::OCCGenerateMesh(occgeo, ngMesh, startWith, endWith, optstr); #endif } catch (Standard_Failure& ex) { string comment = ex.DynamicType()->Name(); if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) { comment += ": "; comment += ex.GetMessageString(); } error(COMPERR_OCC_EXCEPTION, comment); } catch (NgException exc) { error( SMESH_Comment("NgException: ") << exc.What() ); } catch (...) { error(COMPERR_EXCEPTION,"Exception in netgen::OCCGenerateMesh()"); } // ---------------------------------------------------- // Fill the SMESHDS with the generated nodes and faces // ---------------------------------------------------- int nbNodes = ngMesh->GetNP(); int nbFaces = ngMesh->GetNSE(); int nbInputNodes = nodeVec.size(); nodeVec.resize( nbNodes, 0 ); // add nodes for ( int i = nbInputNodes + 1; i <= nbNodes; ++i ) { const MeshPoint& ngPoint = ngMesh->Point(i); SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2)); nodeVec[ i-1 ] = node; } // create faces bool reverse = ( aShape.Orientation() == TopAbs_REVERSED ); for ( int i = 1; i <= nbFaces ; ++i ) { const Element2d& elem = ngMesh->SurfaceElement(i); vector<const SMDS_MeshNode*> nodes( elem.GetNP() ); for (int j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); const SMDS_MeshNode* node = nodeVec.at(pind-1); if ( reverse ) nodes[ nodes.size()-j ] = node; else nodes[ j-1 ] = node; if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) { const PointGeomInfo& pgi = elem.GeomInfoPi(j); meshDS->SetNodeOnFace((SMDS_MeshNode*)node, faceID, pgi.u, pgi.v); } } SMDS_MeshFace* face = 0; if ( elem.GetType() == TRIG ) face = helper.AddFace(nodes[0],nodes[1],nodes[2]); else face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); } Ng_DeleteMesh((nglib::Ng_Mesh*)ngMesh); Ng_Exit(); NETGENPlugin_Mesher::RemoveTmpFiles(); return !err; }
void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh) { if ( myShape.IsSame( aSh )) return; myShape = aSh; mySeamShapeIds.clear(); myDegenShapeIds.clear(); if ( myShape.IsNull() ) { myShapeID = -1; return; } SMESHDS_Mesh* meshDS = GetMeshDS(); myShapeID = meshDS->ShapeToIndex(aSh); // treatment of periodic faces for ( TopExp_Explorer eF( aSh, TopAbs_FACE ); eF.More(); eF.Next() ) { const TopoDS_Face& face = TopoDS::Face( eF.Current() ); BRepAdaptor_Surface surface( face ); if ( surface.IsUPeriodic() || surface.IsVPeriodic() ) { for (TopExp_Explorer exp( face, TopAbs_EDGE ); exp.More(); exp.Next()) { // look for a seam edge const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() ); if ( BRep_Tool::IsClosed( edge, face )) { // initialize myPar1, myPar2 and myParIndex if ( mySeamShapeIds.empty() ) { gp_Pnt2d uv1, uv2; BRep_Tool::UVPoints( edge, face, uv1, uv2 ); if ( Abs( uv1.Coord(1) - uv2.Coord(1) ) < Abs( uv1.Coord(2) - uv2.Coord(2) )) { myParIndex = 1; // U periodic myPar1 = surface.FirstUParameter(); myPar2 = surface.LastUParameter(); } else { myParIndex = 2; // V periodic myPar1 = surface.FirstVParameter(); myPar2 = surface.LastVParameter(); } } // store seam shape indices, negative if shape encounters twice int edgeID = meshDS->ShapeToIndex( edge ); mySeamShapeIds.insert( IsSeamShape( edgeID ) ? -edgeID : edgeID ); for ( TopExp_Explorer v( edge, TopAbs_VERTEX ); v.More(); v.Next() ) { int vertexID = meshDS->ShapeToIndex( v.Current() ); mySeamShapeIds.insert( IsSeamShape( vertexID ) ? -vertexID : vertexID ); } } // look for a degenerated edge if ( BRep_Tool::Degenerated( edge )) { myDegenShapeIds.insert( meshDS->ShapeToIndex( edge )); for ( TopExp_Explorer v( edge, TopAbs_VERTEX ); v.More(); v.Next() ) myDegenShapeIds.insert( meshDS->ShapeToIndex( v.Current() )); } } } } }
bool StdMeshers_CompositeSegment_1D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape) { TopoDS_Edge edge = TopoDS::Edge( aShape ); SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); // Get edges to be discretized as a whole TopoDS_Face nullFace; auto_ptr< StdMeshers_FaceSide > side( GetFaceSide(aMesh, edge, nullFace, true )); //side->dump("IN COMPOSITE SEG"); if ( side->NbEdges() < 2 ) return StdMeshers_Regular_1D::Compute( aMesh, aShape ); // update segment lenght computed by StdMeshers_AutomaticLength const list <const SMESHDS_Hypothesis * > & hyps = GetUsedHypothesis(aMesh, aShape); if ( !hyps.empty() ) { StdMeshers_AutomaticLength * autoLenHyp = const_cast<StdMeshers_AutomaticLength *> (dynamic_cast <const StdMeshers_AutomaticLength * >(hyps.front())); if ( autoLenHyp ) _value[ BEG_LENGTH_IND ]= autoLenHyp->GetLength( &aMesh, side->Length() ); } // Compute node parameters auto_ptr< BRepAdaptor_CompCurve > C3d ( side->GetCurve3d() ); double f = C3d->FirstParameter(), l = C3d->LastParameter(); list< double > params; if ( !computeInternalParameters ( aMesh, *C3d, side->Length(), f, l, params, false )) return false; // Redistribute parameters near ends TopoDS_Vertex VFirst = side->FirstVertex(); TopoDS_Vertex VLast = side->LastVertex(); redistributeNearVertices( aMesh, *C3d, side->Length(), params, VFirst, VLast ); params.push_front(f); params.push_back(l); int nbNodes = params.size(); // Create mesh const SMDS_MeshNode * nFirst = SMESH_Algo::VertexNode( VFirst, meshDS ); const SMDS_MeshNode * nLast = SMESH_Algo::VertexNode( VLast, meshDS ); if (!nFirst) return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ") <<meshDS->ShapeToIndex(VFirst)); if (!nLast) return error(COMPERR_BAD_INPUT_MESH, TComm("No node on vertex ") <<meshDS->ShapeToIndex(VLast)); vector<const SMDS_MeshNode*> nodes( nbNodes, (const SMDS_MeshNode*)0 ); nodes.front() = nFirst; nodes.back() = nLast; // create internal nodes list< double >::iterator parIt = params.begin(); double prevPar = *parIt; Standard_Real u; for ( int iN = 0; parIt != params.end(); ++iN, ++parIt) { if ( !nodes[ iN ] ) { gp_Pnt p = C3d->Value( *parIt ); SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z()); C3d->Edge( *parIt, edge, u ); meshDS->SetNodeOnEdge( n, edge, u ); // cout << "new NODE: par="<<*parIt<<" ePar="<<u<<" e="<<edge.TShape().operator->() // << " " << n << endl; nodes[ iN ] = n; } // create edges if ( iN ) { double mPar = ( prevPar + *parIt )/2; if ( _quadraticMesh ) { // create medium node double segLen = GCPnts_AbscissaPoint::Length(*C3d, prevPar, *parIt); GCPnts_AbscissaPoint ruler( *C3d, segLen/2., prevPar ); if ( ruler.IsDone() ) mPar = ruler.Parameter(); gp_Pnt p = C3d->Value( mPar ); SMDS_MeshNode* n = meshDS->AddNode( p.X(), p.Y(), p.Z()); //cout << "new NODE "<< n << endl; meshDS->SetNodeOnEdge( n, edge, u ); SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ], n); meshDS->SetMeshElementOnShape(seg, edge); } else { C3d->Edge( mPar, edge, u ); SMDS_MeshEdge * seg = meshDS->AddEdge(nodes[ iN-1 ], nodes[ iN ]); meshDS->SetMeshElementOnShape(seg, edge); } } prevPar = *parIt; } // remove nodes on internal vertices for ( int iE = 1; iE < side->NbEdges(); ++iE ) { TopoDS_Vertex V = side->FirstVertex( iE ); while ( const SMDS_MeshNode * n = SMESH_Algo::VertexNode( V, meshDS )) meshDS->RemoveNode( n ); } // Update submeshes state for all edges and internal vertices, // make them look computed even if none edge or node is set on them careOfSubMeshes( *side, _EventListener ); return true; }
bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { TopExp_Explorer exp; SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); myHelper = new SMESH_MesherHelper( aMesh ); myHelper->IsQuadraticSubMesh( aShape ); // to delete helper at exit from Compute() std::auto_ptr<SMESH_MesherHelper> helperDeleter( myHelper ); // get 2 shells TopoDS_Solid solid = TopoDS::Solid( aShape ); TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); TopoDS_Shape innerShell; int nbShells = 0; for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) if ( !outerShell.IsSame( It.Value() )) innerShell = It.Value(); if ( nbShells != 2 ) return error(COMPERR_BAD_SHAPE, SMESH_Comment("Must be 2 shells but not ")<<nbShells); // ---------------------------------- // Associate sub-shapes of the shells // ---------------------------------- ProjectionUtils::TShapeShapeMap shape2ShapeMaps[2]; bool mapOk1 = ProjectionUtils::FindSubShapeAssociation( innerShell, &aMesh, outerShell, &aMesh, shape2ShapeMaps[0]); bool mapOk2 = ProjectionUtils::FindSubShapeAssociation( innerShell.Reversed(), &aMesh, outerShell, &aMesh, shape2ShapeMaps[1]); if ( !mapOk1 && !mapOk2 ) return error(COMPERR_BAD_SHAPE,"Topology of inner and outer shells seems different" ); int iMap; if ( shape2ShapeMaps[0].Extent() == shape2ShapeMaps[1].Extent() ) { // choose an assiciation by shortest distance between VERTEXes double dist1 = 0, dist2 = 0; TopTools_DataMapIteratorOfDataMapOfShapeShape ssIt( shape2ShapeMaps[0]._map1to2 ); for (; ssIt.More(); ssIt.Next() ) { if ( ssIt.Key().ShapeType() != TopAbs_VERTEX ) continue; gp_Pnt pIn = BRep_Tool::Pnt( TopoDS::Vertex( ssIt.Key() )); gp_Pnt pOut1 = BRep_Tool::Pnt( TopoDS::Vertex( ssIt.Value() )); gp_Pnt pOut2 = BRep_Tool::Pnt( TopoDS::Vertex( shape2ShapeMaps[1]( ssIt.Key() ))); dist1 += pIn.SquareDistance( pOut1 ); dist2 += pIn.SquareDistance( pOut2 ); } iMap = ( dist1 < dist2 ) ? 0 : 1; } else { iMap = ( shape2ShapeMaps[0].Extent() > shape2ShapeMaps[1].Extent() ) ? 0 : 1; } ProjectionUtils::TShapeShapeMap& shape2ShapeMap = shape2ShapeMaps[iMap]; // ------------------ // Make mesh // ------------------ TNode2ColumnMap node2columnMap; myLayerPositions.clear(); for ( exp.Init( outerShell, TopAbs_FACE ); exp.More(); exp.Next() ) { // Corresponding sub-shapes TopoDS_Face outFace = TopoDS::Face( exp.Current() ); TopoDS_Face inFace; if ( !shape2ShapeMap.IsBound( outFace, /*isOut=*/true )) { return error(SMESH_Comment("Corresponding inner face not found for face #" ) << meshDS->ShapeToIndex( outFace )); } else { inFace = TopoDS::Face( shape2ShapeMap( outFace, /*isOut=*/true )); } // Find matching nodes of in and out faces ProjectionUtils::TNodeNodeMap nodeIn2OutMap; if ( ! ProjectionUtils::FindMatchingNodesOnFaces( inFace, &aMesh, outFace, &aMesh, shape2ShapeMap, nodeIn2OutMap )) return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Mesh on faces #") << meshDS->ShapeToIndex( outFace ) << " and " << meshDS->ShapeToIndex( inFace ) << " seems different" ); // Create volumes SMDS_ElemIteratorPtr faceIt = meshDS->MeshElements( inFace )->GetElements(); while ( faceIt->more() ) // loop on faces on inFace { const SMDS_MeshElement* face = faceIt->next(); if ( !face || face->GetType() != SMDSAbs_Face ) continue; int nbNodes = face->NbNodes(); if ( face->IsQuadratic() ) nbNodes /= 2; // find node columns for each node vector< const TNodeColumn* > columns( nbNodes ); for ( int i = 0; i < nbNodes; ++i ) { const SMDS_MeshNode* nIn = face->GetNode( i ); TNode2ColumnMap::iterator n_col = node2columnMap.find( nIn ); if ( n_col != node2columnMap.end() ) { columns[ i ] = & n_col->second; } else { TNodeNodeMap::iterator nInOut = nodeIn2OutMap.find( nIn ); if ( nInOut == nodeIn2OutMap.end() ) RETURN_BAD_RESULT("No matching node for "<< nIn->GetID() << " in face "<< face->GetID()); columns[ i ] = makeNodeColumn( node2columnMap, nIn, nInOut->second ); } } StdMeshers_Prism_3D::AddPrisms( columns, myHelper ); } } // loop on faces of out shell return true; }
bool StdMeshers_RadialPrism_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { TopExp_Explorer exp; SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); myHelper = new SMESH_MesherHelper( aMesh ); myHelper->IsQuadraticSubMesh( aShape ); // to delete helper at exit from Compute() std::auto_ptr<SMESH_MesherHelper> helperDeleter( myHelper ); // get 2 shells TopoDS_Solid solid = TopoDS::Solid( aShape ); TopoDS_Shell outerShell = BRepClass3d::OuterShell( solid ); TopoDS_Shape innerShell; int nbShells = 0; for ( TopoDS_Iterator It (solid); It.More(); It.Next(), ++nbShells ) if ( !outerShell.IsSame( It.Value() )) innerShell = It.Value(); if ( nbShells != 2 ) return error(COMPERR_BAD_SHAPE, SMESH_Comment("Must be 2 shells but not ")<<nbShells); // ---------------------------------- // Associate subshapes of the shells // ---------------------------------- TAssocTool::TShapeShapeMap shape2ShapeMap; if ( !TAssocTool::FindSubShapeAssociation( outerShell, &aMesh, innerShell, &aMesh, shape2ShapeMap) ) return error(COMPERR_BAD_SHAPE,"Topology of inner and outer shells seems different" ); // ------------------ // Make mesh // ------------------ TNode2ColumnMap node2columnMap; myLayerPositions.clear(); for ( exp.Init( outerShell, TopAbs_FACE ); exp.More(); exp.Next() ) { // Corresponding subshapes TopoDS_Face outFace = TopoDS::Face( exp.Current() ); TopoDS_Face inFace; if ( !shape2ShapeMap.IsBound( outFace )) { return error(SMESH_Comment("Corresponding inner face not found for face #" ) << meshDS->ShapeToIndex( outFace )); } else { inFace = TopoDS::Face( shape2ShapeMap( outFace )); } // Find matching nodes of in and out faces TNodeNodeMap nodeIn2OutMap; if ( ! TAssocTool::FindMatchingNodesOnFaces( inFace, &aMesh, outFace, &aMesh, shape2ShapeMap, nodeIn2OutMap )) return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Mesh on faces #") << meshDS->ShapeToIndex( outFace ) << " and " << meshDS->ShapeToIndex( inFace ) << " seems different" ); // Create volumes SMDS_ElemIteratorPtr faceIt = meshDS->MeshElements( inFace )->GetElements(); while ( faceIt->more() ) // loop on faces on inFace { const SMDS_MeshElement* face = faceIt->next(); if ( !face || face->GetType() != SMDSAbs_Face ) continue; int nbNodes = face->NbNodes(); if ( face->IsQuadratic() ) nbNodes /= 2; // find node columns for each node vector< const TNodeColumn* > columns( nbNodes ); for ( int i = 0; i < nbNodes; ++i ) { const SMDS_MeshNode* nIn = face->GetNode( i ); TNode2ColumnMap::iterator n_col = node2columnMap.find( nIn ); if ( n_col != node2columnMap.end() ) { columns[ i ] = & n_col->second; } else { TNodeNodeMap::iterator nInOut = nodeIn2OutMap.find( nIn ); if ( nInOut == nodeIn2OutMap.end() ) RETURN_BAD_RESULT("No matching node for "<< nIn->GetID() << " in face "<< face->GetID()); columns[ i ] = makeNodeColumn( node2columnMap, nIn, nInOut->second ); } } StdMeshers_Prism_3D::AddPrisms( columns, myHelper ); } } // loop on faces of out shell return true; }
bool StdMeshers_Projection_3D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { if ( !_sourceHypo ) return false; SMESH_Mesh * srcMesh = _sourceHypo->GetSourceMesh(); SMESH_Mesh * tgtMesh = & aMesh; if ( !srcMesh ) srcMesh = tgtMesh; SMESHDS_Mesh * srcMeshDS = srcMesh->GetMeshDS(); SMESHDS_Mesh * tgtMeshDS = tgtMesh->GetMeshDS(); // get shell from shape3D TopoDS_Shell srcShell, tgtShell; TopExp_Explorer exp( _sourceHypo->GetSource3DShape(), TopAbs_SHELL ); int nbShell; for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell ) srcShell = TopoDS::Shell( exp.Current() ); if ( nbShell != 1 ) return error(COMPERR_BAD_SHAPE, SMESH_Comment("Source shape must have 1 shell but not ") << nbShell); exp.Init( aShape, TopAbs_SHELL ); for ( nbShell = 0; exp.More(); exp.Next(), ++nbShell ) tgtShell = TopoDS::Shell( exp.Current() ); if ( nbShell != 1 ) return error(COMPERR_BAD_SHAPE, SMESH_Comment("Target shape must have 1 shell but not ") << nbShell); // Check that shapes are blocks if ( TAssocTool::Count( tgtShell, TopAbs_FACE , 1 ) != 6 || TAssocTool::Count( tgtShell, TopAbs_EDGE , 1 ) != 12 || TAssocTool::Count( tgtShell, TopAbs_WIRE , 1 ) != 6 ) return error(COMPERR_BAD_SHAPE, "Target shape is not a block"); if ( TAssocTool::Count( srcShell, TopAbs_FACE , 1 ) != 6 || TAssocTool::Count( srcShell, TopAbs_EDGE , 1 ) != 12 || TAssocTool::Count( srcShell, TopAbs_WIRE , 1 ) != 6 ) return error(COMPERR_BAD_SHAPE, "Source shape is not a block"); // Assure that mesh on a source shape is computed SMESH_subMesh* srcSubMesh = srcMesh->GetSubMesh( _sourceHypo->GetSource3DShape() ); //SMESH_subMesh* tgtSubMesh = tgtMesh->GetSubMesh( aShape ); if ( tgtMesh == srcMesh && !aShape.IsSame( _sourceHypo->GetSource3DShape() )) { if ( !TAssocTool::MakeComputed( srcSubMesh )) return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); } else { if ( !srcSubMesh->IsMeshComputed() ) return error(COMPERR_BAD_INPUT_MESH,"Source mesh not computed"); } // Find 2 pairs of corresponding vertices TopoDS_Vertex tgtV000, tgtV100, srcV000, srcV100; TAssocTool::TShapeShapeMap shape2ShapeMap; if ( _sourceHypo->HasVertexAssociation() ) { tgtV000 = _sourceHypo->GetTargetVertex(1); tgtV100 = _sourceHypo->GetTargetVertex(2); srcV000 = _sourceHypo->GetSourceVertex(1); srcV100 = _sourceHypo->GetSourceVertex(2); } else { if ( !TAssocTool::FindSubShapeAssociation( tgtShell, tgtMesh, srcShell, srcMesh, shape2ShapeMap) ) return error(COMPERR_BAD_SHAPE,"Topology of source and target shapes seems different" ); exp.Init( tgtShell, TopAbs_EDGE ); TopExp::Vertices( TopoDS::Edge( exp.Current() ), tgtV000, tgtV100 ); if ( !shape2ShapeMap.IsBound( tgtV000 ) || !shape2ShapeMap.IsBound( tgtV100 )) return error("Association of subshapes failed" ); srcV000 = TopoDS::Vertex( shape2ShapeMap( tgtV000 )); srcV100 = TopoDS::Vertex( shape2ShapeMap( tgtV100 )); if ( !TAssocTool::IsSubShape( srcV000, srcShell ) || !TAssocTool::IsSubShape( srcV100, srcShell )) return error("Incorrect association of subshapes" ); } // Load 2 SMESH_Block's with src and tgt shells SMESH_Block srcBlock, tgtBlock; TopTools_IndexedMapOfOrientedShape scrShapes, tgtShapes; if ( !tgtBlock.LoadBlockShapes( tgtShell, tgtV000, tgtV100, tgtShapes )) return error(COMPERR_BAD_SHAPE, "Can't detect block subshapes. Not a block?"); if ( !srcBlock.LoadBlockShapes( srcShell, srcV000, srcV100, scrShapes )) return error(COMPERR_BAD_SHAPE, "Can't detect block subshapes. Not a block?"); // Find matching nodes of src and tgt shells TNodeNodeMap src2tgtNodeMap; for ( int fId = SMESH_Block::ID_FirstF; fId < SMESH_Block::ID_Shell; ++fId ) { // Corresponding subshapes TopoDS_Face srcFace = TopoDS::Face( scrShapes( fId )); TopoDS_Face tgtFace = TopoDS::Face( tgtShapes( fId )); if ( _sourceHypo->HasVertexAssociation() ) { // associate face subshapes shape2ShapeMap.Clear(); vector< int > edgeIdVec; SMESH_Block::GetFaceEdgesIDs( fId, edgeIdVec ); for ( int i = 0; i < edgeIdVec.size(); ++i ) { int eID = edgeIdVec[ i ]; shape2ShapeMap.Bind( tgtShapes( eID ), scrShapes( eID )); if ( i < 2 ) { vector< int > vertexIdVec; SMESH_Block::GetEdgeVertexIDs( eID, vertexIdVec ); shape2ShapeMap.Bind( tgtShapes( vertexIdVec[0] ), scrShapes( vertexIdVec[0] )); shape2ShapeMap.Bind( tgtShapes( vertexIdVec[1] ), scrShapes( vertexIdVec[1] )); } } } // Find matching nodes of tgt and src faces TNodeNodeMap faceMatchingNodes; if ( ! TAssocTool::FindMatchingNodesOnFaces( srcFace, srcMesh, tgtFace, tgtMesh, shape2ShapeMap, faceMatchingNodes )) return error(COMPERR_BAD_INPUT_MESH,SMESH_Comment("Mesh on faces #") << srcMeshDS->ShapeToIndex( srcFace ) << " and " << tgtMeshDS->ShapeToIndex( tgtFace ) << " seems different" ); // put found matching nodes of 2 faces to the global map src2tgtNodeMap.insert( faceMatchingNodes.begin(), faceMatchingNodes.end() ); } // ------------------ // Make mesh // ------------------ SMDS_VolumeTool volTool; SMESH_MesherHelper helper( *tgtMesh ); helper.IsQuadraticSubMesh( aShape ); SMESHDS_SubMesh* srcSMDS = srcSubMesh->GetSubMeshDS(); SMDS_ElemIteratorPtr volIt = srcSMDS->GetElements(); while ( volIt->more() ) // loop on source volumes { const SMDS_MeshElement* srcVol = volIt->next(); if ( !srcVol || srcVol->GetType() != SMDSAbs_Volume ) continue; int nbNodes = srcVol->NbNodes(); SMDS_VolumeTool::VolumeType volType = volTool.GetType( nbNodes ); if ( srcVol->IsQuadratic() ) nbNodes = volTool.NbCornerNodes( volType ); // Find or create a new tgt node for each node of a src volume vector< const SMDS_MeshNode* > nodes( nbNodes ); for ( int i = 0; i < nbNodes; ++i ) { const SMDS_MeshNode* srcNode = srcVol->GetNode( i ); const SMDS_MeshNode* tgtNode = 0; TNodeNodeMap::iterator sN_tN = src2tgtNodeMap.find( srcNode ); if ( sN_tN != src2tgtNodeMap.end() ) // found { tgtNode = sN_tN->second; } else // Create a new tgt node { // compute normalized parameters of source node in srcBlock gp_Pnt srcCoord = gpXYZ( srcNode ); gp_XYZ srcParam; if ( !srcBlock.ComputeParameters( srcCoord, srcParam )) return error(SMESH_Comment("Can't compute normalized parameters ") << "for source node " << srcNode->GetID()); // compute coordinates of target node by srcParam gp_XYZ tgtXYZ; if ( !tgtBlock.ShellPoint( srcParam, tgtXYZ )) return error("Can't compute coordinates by normalized parameters"); // add node SMDS_MeshNode* newNode = tgtMeshDS->AddNode( tgtXYZ.X(), tgtXYZ.Y(), tgtXYZ.Z() ); tgtMeshDS->SetNodeInVolume( newNode, helper.GetSubShapeID() ); tgtNode = newNode; src2tgtNodeMap.insert( make_pair( srcNode, tgtNode )); } nodes[ i ] = tgtNode; } // Create a new volume SMDS_MeshVolume * tgtVol = 0; int id = 0, force3d = false; switch ( volType ) { case SMDS_VolumeTool::TETRA : case SMDS_VolumeTool::QUAD_TETRA: tgtVol = helper.AddVolume( nodes[0], nodes[1], nodes[2], nodes[3], id, force3d); break; case SMDS_VolumeTool::PYRAM : case SMDS_VolumeTool::QUAD_PYRAM: tgtVol = helper.AddVolume( nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, force3d); break; case SMDS_VolumeTool::PENTA : case SMDS_VolumeTool::QUAD_PENTA: tgtVol = helper.AddVolume( nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, force3d); break; case SMDS_VolumeTool::HEXA : case SMDS_VolumeTool::QUAD_HEXA : tgtVol = helper.AddVolume( nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], nodes[6], nodes[7], id, force3d); break; default: // polyhedron const SMDS_PolyhedralVolumeOfNodes * poly = dynamic_cast<const SMDS_PolyhedralVolumeOfNodes*>( srcVol ); if ( !poly ) RETURN_BAD_RESULT("Unexpected volume type"); tgtVol = tgtMeshDS->AddPolyhedralVolume( nodes, poly->GetQuanities() ); } if ( tgtVol ) { tgtMeshDS->SetMeshElementOnShape( tgtVol, helper.GetSubShapeID() ); } } // loop on volumes of src shell return true; }
bool StdMeshers_RadialQuadrangle_1D2D::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { TopExp_Explorer exp; SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); myHelper = new SMESH_MesherHelper( aMesh ); myHelper->IsQuadraticSubMesh( aShape ); // to delete helper at exit from Compute() auto_ptr<SMESH_MesherHelper> helperDeleter( myHelper ); myLayerPositions.clear(); TopoDS_Edge CircEdge, LinEdge1, LinEdge2; int nbe = analyseFace( aShape, CircEdge, LinEdge1, LinEdge2 ); if( nbe>3 || nbe < 1 || CircEdge.IsNull() ) return error(COMPERR_BAD_SHAPE); gp_Pnt P0,P1; // points for rotation TColgp_SequenceOfPnt Points; // angles for rotation TColStd_SequenceOfReal Angles; // Nodes1 and Nodes2 - nodes along radiuses // CNodes - nodes on circle edge vector< const SMDS_MeshNode* > Nodes1, Nodes2, CNodes; SMDS_MeshNode * NC; // parameters edge nodes on face TColgp_SequenceOfPnt2d Pnts2d1; gp_Pnt2d PC; int faceID = meshDS->ShapeToIndex(aShape); TopoDS_Face F = TopoDS::Face(aShape); Handle(Geom_Surface) S = BRep_Tool::Surface(F); if(nbe==1) { Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); bool ok = _gen->Compute( aMesh, CircEdge ); if( !ok ) return false; map< double, const SMDS_MeshNode* > theNodes; ok = GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes); if( !ok ) return false; CNodes.clear(); map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); const SMDS_MeshNode* NF = (*itn).second; CNodes.push_back( (*itn).second ); double fang = (*itn).first; if ( itn != theNodes.end() ) { itn++; for(; itn != theNodes.end(); itn++ ) { CNodes.push_back( (*itn).second ); double ang = (*itn).first - fang; if( ang>M_PI ) ang = ang - 2*M_PI; if( ang<-M_PI ) ang = ang + 2*M_PI; Angles.Append( ang ); } } P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); P0 = aCirc->Location(); myLayerPositions.clear(); computeLayerPositions(P0,P1); exp.Init( CircEdge, TopAbs_VERTEX ); TopoDS_Vertex V1 = TopoDS::Vertex( exp.Current() ); gp_Pnt2d p2dV = BRep_Tool::Parameters( V1, TopoDS::Face(aShape) ); NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); GeomAPI_ProjectPointOnSurf PPS(P0,S); double U0,V0; PPS.Parameters(1,U0,V0); meshDS->SetNodeOnFace(NC, faceID, U0, V0); PC = gp_Pnt2d(U0,V0); gp_Vec aVec(P0,P1); gp_Vec2d aVec2d(PC,p2dV); Nodes1.resize( myLayerPositions.size()+1 ); Nodes2.resize( myLayerPositions.size()+1 ); int i = 0; for(; i<myLayerPositions.size(); i++) { gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i], P0.Y() + aVec.Y()*myLayerPositions[i], P0.Z() + aVec.Z()*myLayerPositions[i] ); Points.Append(P); SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes1[i] = node; Nodes2[i] = node; double U = PC.X() + aVec2d.X()*myLayerPositions[i]; double V = PC.Y() + aVec2d.Y()*myLayerPositions[i]; meshDS->SetNodeOnFace( node, faceID, U, V ); Pnts2d1.Append(gp_Pnt2d(U,V)); } Nodes1[Nodes1.size()-1] = NF; Nodes2[Nodes1.size()-1] = NF; } else if(nbe==2 && LinEdge1.Orientation() != TopAbs_INTERNAL ) { // one curve must be a half of circle and other curve must be // a segment of line double fp, lp; Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge, &fp, &lp )); if( fabs(fabs(lp-fp)-M_PI) > Precision::Confusion() ) { // not half of circle return error(COMPERR_BAD_SHAPE); } Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 )); if( aLine.IsNull() ) { // other curve not line return error(COMPERR_BAD_SHAPE); } bool linEdgeComputed = false; if( SMESH_subMesh* sm1 = aMesh.GetSubMesh(LinEdge1) ) { if( !sm1->IsEmpty() ) { if( isEdgeCompitaballyMeshed( LinEdge1, aMesh.GetSubMesh(F) )) linEdgeComputed = true; else return error("Invalid set of hypotheses"); } } bool ok = _gen->Compute( aMesh, CircEdge ); if( !ok ) return false; map< double, const SMDS_MeshNode* > theNodes; GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes); CNodes.clear(); map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); double fang = (*itn).first; itn++; for(; itn != theNodes.end(); itn++ ) { CNodes.push_back( (*itn).second ); double ang = (*itn).first - fang; if( ang>M_PI ) ang = ang - 2*M_PI; if( ang<-M_PI ) ang = ang + 2*M_PI; Angles.Append( ang ); } const SMDS_MeshNode* NF = theNodes.begin()->second; const SMDS_MeshNode* NL = theNodes.rbegin()->second; CNodes.push_back( NF ); P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); gp_Pnt P2( NL->X(), NL->Y(), NL->Z() ); P0 = aCirc->Location(); myLayerPositions.clear(); computeLayerPositions(P0,P1); if ( linEdgeComputed ) { if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes)) return error("Invalid mesh on a straight edge"); vector< const SMDS_MeshNode* > *pNodes1 = &Nodes1, *pNodes2 = &Nodes2; bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF ); if ( !nodesFromP0ToP1 ) std::swap( pNodes1, pNodes2 ); map< double, const SMDS_MeshNode* >::reverse_iterator ritn = theNodes.rbegin(); itn = theNodes.begin(); for ( int i = Nodes1.size()-1; i > -1; ++itn, ++ritn, --i ) { (*pNodes1)[i] = ritn->second; (*pNodes2)[i] = itn->second; Points.Append( gpXYZ( Nodes1[i])); Pnts2d1.Append( myHelper->GetNodeUV( F, Nodes1[i])); } NC = const_cast<SMDS_MeshNode*>( itn->second ); Points.Remove( Nodes1.size() ); } else { gp_Vec aVec(P0,P1); int edgeID = meshDS->ShapeToIndex(LinEdge1); // check orientation Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge1,fp,lp); gp_Pnt Ptmp; Crv->D0(fp,Ptmp); bool ori = true; if( P1.Distance(Ptmp) > Precision::Confusion() ) ori = false; // get UV points for edge gp_Pnt2d PF,PL; BRep_Tool::UVPoints( LinEdge1, TopoDS::Face(aShape), PF, PL ); PC = gp_Pnt2d( (PF.X()+PL.X())/2, (PF.Y()+PL.Y())/2 ); gp_Vec2d V2d; if(ori) V2d = gp_Vec2d(PC,PF); else V2d = gp_Vec2d(PC,PL); // add nodes on edge double cp = (fp+lp)/2; double dp2 = (lp-fp)/2; NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); meshDS->SetNodeOnEdge(NC, edgeID, cp); Nodes1.resize( myLayerPositions.size()+1 ); Nodes2.resize( myLayerPositions.size()+1 ); int i = 0; for(; i<myLayerPositions.size(); i++) { gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i], P0.Y() + aVec.Y()*myLayerPositions[i], P0.Z() + aVec.Z()*myLayerPositions[i] ); Points.Append(P); SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes1[i] = node; double param; if(ori) param = fp + dp2*(1-myLayerPositions[i]); else param = cp + dp2*myLayerPositions[i]; meshDS->SetNodeOnEdge(node, edgeID, param); P = gp_Pnt( P0.X() - aVec.X()*myLayerPositions[i], P0.Y() - aVec.Y()*myLayerPositions[i], P0.Z() - aVec.Z()*myLayerPositions[i] ); node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes2[i] = node; if(!ori) param = fp + dp2*(1-myLayerPositions[i]); else param = cp + dp2*myLayerPositions[i]; meshDS->SetNodeOnEdge(node, edgeID, param); // parameters on face gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], PC.Y() + V2d.Y()*myLayerPositions[i] ); Pnts2d1.Append(P2d); } Nodes1[ myLayerPositions.size() ] = NF; Nodes2[ myLayerPositions.size() ] = NL; // create 1D elements on edge vector< const SMDS_MeshNode* > tmpNodes; tmpNodes.resize(2*Nodes1.size()+1); for(i=0; i<Nodes2.size(); i++) tmpNodes[Nodes2.size()-i-1] = Nodes2[i]; tmpNodes[Nodes2.size()] = NC; for(i=0; i<Nodes1.size(); i++) tmpNodes[Nodes2.size()+1+i] = Nodes1[i]; for(i=1; i<tmpNodes.size(); i++) { SMDS_MeshEdge* ME = myHelper->AddEdge( tmpNodes[i-1], tmpNodes[i] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); } markLinEdgeAsComputedByMe( LinEdge1, aMesh.GetSubMesh( F )); } } else // nbe==3 or ( nbe==2 && linEdge is INTERNAL ) { if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL ) LinEdge2 = LinEdge1; // one curve must be a part of circle and other curves must be // segments of line double fp, lp; Handle(Geom_Circle) aCirc = Handle(Geom_Circle)::DownCast( getCurve( CircEdge )); Handle(Geom_Line) aLine1 = Handle(Geom_Line)::DownCast( getCurve( LinEdge1 )); Handle(Geom_Line) aLine2 = Handle(Geom_Line)::DownCast( getCurve( LinEdge2 )); if( aLine1.IsNull() || aLine2.IsNull() ) { // other curve not line return error(COMPERR_BAD_SHAPE); } bool linEdge1Computed = false; if ( SMESH_subMesh* sm1 = aMesh.GetSubMesh(LinEdge1)) if( !sm1->IsEmpty() ) { if( isEdgeCompitaballyMeshed( LinEdge1, aMesh.GetSubMesh(F) )) linEdge1Computed = true; else return error("Invalid set of hypotheses"); } bool linEdge2Computed = false; if ( SMESH_subMesh* sm2 = aMesh.GetSubMesh(LinEdge2)) if( !sm2->IsEmpty() ) { if( isEdgeCompitaballyMeshed( LinEdge2, aMesh.GetSubMesh(F) )) linEdge2Computed = true; else return error("Invalid set of hypotheses"); } bool ok = _gen->Compute( aMesh, CircEdge ); if( !ok ) return false; map< double, const SMDS_MeshNode* > theNodes; GetSortedNodesOnEdge(aMesh.GetMeshDS(),CircEdge,true,theNodes); const SMDS_MeshNode* NF = theNodes.begin()->second; const SMDS_MeshNode* NL = theNodes.rbegin()->second; CNodes.clear(); CNodes.push_back( NF ); map< double, const SMDS_MeshNode* >::iterator itn = theNodes.begin(); double fang = (*itn).first; itn++; for(; itn != theNodes.end(); itn++ ) { CNodes.push_back( (*itn).second ); double ang = (*itn).first - fang; if( ang>M_PI ) ang = ang - 2*M_PI; if( ang<-M_PI ) ang = ang + 2*M_PI; Angles.Append( ang ); } P1 = gp_Pnt( NF->X(), NF->Y(), NF->Z() ); gp_Pnt P2( NL->X(), NL->Y(), NL->Z() ); P0 = aCirc->Location(); myLayerPositions.clear(); computeLayerPositions(P0,P1); Nodes1.resize( myLayerPositions.size()+1 ); Nodes2.resize( myLayerPositions.size()+1 ); exp.Init( LinEdge1, TopAbs_VERTEX ); TopoDS_Vertex V1 = TopoDS::Vertex( exp.Current() ); exp.Next(); TopoDS_Vertex V2 = TopoDS::Vertex( exp.Current() ); gp_Pnt PE1 = BRep_Tool::Pnt(V1); gp_Pnt PE2 = BRep_Tool::Pnt(V2); if( ( P1.Distance(PE1) > Precision::Confusion() ) && ( P1.Distance(PE2) > Precision::Confusion() ) ) { std::swap( LinEdge1, LinEdge2 ); std::swap( linEdge1Computed, linEdge2Computed ); } TopoDS_Vertex VC = V2; if( ( P1.Distance(PE1) > Precision::Confusion() ) && ( P2.Distance(PE1) > Precision::Confusion() ) ) VC = V1; int vertID = meshDS->ShapeToIndex(VC); // LinEdge1 if ( linEdge1Computed ) { if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge1,true,theNodes)) return error("Invalid mesh on a straight edge"); bool nodesFromP0ToP1 = ( theNodes.rbegin()->second == NF ); NC = const_cast<SMDS_MeshNode*> ( nodesFromP0ToP1 ? theNodes.begin()->second : theNodes.rbegin()->second ); int i = 0, ir = Nodes1.size()-1; int * pi = nodesFromP0ToP1 ? &i : &ir; itn = theNodes.begin(); if ( nodesFromP0ToP1 ) ++itn; for ( ; i < Nodes1.size(); ++i, --ir, ++itn ) { Nodes1[*pi] = itn->second; } for ( i = 0; i < Nodes1.size()-1; ++i ) { Points.Append( gpXYZ( Nodes1[i])); Pnts2d1.Append( myHelper->GetNodeUV( F, Nodes1[i])); } } else { int edgeID = meshDS->ShapeToIndex(LinEdge1); gp_Vec aVec(P0,P1); // check orientation Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge1,fp,lp); gp_Pnt Ptmp = Crv->Value(fp); bool ori = false; if( P1.Distance(Ptmp) > Precision::Confusion() ) ori = true; // get UV points for edge gp_Pnt2d PF,PL; BRep_Tool::UVPoints( LinEdge1, TopoDS::Face(aShape), PF, PL ); gp_Vec2d V2d; if(ori) { V2d = gp_Vec2d(PF,PL); PC = PF; } else { V2d = gp_Vec2d(PL,PF); PC = PL; } NC = const_cast<SMDS_MeshNode*>( VertexNode( VC, meshDS )); if ( !NC ) { NC = meshDS->AddNode(P0.X(), P0.Y(), P0.Z()); meshDS->SetNodeOnVertex(NC, vertID); } double dp = lp-fp; int i = 0; for(; i<myLayerPositions.size(); i++) { gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i], P0.Y() + aVec.Y()*myLayerPositions[i], P0.Z() + aVec.Z()*myLayerPositions[i] ); Points.Append(P); SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes1[i] = node; double param; if(!ori) param = fp + dp*(1-myLayerPositions[i]); else param = fp + dp*myLayerPositions[i]; meshDS->SetNodeOnEdge(node, edgeID, param); // parameters on face gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], PC.Y() + V2d.Y()*myLayerPositions[i] ); Pnts2d1.Append(P2d); } Nodes1[ myLayerPositions.size() ] = NF; // create 1D elements on edge SMDS_MeshEdge* ME = myHelper->AddEdge( NC, Nodes1[0] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); for(i=1; i<Nodes1.size(); i++) { ME = myHelper->AddEdge( Nodes1[i-1], Nodes1[i] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); } if (nbe==2 && LinEdge1.Orientation() == TopAbs_INTERNAL ) Nodes2 = Nodes1; } markLinEdgeAsComputedByMe( LinEdge1, aMesh.GetSubMesh( F )); // LinEdge2 if ( linEdge2Computed ) { if (!GetSortedNodesOnEdge(aMesh.GetMeshDS(),LinEdge2,true,theNodes)) return error("Invalid mesh on a straight edge"); bool nodesFromP0ToP2 = ( theNodes.rbegin()->second == NL ); int i = 0, ir = Nodes1.size()-1; int * pi = nodesFromP0ToP2 ? &i : &ir; itn = theNodes.begin(); if ( nodesFromP0ToP2 ) ++itn; for ( ; i < Nodes2.size(); ++i, --ir, ++itn ) Nodes2[*pi] = itn->second; } else { int edgeID = meshDS->ShapeToIndex(LinEdge2); gp_Vec aVec = gp_Vec(P0,P2); // check orientation Handle(Geom_Curve) Crv = BRep_Tool::Curve(LinEdge2,fp,lp); gp_Pnt Ptmp = Crv->Value(fp); bool ori = false; if( P2.Distance(Ptmp) > Precision::Confusion() ) ori = true; // get UV points for edge gp_Pnt2d PF,PL; BRep_Tool::UVPoints( LinEdge2, TopoDS::Face(aShape), PF, PL ); gp_Vec2d V2d; if(ori) { V2d = gp_Vec2d(PF,PL); PC = PF; } else { V2d = gp_Vec2d(PL,PF); PC = PL; } double dp = lp-fp; for(int i=0; i<myLayerPositions.size(); i++) { gp_Pnt P( P0.X() + aVec.X()*myLayerPositions[i], P0.Y() + aVec.Y()*myLayerPositions[i], P0.Z() + aVec.Z()*myLayerPositions[i] ); SMDS_MeshNode * node = meshDS->AddNode(P.X(), P.Y(), P.Z()); Nodes2[i] = node; double param; if(!ori) param = fp + dp*(1-myLayerPositions[i]); else param = fp + dp*myLayerPositions[i]; meshDS->SetNodeOnEdge(node, edgeID, param); // parameters on face gp_Pnt2d P2d( PC.X() + V2d.X()*myLayerPositions[i], PC.Y() + V2d.Y()*myLayerPositions[i] ); } Nodes2[ myLayerPositions.size() ] = NL; // create 1D elements on edge SMDS_MeshEdge* ME = myHelper->AddEdge( NC, Nodes2[0] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); for(int i=1; i<Nodes2.size(); i++) { ME = myHelper->AddEdge( Nodes2[i-1], Nodes2[i] ); if(ME) meshDS->SetMeshElementOnShape(ME, edgeID); } } markLinEdgeAsComputedByMe( LinEdge2, aMesh.GetSubMesh( F )); } // orientation bool IsForward = ( CircEdge.Orientation()==TopAbs_FORWARD ); // create nodes and mesh elements on face // find axis of rotation gp_Pnt P2 = gp_Pnt( CNodes[1]->X(), CNodes[1]->Y(), CNodes[1]->Z() ); gp_Vec Vec1(P0,P1); gp_Vec Vec2(P0,P2); gp_Vec Axis = Vec1.Crossed(Vec2); // create elements int i = 1; //cout<<"Angles.Length() = "<<Angles.Length()<<" Points.Length() = "<<Points.Length()<<endl; //cout<<"Nodes1.size() = "<<Nodes1.size()<<" Pnts2d1.Length() = "<<Pnts2d1.Length()<<endl; for(; i<Angles.Length(); i++) { vector< const SMDS_MeshNode* > tmpNodes; tmpNodes.reserve(Nodes1.size()); gp_Trsf aTrsf; gp_Ax1 theAxis(P0,gp_Dir(Axis)); aTrsf.SetRotation( theAxis, Angles.Value(i) ); gp_Trsf2d aTrsf2d; aTrsf2d.SetRotation( PC, Angles.Value(i) ); // create nodes int j = 1; for(; j<=Points.Length(); j++) { double cx,cy,cz; Points.Value(j).Coord( cx, cy, cz ); aTrsf.Transforms( cx, cy, cz ); SMDS_MeshNode* node = myHelper->AddNode( cx, cy, cz ); // find parameters on face Pnts2d1.Value(j).Coord( cx, cy ); aTrsf2d.Transforms( cx, cy ); // set node on face meshDS->SetNodeOnFace( node, faceID, cx, cy ); tmpNodes[j-1] = node; } // create faces tmpNodes[Points.Length()] = CNodes[i]; // quad for(j=0; j<Nodes1.size()-1; j++) { SMDS_MeshFace* MF; if(IsForward) MF = myHelper->AddFace( tmpNodes[j], Nodes1[j], Nodes1[j+1], tmpNodes[j+1] ); else MF = myHelper->AddFace( tmpNodes[j], tmpNodes[j+1], Nodes1[j+1], Nodes1[j] ); if(MF) meshDS->SetMeshElementOnShape(MF, faceID); } // tria SMDS_MeshFace* MF; if(IsForward) MF = myHelper->AddFace( NC, Nodes1[0], tmpNodes[0] ); else MF = myHelper->AddFace( NC, tmpNodes[0], Nodes1[0] ); if(MF) meshDS->SetMeshElementOnShape(MF, faceID); for(j=0; j<Nodes1.size(); j++) { Nodes1[j] = tmpNodes[j]; } } // create last faces // quad for(i=0; i<Nodes1.size()-1; i++) { SMDS_MeshFace* MF; if(IsForward) MF = myHelper->AddFace( Nodes2[i], Nodes1[i], Nodes1[i+1], Nodes2[i+1] ); else MF = myHelper->AddFace( Nodes2[i], Nodes2[i+1], Nodes1[i+1], Nodes1[i] ); if(MF) meshDS->SetMeshElementOnShape(MF, faceID); } // tria SMDS_MeshFace* MF; if(IsForward) MF = myHelper->AddFace( NC, Nodes1[0], Nodes2[0] ); else MF = myHelper->AddFace( NC, Nodes2[0], Nodes1[0] ); if(MF) meshDS->SetMeshElementOnShape(MF, faceID); return true; }
bool NETGENPlugin_NETGEN_2D_ONLY::Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) { netgen::multithread.terminate = 0; //netgen::multithread.task = "Surface meshing"; SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); SMESH_MesherHelper helper(aMesh); helper.SetElementsOnShape( true ); NETGENPlugin_NetgenLibWrapper ngLib; ngLib._isComputeOk = false; netgen::Mesh ngMeshNoLocSize; #if NETGEN_VERSION < 6 netgen::Mesh * ngMeshes[2] = { (netgen::Mesh*) ngLib._ngMesh, & ngMeshNoLocSize }; #else netgen::Mesh * ngMeshes[2] = { (netgen::Mesh*) ngLib._ngMesh.get(), & ngMeshNoLocSize }; #endif netgen::OCCGeometry occgeoComm; // min / max sizes are set as follows: // if ( _hypParameters ) // min and max are defined by the user // else if ( _hypLengthFromEdges ) // min = aMesher.GetDefaultMinSize() // max = average segment len of a FACE // else if ( _hypMaxElementArea ) // min = aMesher.GetDefaultMinSize() // max = f( _hypMaxElementArea ) // else // min = aMesher.GetDefaultMinSize() // max = max segment len of a FACE NETGENPlugin_Mesher aMesher( &aMesh, aShape, /*isVolume=*/false); aMesher.SetParameters( _hypParameters ); // _hypParameters -> netgen::mparam const bool toOptimize = _hypParameters ? _hypParameters->GetOptimize() : true; if ( _hypMaxElementArea ) { netgen::mparam.maxh = sqrt( 2. * _hypMaxElementArea->GetMaxArea() / sqrt(3.0) ); } if ( _hypQuadranglePreference ) netgen::mparam.quad = true; // local size is common for all FACEs in aShape? const bool isCommonLocalSize = ( !_hypLengthFromEdges && !_hypMaxElementArea && netgen::mparam.uselocalh ); const bool isDefaultHyp = ( !_hypLengthFromEdges && !_hypMaxElementArea && !_hypParameters ); if ( isCommonLocalSize ) // compute common local size in ngMeshes[0] { //list< SMESH_subMesh* > meshedSM[4]; --> all sub-shapes are added to occgeoComm aMesher.PrepareOCCgeometry( occgeoComm, aShape, aMesh );//, meshedSM ); // local size set at MESHCONST_ANALYSE step depends on // minh, face_maxh, grading and curvaturesafety; find minh if not set by the user if ( !_hypParameters || netgen::mparam.minh < DBL_MIN ) { if ( !_hypParameters ) netgen::mparam.maxh = occgeoComm.GetBoundingBox().Diam() / 3.; netgen::mparam.minh = aMesher.GetDefaultMinSize( aShape, netgen::mparam.maxh ); } // set local size depending on curvature and NOT closeness of EDGEs netgen::occparam.resthcloseedgeenable = false; //netgen::occparam.resthcloseedgefac = 1.0 + netgen::mparam.grading; occgeoComm.face_maxh = netgen::mparam.maxh; netgen::OCCSetLocalMeshSize( occgeoComm, *ngMeshes[0] ); occgeoComm.emap.Clear(); occgeoComm.vmap.Clear(); // set local size according to size of existing segments const double factor = netgen::occparam.resthcloseedgefac; TopTools_IndexedMapOfShape edgeMap; TopExp::MapShapes( aMesh.GetShapeToMesh(), TopAbs_EDGE, edgeMap ); for ( int iE = 1; iE <= edgeMap.Extent(); ++iE ) { const TopoDS_Shape& edge = edgeMap( iE ); if ( SMESH_Algo::isDegenerated( TopoDS::Edge( edge ))/* || helper.IsSubShape( edge, aShape )*/) continue; SMESHDS_SubMesh* smDS = meshDS->MeshElements( edge ); if ( !smDS ) continue; SMDS_ElemIteratorPtr segIt = smDS->GetElements(); while ( segIt->more() ) { const SMDS_MeshElement* seg = segIt->next(); SMESH_TNodeXYZ n1 = seg->GetNode(0); SMESH_TNodeXYZ n2 = seg->GetNode(1); gp_XYZ p = 0.5 * ( n1 + n2 ); netgen::Point3d pi(p.X(), p.Y(), p.Z()); ngMeshes[0]->RestrictLocalH( pi, factor * ( n1 - n2 ).Modulus() ); } } } netgen::mparam.uselocalh = toOptimize; // restore as it is used at surface optimization // ================== // Loop on all FACEs // ================== vector< const SMDS_MeshNode* > nodeVec; TopExp_Explorer fExp( aShape, TopAbs_FACE ); for ( int iF = 0; fExp.More(); fExp.Next(), ++iF ) { TopoDS_Face F = TopoDS::Face( fExp.Current() /*.Oriented( TopAbs_FORWARD )*/); int faceID = meshDS->ShapeToIndex( F ); SMESH_ComputeErrorPtr& faceErr = aMesh.GetSubMesh( F )->GetComputeError(); _quadraticMesh = helper.IsQuadraticSubMesh( F ); const bool ignoreMediumNodes = _quadraticMesh; // build viscous layers if required if ( F.Orientation() != TopAbs_FORWARD && F.Orientation() != TopAbs_REVERSED ) F.Orientation( TopAbs_FORWARD ); // avoid pb with TopAbs_INTERNAL SMESH_ProxyMesh::Ptr proxyMesh = StdMeshers_ViscousLayers2D::Compute( aMesh, F ); if ( !proxyMesh ) continue; // ------------------------ // get all EDGEs of a FACE // ------------------------ TSideVector wires = StdMeshers_FaceSide::GetFaceWires( F, aMesh, ignoreMediumNodes, faceErr, proxyMesh ); if ( faceErr && !faceErr->IsOK() ) continue; int nbWires = wires.size(); if ( nbWires == 0 ) { faceErr.reset ( new SMESH_ComputeError ( COMPERR_ALGO_FAILED, "Problem in StdMeshers_FaceSide::GetFaceWires()" )); continue; } if ( wires[0]->NbSegments() < 3 ) // ex: a circle with 2 segments { faceErr.reset ( new SMESH_ComputeError ( COMPERR_BAD_INPUT_MESH, SMESH_Comment("Too few segments: ")<<wires[0]->NbSegments()) ); continue; } // ---------------------- // compute maxh of a FACE // ---------------------- if ( !_hypParameters ) { double edgeLength = 0; if (_hypLengthFromEdges ) { // compute edgeLength as an average segment length int nbSegments = 0; for ( int iW = 0; iW < nbWires; ++iW ) { edgeLength += wires[ iW ]->Length(); nbSegments += wires[ iW ]->NbSegments(); } if ( nbSegments ) edgeLength /= nbSegments; netgen::mparam.maxh = edgeLength; } else if ( isDefaultHyp ) { // set edgeLength by a longest segment double maxSeg2 = 0; for ( int iW = 0; iW < nbWires; ++iW ) { const UVPtStructVec& points = wires[ iW ]->GetUVPtStruct(); if ( points.empty() ) return error( COMPERR_BAD_INPUT_MESH ); gp_Pnt pPrev = SMESH_TNodeXYZ( points[0].node ); for ( size_t i = 1; i < points.size(); ++i ) { gp_Pnt p = SMESH_TNodeXYZ( points[i].node ); maxSeg2 = Max( maxSeg2, p.SquareDistance( pPrev )); pPrev = p; } } edgeLength = sqrt( maxSeg2 ) * 1.05; netgen::mparam.maxh = edgeLength; } if ( netgen::mparam.maxh < DBL_MIN ) netgen::mparam.maxh = occgeoComm.GetBoundingBox().Diam(); if ( !isCommonLocalSize ) { netgen::mparam.minh = aMesher.GetDefaultMinSize( F, netgen::mparam.maxh ); } } // prepare occgeom netgen::OCCGeometry occgeom; occgeom.shape = F; occgeom.fmap.Add( F ); occgeom.CalcBoundingBox(); occgeom.facemeshstatus.SetSize(1); occgeom.facemeshstatus = 0; occgeom.face_maxh_modified.SetSize(1); occgeom.face_maxh_modified = 0; occgeom.face_maxh.SetSize(1); occgeom.face_maxh = netgen::mparam.maxh; // ------------------------- // Fill netgen mesh // ------------------------- // MESHCONST_ANALYSE step may lead to a failure, so we make an attempt // w/o MESHCONST_ANALYSE at the second loop int err = 0; enum { LOC_SIZE, NO_LOC_SIZE }; int iLoop = isCommonLocalSize ? 0 : 1; for ( ; iLoop < 2; iLoop++ ) { //bool isMESHCONST_ANALYSE = false; InitComputeError(); netgen::Mesh * ngMesh = ngMeshes[ iLoop ]; ngMesh->DeleteMesh(); if ( iLoop == NO_LOC_SIZE ) { ngMesh->SetGlobalH ( mparam.maxh ); ngMesh->SetMinimalH( mparam.minh ); Box<3> bb = occgeom.GetBoundingBox(); bb.Increase (bb.Diam()/10); ngMesh->SetLocalH (bb.PMin(), bb.PMax(), mparam.grading); } nodeVec.clear(); faceErr = aMesher.AddSegmentsToMesh( *ngMesh, occgeom, wires, helper, nodeVec, /*overrideMinH=*/!_hypParameters); if ( faceErr && !faceErr->IsOK() ) break; //if ( !isCommonLocalSize ) //limitSize( ngMesh, mparam.maxh * 0.8); // ------------------------- // Generate surface mesh // ------------------------- const int startWith = MESHCONST_MESHSURFACE; const int endWith = toOptimize ? MESHCONST_OPTSURFACE : MESHCONST_MESHSURFACE; SMESH_Comment str; try { OCC_CATCH_SIGNALS; #if NETGEN_VERSION >=6 std::shared_ptr<netgen::Mesh> mesh_ptr(ngMesh, [](netgen::Mesh*) {}); err = netgen::OCCGenerateMesh(occgeom, mesh_ptr, netgen::mparam, startWith, endWith); #elif NETGEN_VERSION > 4 err = netgen::OCCGenerateMesh(occgeom, ngMesh, netgen::mparam, startWith, endWith); #else char *optstr = 0; err = netgen::OCCGenerateMesh(occgeom, ngMesh, startWith, endWith, optstr); #endif if ( netgen::multithread.terminate ) return false; if ( err ) str << "Error in netgen::OCCGenerateMesh() at " << netgen::multithread.task; } catch (Standard_Failure& ex) { err = 1; str << "Exception in netgen::OCCGenerateMesh()" << " at " << netgen::multithread.task << ": " << ex.DynamicType()->Name(); if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) str << ": " << ex.GetMessageString(); } catch (...) { err = 1; str << "Exception in netgen::OCCGenerateMesh()" << " at " << netgen::multithread.task; } if ( err ) { if ( aMesher.FixFaceMesh( occgeom, *ngMesh, 1 )) break; if ( iLoop == LOC_SIZE ) { netgen::mparam.minh = netgen::mparam.maxh; netgen::mparam.maxh = 0; for ( int iW = 0; iW < wires.size(); ++iW ) { StdMeshers_FaceSidePtr wire = wires[ iW ]; const vector<UVPtStruct>& uvPtVec = wire->GetUVPtStruct(); for ( size_t iP = 1; iP < uvPtVec.size(); ++iP ) { SMESH_TNodeXYZ p( uvPtVec[ iP ].node ); netgen::Point3d np( p.X(),p.Y(),p.Z()); double segLen = p.Distance( uvPtVec[ iP-1 ].node ); double size = ngMesh->GetH( np ); netgen::mparam.minh = Min( netgen::mparam.minh, size ); netgen::mparam.maxh = Max( netgen::mparam.maxh, segLen ); } } //cerr << "min " << netgen::mparam.minh << " max " << netgen::mparam.maxh << endl; netgen::mparam.minh *= 0.9; netgen::mparam.maxh *= 1.1; continue; } else { faceErr.reset( new SMESH_ComputeError( COMPERR_ALGO_FAILED, str )); } } // ---------------------------------------------------- // Fill the SMESHDS with the generated nodes and faces // ---------------------------------------------------- int nbNodes = ngMesh->GetNP(); int nbFaces = ngMesh->GetNSE(); int nbInputNodes = nodeVec.size()-1; nodeVec.resize( nbNodes+1, 0 ); // add nodes for ( int ngID = nbInputNodes + 1; ngID <= nbNodes; ++ngID ) { const MeshPoint& ngPoint = ngMesh->Point( ngID ); SMDS_MeshNode * node = meshDS->AddNode(ngPoint(0), ngPoint(1), ngPoint(2)); nodeVec[ ngID ] = node; } // create faces int i,j; vector<const SMDS_MeshNode*> nodes; for ( i = 1; i <= nbFaces ; ++i ) { const Element2d& elem = ngMesh->SurfaceElement(i); nodes.resize( elem.GetNP() ); for (j=1; j <= elem.GetNP(); ++j) { int pind = elem.PNum(j); if ( pind < 1 ) break; nodes[ j-1 ] = nodeVec[ pind ]; if ( nodes[ j-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_3DSPACE ) { const PointGeomInfo& pgi = elem.GeomInfoPi(j); meshDS->SetNodeOnFace( nodes[ j-1 ], faceID, pgi.u, pgi.v); } } if ( j > elem.GetNP() ) { SMDS_MeshFace* face = 0; if ( elem.GetType() == TRIG ) face = helper.AddFace(nodes[0],nodes[1],nodes[2]); else face = helper.AddFace(nodes[0],nodes[1],nodes[2],nodes[3]); } } break; } // two attempts } // loop on FACEs return true; }
bool StdMeshers_Hexa_3D::Compute(SMESH_Mesh & aMesh, const TopoDS_Shape & aShape)// throw(SALOME_Exception) { // PAL14921. Enable catching std::bad_alloc and Standard_OutOfMemory outside //Unexpect aCatch(SalomeException); MESSAGE("StdMeshers_Hexa_3D::Compute"); SMESHDS_Mesh * meshDS = aMesh.GetMeshDS(); // 0. - shape and face mesh verification // 0.1 - shape must be a solid (or a shell) with 6 faces vector < SMESH_subMesh * >meshFaces; for (TopExp_Explorer exp(aShape, TopAbs_FACE); exp.More(); exp.Next()) { SMESH_subMesh *aSubMesh = aMesh.GetSubMeshContaining(exp.Current()); ASSERT(aSubMesh); meshFaces.push_back(aSubMesh); } if (meshFaces.size() != 6) { //return error(COMPERR_BAD_SHAPE, TComm(meshFaces.size())<<" instead of 6 faces in a block"); static StdMeshers_CompositeHexa_3D compositeHexa(-10, 0, aMesh.GetGen()); if ( !compositeHexa.Compute( aMesh, aShape )) return error( compositeHexa.GetComputeError() ); return true; } // 0.2 - is each face meshed with Quadrangle_2D? (so, with a wire of 4 edges) // tool for working with quadratic elements SMESH_MesherHelper aTool (aMesh); _quadraticMesh = aTool.IsQuadraticSubMesh(aShape); // cube structure typedef struct cubeStruct { TopoDS_Vertex V000; TopoDS_Vertex V001; TopoDS_Vertex V010; TopoDS_Vertex V011; TopoDS_Vertex V100; TopoDS_Vertex V101; TopoDS_Vertex V110; TopoDS_Vertex V111; faceQuadStruct* quad_X0; faceQuadStruct* quad_X1; faceQuadStruct* quad_Y0; faceQuadStruct* quad_Y1; faceQuadStruct* quad_Z0; faceQuadStruct* quad_Z1; Point3DStruct* np; // normalised 3D coordinates } CubeStruct; CubeStruct aCube; // bounding faces FaceQuadStruct* aQuads[6]; for (int i = 0; i < 6; i++) aQuads[i] = 0; for (int i = 0; i < 6; i++) { TopoDS_Shape aFace = meshFaces[i]->GetSubShape(); SMESH_Algo *algo = _gen->GetAlgo(aMesh, aFace); string algoName = algo->GetName(); bool isAllQuad = false; if (algoName == "Quadrangle_2D") { SMESHDS_SubMesh * sm = meshDS->MeshElements( aFace ); if ( sm ) { isAllQuad = true; SMDS_ElemIteratorPtr eIt = sm->GetElements(); while ( isAllQuad && eIt->more() ) { const SMDS_MeshElement* elem = eIt->next(); isAllQuad = ( elem->NbNodes()==4 ||(_quadraticMesh && elem->NbNodes()==8) ); } } } if ( ! isAllQuad ) { SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape); return ClearAndReturn( aQuads, error(err)); } StdMeshers_Quadrangle_2D *quadAlgo = dynamic_cast < StdMeshers_Quadrangle_2D * >(algo); ASSERT(quadAlgo); try { aQuads[i] = quadAlgo->CheckAnd2Dcompute(aMesh, aFace, _quadraticMesh); if(!aQuads[i]) { return error( quadAlgo->GetComputeError()); } } catch(SALOME_Exception & S_ex) { return ClearAndReturn( aQuads, error(COMPERR_SLM_EXCEPTION,TComm(S_ex.what()) << " Raised by StdMeshers_Quadrangle_2D " " on face #" << meshDS->ShapeToIndex( aFace ))); } // 0.2.1 - number of points on the opposite edges must be the same if (aQuads[i]->side[0]->NbPoints() != aQuads[i]->side[2]->NbPoints() || aQuads[i]->side[1]->NbPoints() != aQuads[i]->side[3]->NbPoints() /*aQuads[i]->side[0]->NbEdges() != 1 || aQuads[i]->side[1]->NbEdges() != 1 || aQuads[i]->side[2]->NbEdges() != 1 || aQuads[i]->side[3]->NbEdges() != 1*/) { MESSAGE("different number of points on the opposite edges of face " << i); // Try to go into penta algorithm 'cause it has been improved. SMESH_ComputeErrorPtr err = ComputePentahedralMesh(aMesh, aShape); return ClearAndReturn( aQuads, error(err)); } } // 1. - identify faces and vertices of the "cube" // 1.1 - ancestor maps vertex->edges in the cube // TopTools_IndexedDataMapOfShapeListOfShape MS; // TopExp::MapShapesAndAncestors(aShape, TopAbs_VERTEX, TopAbs_EDGE, MS); // 1.2 - first face is choosen as face Y=0 of the unit cube const TopoDS_Shape & aFace = meshFaces[0]->GetSubShape(); //const TopoDS_Face & F = TopoDS::Face(aFace); // 1.3 - identify the 4 vertices of the face Y=0: V000, V100, V101, V001 aCube.V000 = aQuads[0]->side[0]->FirstVertex(); // will be (0,0,0) on the unit cube aCube.V100 = aQuads[0]->side[0]->LastVertex(); // will be (1,0,0) on the unit cube aCube.V001 = aQuads[0]->side[2]->FirstVertex(); // will be (0,0,1) on the unit cube aCube.V101 = aQuads[0]->side[2]->LastVertex(); // will be (1,0,1) on the unit cube TopTools_IndexedMapOfShape MV0; TopExp::MapShapes(aFace, TopAbs_VERTEX, MV0); aCube.V010 = OppositeVertex( aCube.V000, MV0, aQuads); aCube.V110 = OppositeVertex( aCube.V100, MV0, aQuads); aCube.V011 = OppositeVertex( aCube.V001, MV0, aQuads); aCube.V111 = OppositeVertex( aCube.V101, MV0, aQuads); // 1.6 - find remaining faces given 4 vertices int _indY0 = 0; int _indY1 = GetFaceIndex(aMesh, aShape, meshFaces, aCube.V010, aCube.V011, aCube.V110, aCube.V111); int _indZ0 = GetFaceIndex(aMesh, aShape, meshFaces, aCube.V000, aCube.V010, aCube.V100, aCube.V110); int _indZ1 = GetFaceIndex(aMesh, aShape, meshFaces, aCube.V001, aCube.V011, aCube.V101, aCube.V111); int _indX0 = GetFaceIndex(aMesh, aShape, meshFaces, aCube.V000, aCube.V001, aCube.V010, aCube.V011); int _indX1 = GetFaceIndex(aMesh, aShape, meshFaces, aCube.V100, aCube.V101, aCube.V110, aCube.V111); // IPAL21120: SIGSEGV on Meshing attached Compound with Automatic Hexadralization if ( _indY1 < 1 || _indZ0 < 1 || _indZ1 < 1 || _indX0 < 1 || _indX1 < 1 ) return error(COMPERR_BAD_SHAPE); aCube.quad_Y0 = aQuads[_indY0]; aCube.quad_Y1 = aQuads[_indY1]; aCube.quad_Z0 = aQuads[_indZ0]; aCube.quad_Z1 = aQuads[_indZ1]; aCube.quad_X0 = aQuads[_indX0]; aCube.quad_X1 = aQuads[_indX1]; // 1.7 - get convertion coefs from face 2D normalized to 3D normalized Conv2DStruct cx0; // for face X=0 Conv2DStruct cx1; // for face X=1 Conv2DStruct cy0; Conv2DStruct cy1; Conv2DStruct cz0; Conv2DStruct cz1; GetConv2DCoefs(*aCube.quad_X0, meshFaces[_indX0]->GetSubShape(), aCube.V000, aCube.V010, aCube.V011, aCube.V001, cx0); GetConv2DCoefs(*aCube.quad_X1, meshFaces[_indX1]->GetSubShape(), aCube.V100, aCube.V110, aCube.V111, aCube.V101, cx1); GetConv2DCoefs(*aCube.quad_Y0, meshFaces[_indY0]->GetSubShape(), aCube.V000, aCube.V100, aCube.V101, aCube.V001, cy0); GetConv2DCoefs(*aCube.quad_Y1, meshFaces[_indY1]->GetSubShape(), aCube.V010, aCube.V110, aCube.V111, aCube.V011, cy1); GetConv2DCoefs(*aCube.quad_Z0, meshFaces[_indZ0]->GetSubShape(), aCube.V000, aCube.V100, aCube.V110, aCube.V010, cz0); GetConv2DCoefs(*aCube.quad_Z1, meshFaces[_indZ1]->GetSubShape(), aCube.V001, aCube.V101, aCube.V111, aCube.V011, cz1); // 1.8 - create a 3D structure for normalized values int nbx = aCube.quad_Z0->side[0]->NbPoints(); if (cz0.a1 == 0.) nbx = aCube.quad_Z0->side[1]->NbPoints(); int nby = aCube.quad_X0->side[0]->NbPoints(); if (cx0.a1 == 0.) nby = aCube.quad_X0->side[1]->NbPoints(); int nbz = aCube.quad_Y0->side[0]->NbPoints(); if (cy0.a1 != 0.) nbz = aCube.quad_Y0->side[1]->NbPoints(); int i1, j1, nbxyz = nbx * nby * nbz; Point3DStruct *np = new Point3DStruct[nbxyz]; // 1.9 - store node indexes of faces { const TopoDS_Face & F = TopoDS::Face(meshFaces[_indX0]->GetSubShape()); faceQuadStruct *quad = aCube.quad_X0; int i = 0; // j = x/face , k = y/face int nbdown = quad->side[0]->NbPoints(); int nbright = quad->side[1]->NbPoints(); SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); while(itf->more()) { const SMDS_MeshNode * node = itf->next(); if(aTool.IsMedium(node)) continue; if ( !findIJ( node, quad, i1, j1 )) return ClearAndReturn( aQuads, false ); int ij1 = j1 * nbdown + i1; quad->uv_grid[ij1].node = node; } for (int i1 = 0; i1 < nbdown; i1++) for (int j1 = 0; j1 < nbright; j1++) { int ij1 = j1 * nbdown + i1; int j = cx0.ia * i1 + cx0.ib * j1 + cx0.ic; // j = x/face int k = cx0.ja * i1 + cx0.jb * j1 + cx0.jc; // k = y/face int ijk = k * nbx * nby + j * nbx + i; //MESSAGE(" "<<ij1<<" "<<i<<" "<<j<<" "<<ijk); np[ijk].node = quad->uv_grid[ij1].node; //SCRUTE(np[ijk].nodeId); } } { const TopoDS_Face & F = TopoDS::Face(meshFaces[_indX1]->GetSubShape()); SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); faceQuadStruct *quad = aCube.quad_X1; int i = nbx - 1; // j = x/face , k = y/face int nbdown = quad->side[0]->NbPoints(); int nbright = quad->side[1]->NbPoints(); while(itf->more()) { const SMDS_MeshNode * node = itf->next(); if(aTool.IsMedium(node)) continue; if ( !findIJ( node, quad, i1, j1 )) return ClearAndReturn( aQuads, false ); int ij1 = j1 * nbdown + i1; quad->uv_grid[ij1].node = node; } for (int i1 = 0; i1 < nbdown; i1++) for (int j1 = 0; j1 < nbright; j1++) { int ij1 = j1 * nbdown + i1; int j = cx1.ia * i1 + cx1.ib * j1 + cx1.ic; // j = x/face int k = cx1.ja * i1 + cx1.jb * j1 + cx1.jc; // k = y/face int ijk = k * nbx * nby + j * nbx + i; //MESSAGE(" "<<ij1<<" "<<i<<" "<<j<<" "<<ijk); np[ijk].node = quad->uv_grid[ij1].node; //SCRUTE(np[ijk].nodeId); } } { const TopoDS_Face & F = TopoDS::Face(meshFaces[_indY0]->GetSubShape()); SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); faceQuadStruct *quad = aCube.quad_Y0; int j = 0; // i = x/face , k = y/face int nbdown = quad->side[0]->NbPoints(); int nbright = quad->side[1]->NbPoints(); while(itf->more()) { const SMDS_MeshNode * node = itf->next(); if(aTool.IsMedium(node)) continue; if ( !findIJ( node, quad, i1, j1 )) return ClearAndReturn( aQuads, false ); int ij1 = j1 * nbdown + i1; quad->uv_grid[ij1].node = node; } for (int i1 = 0; i1 < nbdown; i1++) for (int j1 = 0; j1 < nbright; j1++) { int ij1 = j1 * nbdown + i1; int i = cy0.ia * i1 + cy0.ib * j1 + cy0.ic; // i = x/face int k = cy0.ja * i1 + cy0.jb * j1 + cy0.jc; // k = y/face int ijk = k * nbx * nby + j * nbx + i; //MESSAGE(" "<<ij1<<" "<<i<<" "<<j<<" "<<ijk); np[ijk].node = quad->uv_grid[ij1].node; //SCRUTE(np[ijk].nodeId); } } { const TopoDS_Face & F = TopoDS::Face(meshFaces[_indY1]->GetSubShape()); SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); faceQuadStruct *quad = aCube.quad_Y1; int j = nby - 1; // i = x/face , k = y/face int nbdown = quad->side[0]->NbPoints(); int nbright = quad->side[1]->NbPoints(); while(itf->more()) { const SMDS_MeshNode * node = itf->next(); if(aTool.IsMedium(node)) continue; if ( !findIJ( node, quad, i1, j1 )) return ClearAndReturn( aQuads, false ); int ij1 = j1 * nbdown + i1; quad->uv_grid[ij1].node = node; } for (int i1 = 0; i1 < nbdown; i1++) for (int j1 = 0; j1 < nbright; j1++) { int ij1 = j1 * nbdown + i1; int i = cy1.ia * i1 + cy1.ib * j1 + cy1.ic; // i = x/face int k = cy1.ja * i1 + cy1.jb * j1 + cy1.jc; // k = y/face int ijk = k * nbx * nby + j * nbx + i; //MESSAGE(" "<<ij1<<" "<<i<<" "<<j<<" "<<ijk); np[ijk].node = quad->uv_grid[ij1].node; //SCRUTE(np[ijk].nodeId); } } { const TopoDS_Face & F = TopoDS::Face(meshFaces[_indZ0]->GetSubShape()); SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); faceQuadStruct *quad = aCube.quad_Z0; int k = 0; // i = x/face , j = y/face int nbdown = quad->side[0]->NbPoints(); int nbright = quad->side[1]->NbPoints(); while(itf->more()) { const SMDS_MeshNode * node = itf->next(); if(aTool.IsMedium(node)) continue; if ( !findIJ( node, quad, i1, j1 )) return ClearAndReturn( aQuads, false ); int ij1 = j1 * nbdown + i1; quad->uv_grid[ij1].node = node; } for (int i1 = 0; i1 < nbdown; i1++) for (int j1 = 0; j1 < nbright; j1++) { int ij1 = j1 * nbdown + i1; int i = cz0.ia * i1 + cz0.ib * j1 + cz0.ic; // i = x/face int j = cz0.ja * i1 + cz0.jb * j1 + cz0.jc; // j = y/face int ijk = k * nbx * nby + j * nbx + i; //MESSAGE(" "<<ij1<<" "<<i<<" "<<j<<" "<<ijk); np[ijk].node = quad->uv_grid[ij1].node; //SCRUTE(np[ijk].nodeId); } } { const TopoDS_Face & F = TopoDS::Face(meshFaces[_indZ1]->GetSubShape()); SMDS_NodeIteratorPtr itf= aMesh.GetSubMesh(F)->GetSubMeshDS()->GetNodes(); faceQuadStruct *quad = aCube.quad_Z1; int k = nbz - 1; // i = x/face , j = y/face int nbdown = quad->side[0]->NbPoints(); int nbright = quad->side[1]->NbPoints(); while(itf->more()) { const SMDS_MeshNode * node = itf->next(); if(aTool.IsMedium(node)) continue; if ( !findIJ( node, quad, i1, j1 )) return ClearAndReturn( aQuads, false ); int ij1 = j1 * nbdown + i1; quad->uv_grid[ij1].node = node; } for (int i1 = 0; i1 < nbdown; i1++) for (int j1 = 0; j1 < nbright; j1++) { int ij1 = j1 * nbdown + i1; int i = cz1.ia * i1 + cz1.ib * j1 + cz1.ic; // i = x/face int j = cz1.ja * i1 + cz1.jb * j1 + cz1.jc; // j = y/face int ijk = k * nbx * nby + j * nbx + i; //MESSAGE(" "<<ij1<<" "<<i<<" "<<j<<" "<<ijk); np[ijk].node = quad->uv_grid[ij1].node; //SCRUTE(np[ijk].nodeId); } } // 2.0 - for each node of the cube: // - get the 8 points 3D = 8 vertices of the cube // - get the 12 points 3D on the 12 edges of the cube // - get the 6 points 3D on the 6 faces with their ID // - compute the point 3D // - store the point 3D in SMESHDS, store its ID in 3D structure int shapeID = meshDS->ShapeToIndex( aShape ); Pt3 p000, p001, p010, p011, p100, p101, p110, p111; Pt3 px00, px01, px10, px11; Pt3 p0y0, p0y1, p1y0, p1y1; Pt3 p00z, p01z, p10z, p11z; Pt3 pxy0, pxy1, px0z, px1z, p0yz, p1yz; GetPoint(p000, 0, 0, 0, nbx, nby, nbz, np, meshDS); GetPoint(p001, 0, 0, nbz - 1, nbx, nby, nbz, np, meshDS); GetPoint(p010, 0, nby - 1, 0, nbx, nby, nbz, np, meshDS); GetPoint(p011, 0, nby - 1, nbz - 1, nbx, nby, nbz, np, meshDS); GetPoint(p100, nbx - 1, 0, 0, nbx, nby, nbz, np, meshDS); GetPoint(p101, nbx - 1, 0, nbz - 1, nbx, nby, nbz, np, meshDS); GetPoint(p110, nbx - 1, nby - 1, 0, nbx, nby, nbz, np, meshDS); GetPoint(p111, nbx - 1, nby - 1, nbz - 1, nbx, nby, nbz, np, meshDS); for (int i = 1; i < nbx - 1; i++) { for (int j = 1; j < nby - 1; j++) { for (int k = 1; k < nbz - 1; k++) { // *** seulement maillage regulier // 12 points on edges GetPoint(px00, i, 0, 0, nbx, nby, nbz, np, meshDS); GetPoint(px01, i, 0, nbz - 1, nbx, nby, nbz, np, meshDS); GetPoint(px10, i, nby - 1, 0, nbx, nby, nbz, np, meshDS); GetPoint(px11, i, nby - 1, nbz - 1, nbx, nby, nbz, np, meshDS); GetPoint(p0y0, 0, j, 0, nbx, nby, nbz, np, meshDS); GetPoint(p0y1, 0, j, nbz - 1, nbx, nby, nbz, np, meshDS); GetPoint(p1y0, nbx - 1, j, 0, nbx, nby, nbz, np, meshDS); GetPoint(p1y1, nbx - 1, j, nbz - 1, nbx, nby, nbz, np, meshDS); GetPoint(p00z, 0, 0, k, nbx, nby, nbz, np, meshDS); GetPoint(p01z, 0, nby - 1, k, nbx, nby, nbz, np, meshDS); GetPoint(p10z, nbx - 1, 0, k, nbx, nby, nbz, np, meshDS); GetPoint(p11z, nbx - 1, nby - 1, k, nbx, nby, nbz, np, meshDS); // 12 points on faces GetPoint(pxy0, i, j, 0, nbx, nby, nbz, np, meshDS); GetPoint(pxy1, i, j, nbz - 1, nbx, nby, nbz, np, meshDS); GetPoint(px0z, i, 0, k, nbx, nby, nbz, np, meshDS); GetPoint(px1z, i, nby - 1, k, nbx, nby, nbz, np, meshDS); GetPoint(p0yz, 0, j, k, nbx, nby, nbz, np, meshDS); GetPoint(p1yz, nbx - 1, j, k, nbx, nby, nbz, np, meshDS); int ijk = k * nbx * nby + j * nbx + i; double x = double (i) / double (nbx - 1); // *** seulement double y = double (j) / double (nby - 1); // *** maillage double z = double (k) / double (nbz - 1); // *** regulier Pt3 X; for (int i = 0; i < 3; i++) { X[i] = (1 - x) * p0yz[i] + x * p1yz[i] + (1 - y) * px0z[i] + y * px1z[i] + (1 - z) * pxy0[i] + z * pxy1[i] - (1 - x) * ((1 - y) * p00z[i] + y * p01z[i]) - x * ((1 - y) * p10z[i] + y * p11z[i]) - (1 - y) * ((1 - z) * px00[i] + z * px01[i]) - y * ((1 - z) * px10[i] + z * px11[i]) - (1 - z) * ((1 - x) * p0y0[i] + x * p1y0[i]) - z * ((1 - x) * p0y1[i] + x * p1y1[i]) + (1 - x) * ((1 - y) * ((1 - z) * p000[i] + z * p001[i]) + y * ((1 - z) * p010[i] + z * p011[i])) + x * ((1 - y) * ((1 - z) * p100[i] + z * p101[i]) + y * ((1 - z) * p110[i] + z * p111[i])); } SMDS_MeshNode * node = meshDS->AddNode(X[0], X[1], X[2]); np[ijk].node = node; meshDS->SetNodeInVolume(node, shapeID); } } } // find orientation of furute volumes according to MED convention vector< bool > forward( nbx * nby ); SMDS_VolumeTool vTool; for (int i = 0; i < nbx - 1; i++) { for (int j = 0; j < nby - 1; j++) { int n1 = j * nbx + i; int n2 = j * nbx + i + 1; int n3 = (j + 1) * nbx + i + 1; int n4 = (j + 1) * nbx + i; int n5 = nbx * nby + j * nbx + i; int n6 = nbx * nby + j * nbx + i + 1; int n7 = nbx * nby + (j + 1) * nbx + i + 1; int n8 = nbx * nby + (j + 1) * nbx + i; SMDS_VolumeOfNodes tmpVol (np[n1].node,np[n2].node,np[n3].node,np[n4].node, np[n5].node,np[n6].node,np[n7].node,np[n8].node); vTool.Set( &tmpVol ); forward[ n1 ] = vTool.IsForward(); } } //2.1 - for each node of the cube (less 3 *1 Faces): // - store hexahedron in SMESHDS MESSAGE("Storing hexahedron into the DS"); for (int i = 0; i < nbx - 1; i++) { for (int j = 0; j < nby - 1; j++) { bool isForw = forward.at( j * nbx + i ); for (int k = 0; k < nbz - 1; k++) { int n1 = k * nbx * nby + j * nbx + i; int n2 = k * nbx * nby + j * nbx + i + 1; int n3 = k * nbx * nby + (j + 1) * nbx + i + 1; int n4 = k * nbx * nby + (j + 1) * nbx + i; int n5 = (k + 1) * nbx * nby + j * nbx + i; int n6 = (k + 1) * nbx * nby + j * nbx + i + 1; int n7 = (k + 1) * nbx * nby + (j + 1) * nbx + i + 1; int n8 = (k + 1) * nbx * nby + (j + 1) * nbx + i; SMDS_MeshVolume * elt; if ( isForw ) { elt = aTool.AddVolume(np[n1].node, np[n2].node, np[n3].node, np[n4].node, np[n5].node, np[n6].node, np[n7].node, np[n8].node); } else { elt = aTool.AddVolume(np[n1].node, np[n4].node, np[n3].node, np[n2].node, np[n5].node, np[n8].node, np[n7].node, np[n6].node); } meshDS->SetMeshElementOnShape(elt, shapeID); } } } if ( np ) delete [] np; return ClearAndReturn( aQuads, true ); }