+ Handle(ShapeAnalysis_Surface) surface = GetSurface( F );
+ if ( HasDegeneratedEdges() || surface->HasSingularities( 1e-7 ))
+ {
+ gp_Pnt center = calcTFI (0.5, 0.5, // IPAL0052863
+ SMESH_TNodeXYZ(n1), SMESH_TNodeXYZ(n2),
+ SMESH_TNodeXYZ(n3), SMESH_TNodeXYZ(n4),
+ SMESH_TNodeXYZ(n12), SMESH_TNodeXYZ(n23),
+ SMESH_TNodeXYZ(n34), SMESH_TNodeXYZ(n41));
+ gp_Pnt2d uv12 = GetNodeUV( F, n12, n3, &toCheck );
+ uvAvg = surface->NextValueOfUV( uv12, center, BRep_Tool::Tolerance( F )).XY();
+ }
+ else
+ {
+ gp_XY uv[8] = {
+ GetNodeUV( F,n1, n3, &toCheck ),
+ GetNodeUV( F,n2, n4, &toCheck ),
+ GetNodeUV( F,n3, n1, &toCheck ),
+ GetNodeUV( F,n4, n2, &toCheck ),
+ GetNodeUV( F,n12, n3 ),
+ GetNodeUV( F,n23, n4 ),
+ GetNodeUV( F,n34, n2 ),
+ GetNodeUV( F,n41, n2 )
+ };
+ AdjustByPeriod( F, uv, 8 ); // put uv[] within a period (IPAL52698)
+
+ uvAvg = calcTFI (0.5, 0.5, uv[0],uv[1],uv[2],uv[3], uv[4],uv[5],uv[6],uv[7] );
+ }
+ P = surface->Value( uvAvg );
+ centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
+ // if ( mySetElemOnShape ) node is not elem!
+ meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
+ }
+ else // ( force3d || F.IsNull() )
+ {
+ P = calcTFI (0.5, 0.5,
+ SMESH_TNodeXYZ(n1), SMESH_TNodeXYZ(n2),
+ SMESH_TNodeXYZ(n3), SMESH_TNodeXYZ(n4),
+ SMESH_TNodeXYZ(n12), SMESH_TNodeXYZ(n23),
+ SMESH_TNodeXYZ(n34), SMESH_TNodeXYZ(n41));
+ centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
+
+ if ( !F.IsNull() ) // force3d
+ {
+ uvAvg = (GetNodeUV(F,n1,n3,&toCheck) +
+ GetNodeUV(F,n2,n4,&toCheck) +
+ GetNodeUV(F,n3,n1,&toCheck) +
+ GetNodeUV(F,n4,n2,&toCheck)) / 4;
+ //CheckNodeUV( F, centralNode, uvAvg, 2*BRep_Tool::Tolerance( F ), /*force=*/true);
+ meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
+ }
+ else if ( solidID > 0 )
+ {
+ meshDS->SetNodeInVolume( centralNode, solidID );
+ }
+ else if ( myShapeID > 0 && mySetElemOnShape )
+ {
+ meshDS->SetMeshElementOnShape( centralNode, myShapeID );
+ }
+ }
+ myMapWithCentralNode.insert( std::make_pair( keyOfMap, centralNode ) );
+ return centralNode;
+}
+
+//=======================================================================
+//function : GetCentralNode
+//purpose : Return existing or create a new central node for a
+// quadratic triangle given its 6 nodes.
+//@param : force3d - true means node creation in between the given nodes,
+// else node position is found on a geometrical face if any.
+//=======================================================================
+
+const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ const SMDS_MeshNode* n3,
+ const SMDS_MeshNode* n12,
+ const SMDS_MeshNode* n23,
+ const SMDS_MeshNode* n31,
+ bool force3d)
+{
+ SMDS_MeshNode *centralNode = 0; // central node to return
+
+ // Find an existing central node
+
+ TBiQuad keyOfMap(n1,n2,n3);
+ std::map<TBiQuad, const SMDS_MeshNode* >::iterator itMapCentralNode;
+ itMapCentralNode = myMapWithCentralNode.find( keyOfMap );
+ if ( itMapCentralNode != myMapWithCentralNode.end() )
+ {
+ return (*itMapCentralNode).second;
+ }
+
+ // Get type of shape for the new central node
+
+ TopAbs_ShapeEnum shapeType = TopAbs_SHAPE;
+ int solidID = -1;
+ int faceID = -1;
+ TopoDS_Shape shape;
+ TopTools_ListIteratorOfListOfShape it;
+
+ std::map< int, int > faceId2nbNodes;
+ std::map< int, int > ::iterator itMapWithIdFace;
+
+ SMESHDS_Mesh* meshDS = GetMeshDS();
+
+ // check if a face lies on a FACE, i.e. its all corner nodes lie either on the FACE or
+ // on sub-shapes of the FACE
+ if ( GetMesh()->HasShapeToMesh() )
+ {
+ const SMDS_MeshNode* nodes[] = { n1, n2, n3 };
+ for(int i = 0; i < 3; i++)
+ {
+ shape = GetSubShapeByNode( nodes[i], meshDS );
+ if ( shape.IsNull() ) break;
+ if ( shape.ShapeType() == TopAbs_SOLID )
+ {
+ solidID = nodes[i]->getshapeId();
+ shapeType = TopAbs_SOLID;
+ break;
+ }
+ if ( shape.ShapeType() == TopAbs_FACE )
+ {
+ faceID = nodes[i]->getshapeId();
+ itMapWithIdFace = faceId2nbNodes.insert( std::make_pair( faceID, 0 ) ).first;
+ itMapWithIdFace->second++;
+ }
+ else
+ {
+ PShapeIteratorPtr it = GetAncestors(shape, *GetMesh(), TopAbs_FACE );
+ while ( const TopoDS_Shape* face = it->next() )
+ {
+ faceID = meshDS->ShapeToIndex( *face );
+ itMapWithIdFace = faceId2nbNodes.insert( std::make_pair( faceID, 0 ) ).first;
+ itMapWithIdFace->second++;
+ }
+ }
+ }
+ }
+ if ( solidID < 1 && !faceId2nbNodes.empty() ) // SOLID not found
+ {
+ // find ID of the FACE the four corner nodes belong to
+ itMapWithIdFace = faceId2nbNodes.find( myShapeID ); // IPAL52698
+ if ( itMapWithIdFace != faceId2nbNodes.end() &&
+ itMapWithIdFace->second == 4 )
+ {
+ shapeType = TopAbs_FACE;
+ faceID = myShapeID;
+ }
+ else
+ {
+ itMapWithIdFace = faceId2nbNodes.begin();
+ for ( ; itMapWithIdFace != faceId2nbNodes.end(); ++itMapWithIdFace)
+ {
+ if ( itMapWithIdFace->second == 3 )
+ {
+ shapeType = TopAbs_FACE;
+ faceID = (*itMapWithIdFace).first;
+ break;
+ }
+ }
+ }
+ }
+
+ TopoDS_Face F;
+ gp_XY uvAvg;
+
+ if ( shapeType == TopAbs_FACE )
+ {
+ F = TopoDS::Face( meshDS->IndexToShape( faceID ));
+ bool checkOK = true, badTria = false;
+ gp_XY uv[6] = {
+ GetNodeUV( F, n1, n23, &checkOK ),
+ GetNodeUV( F, n2, n31, &checkOK ),
+ GetNodeUV( F, n3, n12, &checkOK ),
+ GetNodeUV( F, n12, n3, &checkOK ),
+ GetNodeUV( F, n23, n1, &checkOK ),
+ GetNodeUV( F, n31, n2, &checkOK )
+ };
+ AdjustByPeriod( F, uv, 6 ); // put uv[] within a period (IPAL52698)
+
+ uvAvg = GetCenterUV( uv[0],uv[1],uv[2], uv[3],uv[4],uv[5], &badTria );
+
+ if ( badTria || !checkOK )
+ force3d = true;
+ }
+
+ // Create a central node
+
+ gp_Pnt P;
+ if ( !F.IsNull() && !force3d )
+ {
+ TopLoc_Location loc;
+ Handle( Geom_Surface ) S = BRep_Tool::Surface( F, loc );
+ P = S->Value( uvAvg.X(), uvAvg.Y() ).Transformed( loc );
+ centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
+ // if ( mySetElemOnShape ) node is not elem!
+ meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
+ }
+ else // ( force3d || F.IsNull() )
+ {
+ P = ( SMESH_TNodeXYZ( n12 ) +
+ SMESH_TNodeXYZ( n23 ) +
+ SMESH_TNodeXYZ( n31 ) ) / 3;
+ centralNode = meshDS->AddNode( P.X(), P.Y(), P.Z() );
+
+ if ( !F.IsNull() ) // force3d
+ {
+ meshDS->SetNodeOnFace( centralNode, faceID, uvAvg.X(), uvAvg.Y() );
+ }
+ else if ( solidID > 0 )
+ {
+ meshDS->SetNodeInVolume( centralNode, solidID );
+ }
+ else if ( myShapeID > 0 && mySetElemOnShape )
+ {
+ meshDS->SetMeshElementOnShape( centralNode, myShapeID );
+ }
+ }
+ myMapWithCentralNode.insert( std::make_pair( keyOfMap, centralNode ) );
+ return centralNode;
+}
+
+//=======================================================================
+//function : GetMediumNode
+//purpose : Return existing or create a new medium node between given ones
+//=======================================================================
+
+const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1,
+ const SMDS_MeshNode* n2,
+ bool force3d,
+ TopAbs_ShapeEnum expectedSupport)
+{
+ // Find existing node
+
+ SMESH_TLink link(n1,n2);
+ ItTLinkNode itLN = myTLinkNodeMap.find( link );
+ if ( itLN != myTLinkNodeMap.end() ) {
+ return (*itLN).second;
+ }
+
+ // Create medium node
+
+ SMDS_MeshNode* n12;
+ SMESHDS_Mesh* meshDS = GetMeshDS();
+
+ if ( IsSeamShape( n1->getshapeId() ))
+ // to get a correct UV of a node on seam, the second node must have checked UV
+ std::swap( n1, n2 );
+
+ // get type of shape for the new medium node
+ int faceID = -1, edgeID = -1;
+ TopoDS_Edge E; double u [2] = {0.,0.};
+ TopoDS_Face F; gp_XY uv[2];
+ bool uvOK[2] = { true, true };
+ const bool useCurSubShape = ( !myShape.IsNull() && myShape.ShapeType() == TopAbs_EDGE );
+
+ pair<int, TopAbs_ShapeEnum> pos = GetMediumPos( n1, n2, useCurSubShape, expectedSupport );
+
+ // get positions of the given nodes on shapes
+ if ( pos.second == TopAbs_FACE )
+ {
+ F = TopoDS::Face( meshDS->IndexToShape( faceID = pos.first ));
+ uv[0] = GetNodeUV(F,n1,n2, force3d ? 0 : &uvOK[0]);
+ uv[1] = GetNodeUV(F,n2,n1, force3d ? 0 : &uvOK[1]);
+ }
+ else if ( pos.second == TopAbs_EDGE )
+ {
+ const SMDS_PositionPtr Pos1 = n1->GetPosition();
+ const SMDS_PositionPtr Pos2 = n2->GetPosition();
+ if ( Pos1->GetTypeOfPosition()==SMDS_TOP_EDGE &&
+ Pos2->GetTypeOfPosition()==SMDS_TOP_EDGE &&
+ n1->getshapeId() != n2->getshapeId() )
+ {
+ // issue 0021006
+ return getMediumNodeOnComposedWire(n1,n2,force3d);
+ }
+ E = TopoDS::Edge(meshDS->IndexToShape( edgeID = pos.first ));
+ try {
+ u[0] = GetNodeU(E,n1,n2, force3d ? 0 : &uvOK[0]);
+ u[1] = GetNodeU(E,n2,n1, force3d ? 0 : &uvOK[1]);
+ }
+ catch ( Standard_Failure& f )
+ {
+ // issue 22502 / a node is on VERTEX not belonging to E
+ // issue 22568 / both nodes are on non-connected VERTEXes
+ return getMediumNodeOnComposedWire(n1,n2,force3d);
+ }
+ }
+
+ if ( !force3d & uvOK[0] && uvOK[1] )
+ {
+ // we try to create medium node using UV parameters of
+ // nodes, else - medium between corresponding 3d points
+ if( ! F.IsNull() )
+ {
+ if ( IsDegenShape( n1->getshapeId() )) {
+ if ( myParIndex & U_periodic ) uv[0].SetCoord( 1, uv[1].Coord( 1 ));
+ else uv[0].SetCoord( 2, uv[1].Coord( 2 ));
+ }
+ else if ( IsDegenShape( n2->getshapeId() )) {
+ if ( myParIndex & U_periodic ) uv[1].SetCoord( 1, uv[0].Coord( 1 ));
+ else uv[1].SetCoord( 2, uv[0].Coord( 2 ));
+ }
+ TopLoc_Location loc;
+ Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
+ gp_XY UV = GetMiddleUV( S, uv[0], uv[1] );
+ gp_Pnt P = S->Value( UV.X(), UV.Y() ).Transformed(loc);
+
+ SMESH_TNodeXYZ p1( n1 ), p2( n2 );
+ gp_Pnt pMid = 0.5 * ( p1 + p2 );
+ double distMid = pMid.SquareDistance( P );
+ double dist12 = ( p1 - p2 ).SquareModulus();
+ Handle(ShapeAnalysis_Surface) surfInfo = GetSurface( F );
+ if ( distMid > dist12 ||
+ HasDegeneratedEdges() ||
+ surfInfo->HasSingularities( 1e-7 ) )
+ {
+ // IPAL52850 (degen VERTEX not at singularity)
+ // project middle point to a surface
+ gp_Pnt2d uvMid;
+ if ( uvOK[0] )
+ uvMid = surfInfo->NextValueOfUV( uv[0], pMid, BRep_Tool::Tolerance( F ));
+ else
+ uvMid = surfInfo->ValueOfUV( pMid, getFaceMaxTol( F ));
+ if ( surfInfo->Gap() * surfInfo->Gap() < distMid )
+ P = surfInfo->Value( uvMid );
+ }
+ n12 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ // if ( mySetElemOnShape ) node is not elem!
+ meshDS->SetNodeOnFace(n12, faceID, UV.X(), UV.Y());
+ myTLinkNodeMap.insert(make_pair(link,n12));
+ return n12;
+ }
+ else if ( !E.IsNull() )
+ {
+ double f,l;
+ Handle(Geom_Curve) C = BRep_Tool::Curve(E, f, l);
+ if(!C.IsNull())
+ {
+ Standard_Boolean isPeriodic = C->IsPeriodic();
+ double U;
+ if(isPeriodic) {
+ Standard_Real Period = C->Period();
+ Standard_Real p = u[1]+ShapeAnalysis::AdjustByPeriod(u[1],u[0],Period);
+ Standard_Real pmid = (u[0]+p)/2.;
+ U = pmid+ShapeAnalysis::AdjustToPeriod(pmid,C->FirstParameter(),C->LastParameter());
+ }
+ else
+ U = (u[0]+u[1])/2.;
+
+ gp_Pnt P = C->Value( U );
+ n12 = meshDS->AddNode(P.X(), P.Y(), P.Z());
+ //if ( mySetElemOnShape ) node is not elem!
+ meshDS->SetNodeOnEdge(n12, edgeID, U);
+ myTLinkNodeMap.insert(make_pair(link,n12));
+ return n12;
+ }
+ }