1 // File: SMESH_MesherHelper.cxx
2 // Created: 15.02.06 15:22:41
4 // Copyright: Open CASCADE 2006
7 #include "SMESH_MesherHelper.hxx"
9 #include "SMDS_FacePosition.hxx"
10 #include "SMDS_EdgePosition.hxx".cxx
11 #include "SMESH_MeshEditor.hxx"
13 #include <BRepAdaptor_Surface.hxx>
14 #include <BRepTools.hxx>
15 #include <BRep_Tool.hxx>
16 #include <Geom2d_Curve.hxx>
17 #include <Geom_Curve.hxx>
18 #include <Geom_Surface.hxx>
19 #include <TopExp_Explorer.hxx>
20 #include <TopTools_MapOfShape.hxx>
21 #include <gp_Pnt2d.hxx>
22 #include <ShapeAnalysis.hxx>
24 //=======================================================================
25 //function : CheckShape
27 //=======================================================================
29 bool SMESH_MesherHelper::IsQuadraticSubMesh(const TopoDS_Shape& aSh)
31 SMESHDS_Mesh* meshDS = GetMesh()->GetMeshDS();
32 myShapeID = meshDS->ShapeToIndex(aSh);
33 // we can create quadratic elements only if all elements
34 // created on subshapes of given shape are quadratic
35 // also we have to fill myNLinkNodeMap
36 myCreateQuadratic = true;
37 mySeamShapeIds.clear();
38 TopAbs_ShapeEnum subType( aSh.ShapeType()==TopAbs_FACE ? TopAbs_EDGE : TopAbs_FACE );
39 SMDSAbs_ElementType elemType( subType==TopAbs_FACE ? SMDSAbs_Face : SMDSAbs_Edge );
41 TopExp_Explorer exp( aSh, subType );
42 for (; exp.More() && myCreateQuadratic; exp.Next()) {
43 if ( SMESHDS_SubMesh * subMesh = meshDS->MeshElements( exp.Current() )) {
44 if ( SMDS_ElemIteratorPtr it = subMesh->GetElements() ) {
46 const SMDS_MeshElement* e = it->next();
47 if ( e->GetType() != elemType || !e->IsQuadratic() ) {
48 myCreateQuadratic = false;
53 switch ( e->NbNodes() ) {
55 AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(2)); break;
57 AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(3));
58 AddNLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(4));
59 AddNLinkNode(e->GetNode(2),e->GetNode(0),e->GetNode(5)); break;
61 AddNLinkNode(e->GetNode(0),e->GetNode(1),e->GetNode(4));
62 AddNLinkNode(e->GetNode(1),e->GetNode(2),e->GetNode(5));
63 AddNLinkNode(e->GetNode(2),e->GetNode(3),e->GetNode(6));
64 AddNLinkNode(e->GetNode(3),e->GetNode(0),e->GetNode(7));
67 myCreateQuadratic = false;
76 if(!myCreateQuadratic) {
77 myNLinkNodeMap.clear();
80 // treatment of periodic faces
81 if ( aSh.ShapeType() == TopAbs_FACE ) {
82 const TopoDS_Face& face = TopoDS::Face( aSh );
83 BRepAdaptor_Surface surface( face );
84 if ( surface.IsUPeriodic() || surface.IsVPeriodic() ) {
85 // look for a seam edge
86 for ( exp.Init( face, TopAbs_EDGE ); exp.More(); exp.Next()) {
87 const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
88 if ( BRep_Tool::IsClosed( edge, face )) {
89 // initialize myPar1, myPar2 and myParIndex
90 if ( mySeamShapeIds.empty() ) {
92 BRep_Tool::UVPoints( edge, face, uv1, uv2 );
93 if ( Abs( uv1.Coord(1) - uv2.Coord(1) ) < Abs( uv1.Coord(2) - uv2.Coord(2) ))
95 myParIndex = 1; // U periodic
96 myPar1 = surface.FirstUParameter();
97 myPar2 = surface.LastUParameter();
100 myParIndex = 2; // V periodic
101 myPar1 = surface.FirstVParameter();
102 myPar2 = surface.LastVParameter();
105 // store shapes indices
106 mySeamShapeIds.insert( meshDS->ShapeToIndex( exp.Current() ));
107 for ( TopExp_Explorer v( exp.Current(), TopAbs_VERTEX ); v.More(); v.Next() )
108 mySeamShapeIds.insert( meshDS->ShapeToIndex( v.Current() ));
114 return myCreateQuadratic;
118 //=======================================================================
119 //function : IsMedium
121 //=======================================================================
123 bool SMESH_MesherHelper::IsMedium(const SMDS_MeshNode* node,
124 const SMDSAbs_ElementType typeToCheck)
126 return SMESH_MeshEditor::IsMedium( node, typeToCheck );
129 //=======================================================================
130 //function : AddNLinkNode
132 //=======================================================================
134 * Auxilary function for filling myNLinkNodeMap
136 void SMESH_MesherHelper::AddNLinkNode(const SMDS_MeshNode* n1,
137 const SMDS_MeshNode* n2,
138 const SMDS_MeshNode* n12)
140 NLink link( n1, n2 );
141 if ( n1 > n2 ) link = NLink( n2, n1 );
142 // add new record to map
143 myNLinkNodeMap.insert( make_pair(link,n12));
146 //=======================================================================
148 * \brief Select UV on either of 2 pcurves of a seam edge, closest to the given UV
149 * \param uv1 - UV on the seam
150 * \param uv2 - UV within a face
151 * \retval gp_Pnt2d - selected UV
153 //=======================================================================
155 gp_Pnt2d SMESH_MesherHelper::GetUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const
157 double p1 = uv1.Coord( myParIndex );
158 double p2 = uv2.Coord( myParIndex );
159 double p3 = ( Abs( p1 - myPar1 ) < Abs( p1 - myPar2 )) ? myPar2 : myPar1;
160 if ( Abs( p2 - p1 ) > Abs( p2 - p3 ))
162 gp_Pnt2d result = uv1;
163 result.SetCoord( myParIndex, p1 );
167 //=======================================================================
169 * \brief Return node UV on face
170 * \param F - the face
171 * \param n - the node
172 * \param n2 - a medium node will be placed between n and n2
173 * \retval gp_XY - resulting UV
175 * Auxilary function called form GetMediumNode()
177 //=======================================================================
179 gp_XY SMESH_MesherHelper::GetNodeUV(const TopoDS_Face& F,
180 const SMDS_MeshNode* n,
181 const SMDS_MeshNode* n2)
184 const SMDS_PositionPtr Pos = n->GetPosition();
185 if(Pos->GetTypeOfPosition()==SMDS_TOP_FACE) {
186 // node has position on face
187 const SMDS_FacePosition* fpos =
188 static_cast<const SMDS_FacePosition*>(n->GetPosition().get());
189 uv = gp_Pnt2d(fpos->GetUParameter(),fpos->GetVParameter());
191 else if(Pos->GetTypeOfPosition()==SMDS_TOP_EDGE) {
192 // node has position on edge => it is needed to find
193 // corresponding edge from face, get pcurve for this
194 // edge and recieve value from this pcurve
195 const SMDS_EdgePosition* epos =
196 static_cast<const SMDS_EdgePosition*>(n->GetPosition().get());
197 SMESHDS_Mesh* meshDS = GetMesh()->GetMeshDS();
198 int edgeID = Pos->GetShapeId();
199 TopoDS_Edge E = TopoDS::Edge(meshDS->IndexToShape(edgeID));
202 Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(E, F, f, l);
203 uv = C2d->Value( epos->GetUParameter() );
204 // for a node on a seam edge select one of UVs on 2 pcurves
205 if ( n2 && mySeamShapeIds.find( edgeID ) != mySeamShapeIds.end() )
206 uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0 ));
208 else if(Pos->GetTypeOfPosition()==SMDS_TOP_VERTEX) {
209 SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
210 int vertexID = n->GetPosition()->GetShapeId();
211 const TopoDS_Vertex& V = TopoDS::Vertex(meshDS->IndexToShape(vertexID));
212 uv = BRep_Tool::Parameters( V, F );
213 if ( n2 && mySeamShapeIds.find( vertexID ) != mySeamShapeIds.end() )
214 uv = GetUVOnSeam( uv, GetNodeUV( F, n2, 0 ));
219 //=======================================================================
221 * \brief Return node U on edge
222 * \param E - the Edge
223 * \param n - the node
224 * \retval double - resulting U
226 * Auxilary function called form GetMediumNode()
228 //=======================================================================
230 double SMESH_MesherHelper::GetNodeU(const TopoDS_Edge& E,
231 const SMDS_MeshNode* n)
234 const SMDS_PositionPtr Pos = n->GetPosition();
235 if(Pos->GetTypeOfPosition()==SMDS_TOP_EDGE) {
236 const SMDS_EdgePosition* epos =
237 static_cast<const SMDS_EdgePosition*>(n->GetPosition().get());
238 param = epos->GetUParameter();
240 else if(Pos->GetTypeOfPosition()==SMDS_TOP_VERTEX) {
241 SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
242 int vertexID = n->GetPosition()->GetShapeId();
243 const TopoDS_Vertex& V = TopoDS::Vertex(meshDS->IndexToShape(vertexID));
244 param = BRep_Tool::Parameter( V, E );
249 //=======================================================================
250 //function : GetMediumNode
252 //=======================================================================
254 * Special function for search or creation medium node
256 const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1,
257 const SMDS_MeshNode* n2,
262 NLink link(( n1 < n2 ? n1 : n2 ), ( n1 < n2 ? n2 : n1 ));
263 ItNLinkNode itLN = myNLinkNodeMap.find( link );
264 if ( itLN != myNLinkNodeMap.end() ) {
265 return (*itLN).second;
268 // create medium node
270 SMESHDS_Mesh* meshDS = GetMesh()->GetMeshDS();
271 int faceID = -1, edgeID = -1;
272 const SMDS_PositionPtr Pos1 = n1->GetPosition();
273 const SMDS_PositionPtr Pos2 = n2->GetPosition();
275 if( myShape.IsNull() )
277 if( Pos1->GetTypeOfPosition()==SMDS_TOP_FACE ) {
278 faceID = Pos1->GetShapeId();
280 else if( Pos2->GetTypeOfPosition()==SMDS_TOP_FACE ) {
281 faceID = Pos2->GetShapeId();
284 if( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE ) {
285 edgeID = Pos1->GetShapeId();
287 if( Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE ) {
288 edgeID = Pos2->GetShapeId();
293 // we try to create medium node using UV parameters of
294 // nodes, else - medium between corresponding 3d points
295 if(faceID>-1 || myShape.ShapeType() == TopAbs_FACE) {
296 // obtaining a face and 2d points for nodes
298 if( myShape.IsNull() )
299 F = TopoDS::Face(meshDS->IndexToShape(faceID));
301 F = TopoDS::Face(myShape);
303 gp_XY p1 = GetNodeUV(F,n1,n2);
304 gp_XY p2 = GetNodeUV(F,n2,n1);
306 //checking if surface is periodic
307 Handle(Geom_Surface) S = BRep_Tool::Surface(F);
308 Standard_Real UF,UL,VF,VL;
309 S->Bounds(UF,UL,VF,VL);
312 Standard_Boolean isUPeriodic = S->IsUPeriodic();
314 Standard_Real UPeriod = S->UPeriod();
315 Standard_Real p2x = p2.X()+ShapeAnalysis::AdjustByPeriod(p2.X(),p1.X(),UPeriod);
316 Standard_Real pmid = (p1.X()+p2x)/2.;
317 u = pmid+ShapeAnalysis::AdjustToPeriod(pmid,UF,UL);
320 u= (p1.X()+p2.X())/2.;
322 Standard_Boolean isVPeriodic = S->IsVPeriodic();
324 Standard_Real VPeriod = S->VPeriod();
325 Standard_Real p2y = p2.Y()+ShapeAnalysis::AdjustByPeriod(p2.Y(),p1.Y(),VPeriod);
326 Standard_Real pmid = (p1.Y()+p2y)/2.;
327 v = pmid+ShapeAnalysis::AdjustToPeriod(pmid,VF,VL);
330 v = (p1.Y()+p2.Y())/2.;
332 gp_Pnt P = S->Value(u, v);
333 n12 = meshDS->AddNode(P.X(), P.Y(), P.Z());
334 meshDS->SetNodeOnFace(n12, faceID, u, v);
335 myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12));
338 if (edgeID>-1 || myShape.ShapeType() == TopAbs_EDGE) {
341 if( myShape.IsNull() )
342 E = TopoDS::Edge(meshDS->IndexToShape(edgeID));
344 E = TopoDS::Edge(myShape);
346 double p1 = GetNodeU(E,n1);
347 double p2 = GetNodeU(E,n2);
350 Handle(Geom_Curve) C = BRep_Tool::Curve(E, f, l);
353 Standard_Boolean isPeriodic = C->IsPeriodic();
356 Standard_Real Period = C->Period();
357 Standard_Real p = p2+ShapeAnalysis::AdjustByPeriod(p2,p1,Period);
358 Standard_Real pmid = (p1+p)/2.;
359 u = pmid+ShapeAnalysis::AdjustToPeriod(pmid,C->FirstParameter(),C->LastParameter());
364 gp_Pnt P = C->Value( u );
365 n12 = meshDS->AddNode(P.X(), P.Y(), P.Z());
366 meshDS->SetNodeOnEdge(n12, edgeID, u);
367 myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12));
373 double x = ( n1->X() + n2->X() )/2.;
374 double y = ( n1->Y() + n2->Y() )/2.;
375 double z = ( n1->Z() + n2->Z() )/2.;
376 n12 = meshDS->AddNode(x,y,z);
378 meshDS->SetNodeOnEdge(n12, edgeID);
380 meshDS->SetNodeOnFace(n12, faceID);
382 meshDS->SetNodeInVolume(n12, myShapeID);
383 myNLinkNodeMap.insert(NLinkNodeMap::value_type(link,n12));
388 //=======================================================================
389 //function : AddQuadraticEdge
391 //=======================================================================
393 * Special function for creation quadratic edge
395 SMDS_QuadraticEdge* SMESH_MesherHelper::AddQuadraticEdge(const SMDS_MeshNode* n1,
396 const SMDS_MeshNode* n2,
400 SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
402 const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
404 myCreateQuadratic = true;
407 return (SMDS_QuadraticEdge*)(meshDS->AddEdgeWithID(n1, n2, n12, id));
409 return (SMDS_QuadraticEdge*)(meshDS->AddEdge(n1, n2, n12));
412 //=======================================================================
415 //=======================================================================
417 * Special function for creation quadratic triangle
419 SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1,
420 const SMDS_MeshNode* n2,
421 const SMDS_MeshNode* n3,
425 SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
426 if(!myCreateQuadratic) {
428 return meshDS->AddFaceWithID(n1, n2, n3, id);
430 return meshDS->AddFace(n1, n2, n3);
433 const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
434 const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
435 const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d);
438 return meshDS->AddFaceWithID(n1, n2, n3, n12, n23, n31, id);
440 return meshDS->AddFace(n1, n2, n3, n12, n23, n31);
444 //=======================================================================
447 //=======================================================================
449 * Special function for creation quadratic quadrangle
451 SMDS_MeshFace* SMESH_MesherHelper::AddFace(const SMDS_MeshNode* n1,
452 const SMDS_MeshNode* n2,
453 const SMDS_MeshNode* n3,
454 const SMDS_MeshNode* n4,
458 SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
459 if(!myCreateQuadratic) {
461 return meshDS->AddFaceWithID(n1, n2, n3, n4, id);
463 return meshDS->AddFace(n1, n2, n3, n4);
466 const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
467 const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
468 const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d);
469 const SMDS_MeshNode* n41 = GetMediumNode(n4,n1,force3d);
472 return meshDS->AddFaceWithID(n1, n2, n3, n4, n12, n23, n34, n41, id);
474 return meshDS->AddFace(n1, n2, n3, n4, n12, n23, n34, n41);
478 //=======================================================================
479 //function : AddVolume
481 //=======================================================================
483 * Special function for creation quadratic volume
485 SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1,
486 const SMDS_MeshNode* n2,
487 const SMDS_MeshNode* n3,
488 const SMDS_MeshNode* n4,
489 const SMDS_MeshNode* n5,
490 const SMDS_MeshNode* n6,
494 SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
495 if(!myCreateQuadratic) {
497 return meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, id);
499 return meshDS->AddVolume(n1, n2, n3, n4, n5, n6);
502 const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
503 const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
504 const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d);
506 const SMDS_MeshNode* n45 = GetMediumNode(n4,n5,force3d);
507 const SMDS_MeshNode* n56 = GetMediumNode(n5,n6,force3d);
508 const SMDS_MeshNode* n64 = GetMediumNode(n6,n4,force3d);
510 const SMDS_MeshNode* n14 = GetMediumNode(n1,n4,force3d);
511 const SMDS_MeshNode* n25 = GetMediumNode(n2,n5,force3d);
512 const SMDS_MeshNode* n36 = GetMediumNode(n3,n6,force3d);
515 return meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6,
516 n12, n23, n31, n45, n56, n64, n14, n25, n36, id);
518 return meshDS->AddVolume(n1, n2, n3, n4, n5, n6,
519 n12, n23, n31, n45, n56, n64, n14, n25, n36);
523 //=======================================================================
524 //function : AddVolume
526 //=======================================================================
528 * Special function for creation quadratic volume
530 SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1,
531 const SMDS_MeshNode* n2,
532 const SMDS_MeshNode* n3,
533 const SMDS_MeshNode* n4,
537 SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
538 if(!myCreateQuadratic) {
540 return meshDS->AddVolumeWithID(n1, n2, n3, n4, id);
542 return meshDS->AddVolume(n1, n2, n3, n4);
545 const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
546 const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
547 const SMDS_MeshNode* n31 = GetMediumNode(n3,n1,force3d);
549 const SMDS_MeshNode* n14 = GetMediumNode(n1,n4,force3d);
550 const SMDS_MeshNode* n24 = GetMediumNode(n2,n4,force3d);
551 const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d);
554 return meshDS->AddVolumeWithID(n1, n2, n3, n4, n12, n23, n31, n14, n24, n34, id);
556 return meshDS->AddVolume(n1, n2, n3, n4, n12, n23, n31, n14, n24, n34);
560 //=======================================================================
561 //function : AddVolume
563 //=======================================================================
565 * Special function for creation quadratic volume
567 SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1,
568 const SMDS_MeshNode* n2,
569 const SMDS_MeshNode* n3,
570 const SMDS_MeshNode* n4,
571 const SMDS_MeshNode* n5,
572 const SMDS_MeshNode* n6,
573 const SMDS_MeshNode* n7,
574 const SMDS_MeshNode* n8,
578 SMESHDS_Mesh * meshDS = GetMesh()->GetMeshDS();
579 if(!myCreateQuadratic) {
581 return meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8, id);
583 return meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8);
586 const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d);
587 const SMDS_MeshNode* n23 = GetMediumNode(n2,n3,force3d);
588 const SMDS_MeshNode* n34 = GetMediumNode(n3,n4,force3d);
589 const SMDS_MeshNode* n41 = GetMediumNode(n4,n1,force3d);
591 const SMDS_MeshNode* n56 = GetMediumNode(n5,n6,force3d);
592 const SMDS_MeshNode* n67 = GetMediumNode(n6,n7,force3d);
593 const SMDS_MeshNode* n78 = GetMediumNode(n7,n8,force3d);
594 const SMDS_MeshNode* n85 = GetMediumNode(n8,n5,force3d);
596 const SMDS_MeshNode* n15 = GetMediumNode(n1,n5,force3d);
597 const SMDS_MeshNode* n26 = GetMediumNode(n2,n6,force3d);
598 const SMDS_MeshNode* n37 = GetMediumNode(n3,n7,force3d);
599 const SMDS_MeshNode* n48 = GetMediumNode(n4,n8,force3d);
602 return meshDS->AddVolumeWithID(n1, n2, n3, n4, n5, n6, n7, n8,
603 n12, n23, n34, n41, n56, n67,
604 n78, n85, n15, n26, n37, n48, id);
606 return meshDS->AddVolume(n1, n2, n3, n4, n5, n6, n7, n8,
607 n12, n23, n34, n41, n56, n67,
608 n78, n85, n15, n26, n37, n48);