-// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
//
-// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
-// This library is free software; you can redistribute it and/or
-// modify it under the terms of the GNU Lesser General Public
-// License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License.
//
-// This library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
-// SMESH SMESH : idl implementation based on 'SMESH' unit's classes
// File : SMESH_MeshEditor.cxx
// Created : Mon Apr 12 16:10:22 2004
// Author : Edward AGAPOV (eap)
-//
-#define CHRONODEF
+
#include "SMESH_MeshEditor.hxx"
#include "SMDS_FaceOfNodes.hxx"
#include "SMDS_VolumeTool.hxx"
#include "SMDS_EdgePosition.hxx"
-#include "SMDS_PolyhedralVolumeOfNodes.hxx"
#include "SMDS_FacePosition.hxx"
#include "SMDS_SpacePosition.hxx"
-//#include "SMDS_QuadraticFaceOfNodes.hxx"
#include "SMDS_MeshGroup.hxx"
#include "SMDS_LinearEdge.hxx"
#include "SMDS_Downward.hxx"
#include "SMESH_OctreeNode.hxx"
#include "SMESH_subMesh.hxx"
+#include <Basics_OCCTVersion.hxx>
+
#include "utilities.h"
#include <BRepAdaptor_Surface.hxx>
+#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepClass3d_SolidClassifier.hxx>
#include <BRep_Tool.hxx>
#include <ElCLib.hxx>
#include <TopTools_SequenceOfShape.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
+#include <TopoDS_Solid.hxx>
#include <gp.hxx>
#include <gp_Ax1.hxx>
#include <gp_Dir.hxx>
#include <gp_XY.hxx>
#include <gp_XYZ.hxx>
-#include <math.h>
+#include <cmath>
#include <map>
#include <set>
#include <numeric>
#include <limits>
+#include <algorithm>
+#include <sstream>
+
+#include <Standard_Failure.hxx>
+#include <Standard_ErrorHandler.hxx>
#define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
{
}
+//================================================================================
+/*!
+ * \brief Clears myLastCreatedNodes and myLastCreatedElems
+ */
+//================================================================================
+
+void SMESH_MeshEditor::CrearLastCreated()
+{
+ myLastCreatedNodes.Clear();
+ myLastCreatedElems.Clear();
+}
+
+
//=======================================================================
/*!
* \brief Add element
SMESH_MeshEditor::AddElement(const vector<const SMDS_MeshNode*> & node,
const SMDSAbs_ElementType type,
const bool isPoly,
- const int ID)
+ const int ID,
+ const double ballDiameter)
{
//MESSAGE("AddElement " <<node.size() << " " << type << " " << isPoly << " " << ID);
SMDS_MeshElement* e = 0;
else e = mesh->AddFace (node[0], node[1], node[2], node[3],
node[4], node[5], node[6], node[7] );
}
+ else if (nbnode == 9) {
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7], node[8], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7], node[8] );
+ }
} else {
if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
else e = mesh->AddPolygonalFace (node );
node[4], node[5], node[6], node[7],
node[8], node[9] );
}
+ else if (nbnode == 12) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10], node[11], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10], node[11] );
+ }
else if (nbnode == 13) {
if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
node[4], node[5], node[6], node[7],
node[12],node[13],node[14],node[15],
node[16],node[17],node[18],node[19] );
}
+ else if (nbnode == 27) {
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10],node[11],
+ node[12],node[13],node[14],node[15],
+ node[16],node[17],node[18],node[19],
+ node[20],node[21],node[22],node[23],
+ node[24],node[25],node[26], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7],
+ node[8], node[9], node[10],node[11],
+ node[12],node[13],node[14],node[15],
+ node[16],node[17],node[18],node[19],
+ node[20],node[21],node[22],node[23],
+ node[24],node[25],node[26] );
+ }
}
break;
else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
break;
+ case SMDSAbs_Ball:
+ if ( ID >= 1 ) e = mesh->AddBallWithID(node[0], ballDiameter, ID);
+ else e = mesh->AddBall (node[0], ballDiameter);
+ break;
+
default:;
}
if ( e ) myLastCreatedElems.Append( e );
return removed;
}
+//================================================================================
+/*!
+ * \brief Create 0D elements on all nodes of the given object except those
+ * nodes on which a 0D element already exists.
+ * \param elements - Elements on whose nodes to create 0D elements; if empty,
+ * the all mesh is treated
+ * \param all0DElems - returns all 0D elements found or created on nodes of \a elements
+ */
+//================================================================================
+
+void SMESH_MeshEditor::Create0DElementsOnAllNodes( const TIDSortedElemSet& elements,
+ TIDSortedElemSet& all0DElems )
+{
+ typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator> TSetIterator;
+ SMDS_ElemIteratorPtr elemIt;
+ if ( elements.empty() )
+ elemIt = GetMeshDS()->elementsIterator( SMDSAbs_Node );
+ else
+ elemIt = SMDS_ElemIteratorPtr( new TSetIterator( elements.begin(), elements.end() ));
+
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* e = elemIt->next();
+ SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
+ while ( nodeIt->more() )
+ {
+ const SMDS_MeshNode* n = cast2Node( nodeIt->next() );
+ SMDS_ElemIteratorPtr it0D = n->GetInverseElementIterator( SMDSAbs_0DElement );
+ if ( it0D->more() )
+ all0DElems.insert( it0D->next() );
+ else {
+ myLastCreatedElems.Append( GetMeshDS()->Add0DElement( n ));
+ all0DElems.insert( myLastCreatedElems.Last() );
+ }
+ }
+ }
+}
+
//=======================================================================
//function : FindShape
//purpose : Return an index of the shape theElem is on
if ( aMesh->ShapeToMesh().IsNull() )
return 0;
- if ( theElem->GetType() == SMDSAbs_Node )
- {
- int aShapeID = theElem->getshapeId();
- if (aShapeID <= 0)
- return 0;
- else
- return aShapeID;
- }
-
- TopoDS_Shape aShape; // the shape a node is on
- SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
- while ( nodeIt->more() ) {
- const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
- int aShapeID = node->getshapeId();
- if (aShapeID > 0) {
- SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID );
- if ( sm ) {
- if ( sm->Contains( theElem ))
- return aShapeID;
- if ( aShape.IsNull() )
- aShape = aMesh->IndexToShape( aShapeID );
- }
- else {
- //MESSAGE ( "::FindShape() No SubShape for aShapeID " << aShapeID );
+ int aShapeID = theElem->getshapeId();
+ if ( aShapeID < 1 )
+ return 0;
+
+ if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ))
+ if ( sm->Contains( theElem ))
+ return aShapeID;
+
+ if ( theElem->GetType() == SMDSAbs_Node ) {
+ MESSAGE( ":( Error: invalid myShapeId of node " << theElem->GetID() );
+ }
+ else {
+ MESSAGE( ":( Error: invalid myShapeId of element " << theElem->GetID() );
+ }
+
+ TopoDS_Shape aShape; // the shape a node of theElem is on
+ if ( theElem->GetType() != SMDSAbs_Node )
+ {
+ SMDS_ElemIteratorPtr nodeIt = theElem->nodesIterator();
+ while ( nodeIt->more() ) {
+ const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*>( nodeIt->next() );
+ if ((aShapeID = node->getshapeId()) > 0) {
+ if ( SMESHDS_SubMesh * sm = aMesh->MeshElements( aShapeID ) ) {
+ if ( sm->Contains( theElem ))
+ return aShapeID;
+ if ( aShape.IsNull() )
+ aShape = aMesh->IndexToShape( aShapeID );
+ }
}
}
}
// None of nodes is on a proper shape,
// find the shape among ancestors of aShape on which a node is
- if ( aShape.IsNull() ) {
- //MESSAGE ("::FindShape() - NONE node is on shape")
- return 0;
+ if ( !aShape.IsNull() ) {
+ TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
+ for ( ; ancIt.More(); ancIt.Next() ) {
+ SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
+ if ( sm && sm->Contains( theElem ))
+ return aMesh->ShapeToIndex( ancIt.Value() );
+ }
}
- TopTools_ListIteratorOfListOfShape ancIt( GetMesh()->GetAncestors( aShape ));
- for ( ; ancIt.More(); ancIt.Next() ) {
- SMESHDS_SubMesh * sm = aMesh->MeshElements( ancIt.Value() );
- if ( sm && sm->Contains( theElem ))
- return aMesh->ShapeToIndex( ancIt.Value() );
+ else
+ {
+ const map<int,SMESHDS_SubMesh*>& id2sm = GetMeshDS()->SubMeshes();
+ map<int,SMESHDS_SubMesh*>::const_iterator id_sm = id2sm.begin();
+ for ( ; id_sm != id2sm.end(); ++id_sm )
+ if ( id_sm->second->Contains( theElem ))
+ return id_sm->first;
}
//MESSAGE ("::FindShape() - SHAPE NOT FOUND")
aNodes[5] = nd2;
}
+//=======================================================================
+//function : edgeConnectivity
+//purpose : auxilary
+// return number of the edges connected with the theNode.
+// if theEdges has connections with the other type of the
+// elements, return -1
+//=======================================================================
+static int nbEdgeConnectivity(const SMDS_MeshNode* theNode)
+{
+ SMDS_ElemIteratorPtr elemIt = theNode->GetInverseElementIterator();
+ int nb=0;
+ while(elemIt->more()) {
+ elemIt->next();
+ nb++;
+ }
+ return nb;
+}
+
+
//=======================================================================
//function : GetNodesFromTwoTria
//purpose : auxilary
return false;
}
+//================================================================================
+/*!
+ * \brief Reorient faces.
+ * \param theFaces - the faces to reorient. If empty the whole mesh is meant
+ * \param theDirection - desired direction of normal of \a theFace
+ * \param theFace - one of \a theFaces that sould be oriented according to
+ * \a theDirection and whose orientation defines orientation of other faces
+ * \return number of reoriented faces.
+ */
+//================================================================================
+
+int SMESH_MeshEditor::Reorient2D (TIDSortedElemSet & theFaces,
+ const gp_Dir& theDirection,
+ const SMDS_MeshElement * theFace)
+{
+ int nbReori = 0;
+ if ( !theFace || theFace->GetType() != SMDSAbs_Face ) return nbReori;
+
+ if ( theFaces.empty() )
+ {
+ SMDS_FaceIteratorPtr fIt = GetMeshDS()->facesIterator(/*idInceasingOrder=*/true);
+ while ( fIt->more() )
+ theFaces.insert( theFaces.end(), fIt->next() );
+ }
+
+ // orient theFace according to theDirection
+ gp_XYZ normal;
+ SMESH_Algo::FaceNormal( theFace, normal, /*normalized=*/false );
+ if ( normal * theDirection.XYZ() < 0 )
+ nbReori += Reorient( theFace );
+
+ // Orient other faces
+
+ set< const SMDS_MeshElement* > startFaces, visitedFaces;
+ TIDSortedElemSet avoidSet;
+ set< SMESH_TLink > checkedLinks;
+ pair< set< SMESH_TLink >::iterator, bool > linkIt_isNew;
+
+ if ( theFaces.size() > 1 )// leave 1 face to prevent finding not selected faces
+ theFaces.erase( theFace );
+ startFaces.insert( theFace );
+
+ int nodeInd1, nodeInd2;
+ const SMDS_MeshElement* otherFace;
+ vector< const SMDS_MeshElement* > facesNearLink;
+ vector< std::pair< int, int > > nodeIndsOfFace;
+
+ set< const SMDS_MeshElement* >::iterator startFace = startFaces.begin();
+ while ( !startFaces.empty() )
+ {
+ startFace = startFaces.begin();
+ theFace = *startFace;
+ startFaces.erase( startFace );
+ if ( !visitedFaces.insert( theFace ).second )
+ continue;
+
+ avoidSet.clear();
+ avoidSet.insert(theFace);
+
+ NLink link( theFace->GetNode( 0 ), 0 );
+
+ const int nbNodes = theFace->NbCornerNodes();
+ for ( int i = 0; i < nbNodes; ++i ) // loop on links of theFace
+ {
+ link.second = theFace->GetNode(( i+1 ) % nbNodes );
+ linkIt_isNew = checkedLinks.insert( link );
+ if ( !linkIt_isNew.second )
+ {
+ // link has already been checked and won't be encountered more
+ // if the group (theFaces) is manifold
+ //checkedLinks.erase( linkIt_isNew.first );
+ }
+ else
+ {
+ facesNearLink.clear();
+ nodeIndsOfFace.clear();
+ while (( otherFace = FindFaceInSet( link.first, link.second,
+ theFaces, avoidSet, &nodeInd1, &nodeInd2 )))
+ if ( otherFace != theFace)
+ {
+ facesNearLink.push_back( otherFace );
+ nodeIndsOfFace.push_back( make_pair( nodeInd1, nodeInd2 ));
+ avoidSet.insert( otherFace );
+ }
+ if ( facesNearLink.size() > 1 )
+ {
+ // NON-MANIFOLD mesh shell !
+ // select a face most co-directed with theFace,
+ // other faces won't be visited this time
+ gp_XYZ NF, NOF;
+ SMESH_Algo::FaceNormal( theFace, NF, /*normalized=*/false );
+ double proj, maxProj = -1;
+ for ( size_t i = 0; i < facesNearLink.size(); ++i ) {
+ SMESH_Algo::FaceNormal( facesNearLink[i], NOF, /*normalized=*/false );
+ if (( proj = Abs( NF * NOF )) > maxProj ) {
+ maxProj = proj;
+ otherFace = facesNearLink[i];
+ nodeInd1 = nodeIndsOfFace[i].first;
+ nodeInd2 = nodeIndsOfFace[i].second;
+ }
+ }
+ // not to visit rejected faces
+ for ( size_t i = 0; i < facesNearLink.size(); ++i )
+ if ( facesNearLink[i] != otherFace && theFaces.size() > 1 )
+ visitedFaces.insert( facesNearLink[i] );
+ }
+ else if ( facesNearLink.size() == 1 )
+ {
+ otherFace = facesNearLink[0];
+ nodeInd1 = nodeIndsOfFace.back().first;
+ nodeInd2 = nodeIndsOfFace.back().second;
+ }
+ if ( otherFace && otherFace != theFace)
+ {
+ // link must be reverse in otherFace if orientation ot otherFace
+ // is same as that of theFace
+ if ( abs(nodeInd2-nodeInd1) == 1 ? nodeInd2 > nodeInd1 : nodeInd1 > nodeInd2 )
+ {
+ nbReori += Reorient( otherFace );
+ }
+ startFaces.insert( otherFace );
+ }
+ }
+ std::swap( link.first, link.second ); // reverse the link
+ }
+ }
+ return nbReori;
+}
+
//=======================================================================
//function : getBadRate
//purpose :
const SMDS_MeshElement* elem = *itElem;
if ( !elem || elem->GetType() != SMDSAbs_Face )
continue;
- if ( elem->NbNodes() != ( elem->IsQuadratic() ? 8 : 4 ))
+ if ( elem->NbCornerNodes() != 4 )
continue;
// retrieve element nodes
- const SMDS_MeshNode* aNodes [8];
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- int i = 0;
- while ( itN->more() )
- aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
+ vector< const SMDS_MeshNode* > aNodes( elem->begin_nodes(), elem->end_nodes() );
// compare two sets of possible triangles
double aBadRate1, aBadRate2; // to what extent a set is bad
if( !elem->IsQuadratic() ) {
// split liner quadrangle
+ // for MaxElementLength2D functor we return minimum diagonal for splitting,
+ // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
if ( aBadRate1 <= aBadRate2 ) {
// tr1 + tr2 is better
newElem1 = aMesh->AddFace( aNodes[2], aNodes[3], aNodes[0] );
helper.SetSubShape( shape );
}
}
- // get elem nodes
- const SMDS_MeshNode* aNodes [8];
- const SMDS_MeshNode* inFaceNode = 0;
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- int i = 0;
- while ( itN->more() ) {
- aNodes[ i++ ] = static_cast<const SMDS_MeshNode*>( itN->next() );
- if ( !inFaceNode && helper.GetNodeUVneedInFaceNode() &&
- aNodes[ i-1 ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
- {
- inFaceNode = aNodes[ i-1 ];
- }
- }
// find middle point for (0,1,2,3)
// and create a node in this point;
- gp_XYZ p( 0,0,0 );
- if ( surface.IsNull() ) {
- for(i=0; i<4; i++)
- p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
- p /= 4;
+ const SMDS_MeshNode* newN = 0;
+ if ( aNodes.size() == 9 )
+ {
+ // SMDSEntity_BiQuad_Quadrangle
+ newN = aNodes.back();
}
- else {
- TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
- gp_XY uv( 0,0 );
- for(i=0; i<4; i++)
- uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
- uv /= 4.;
- p = surface->Value( uv.X(), uv.Y() ).XYZ();
+ else
+ {
+ gp_XYZ p( 0,0,0 );
+ if ( surface.IsNull() )
+ {
+ for ( int i = 0; i < 4; i++ )
+ p += gp_XYZ(aNodes[i]->X(), aNodes[i]->Y(), aNodes[i]->Z() );
+ p /= 4;
+ }
+ else
+ {
+ const SMDS_MeshNode* inFaceNode = 0;
+ if ( helper.GetNodeUVneedInFaceNode() )
+ for ( size_t i = 0; i < aNodes.size() && !inFaceNode; ++i )
+ if ( aNodes[ i ]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE )
+ inFaceNode = aNodes[ i ];
+
+ TopoDS_Face face = TopoDS::Face( helper.GetSubShape() );
+ gp_XY uv( 0,0 );
+ for ( int i = 0; i < 4; i++ )
+ uv += helper.GetNodeUV( face, aNodes[i], inFaceNode );
+ uv /= 4.;
+ p = surface->Value( uv.X(), uv.Y() ).XYZ();
+ }
+ newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
+ myLastCreatedNodes.Append(newN);
}
- const SMDS_MeshNode* newN = aMesh->AddNode( p.X(), p.Y(), p.Z() );
- myLastCreatedNodes.Append(newN);
-
// create a new element
- const SMDS_MeshNode* N[6];
if ( aBadRate1 <= aBadRate2 ) {
- N[0] = aNodes[0];
- N[1] = aNodes[1];
- N[2] = aNodes[2];
- N[3] = aNodes[4];
- N[4] = aNodes[5];
- N[5] = newN;
newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
aNodes[6], aNodes[7], newN );
newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
newN, aNodes[4], aNodes[5] );
}
else {
- N[0] = aNodes[1];
- N[1] = aNodes[2];
- N[2] = aNodes[3];
- N[3] = aNodes[5];
- N[4] = aNodes[6];
- N[5] = newN;
newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
aNodes[7], aNodes[4], newN );
newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
SMDS_FaceOfNodes tr3 ( aNodes[1], aNodes[2], aNodes[3] );
SMDS_FaceOfNodes tr4 ( aNodes[3], aNodes[0], aNodes[1] );
aBadRate2 = getBadRate( &tr3, theCrit ) + getBadRate( &tr4, theCrit );
-
+ // for MaxElementLength2D functor we return minimum diagonal for splitting,
+ // because aBadRate1=2*len(diagonal 1-3); aBadRate2=2*len(diagonal 2-4)
if (aBadRate1 <= aBadRate2) // tr1 + tr2 is better
return 1; // diagonal 1-3
{
case SMDSEntity_Hexa:
case SMDSEntity_Quad_Hexa:
+ case SMDSEntity_TriQuad_Hexa:
if ( theMethodFlags == SMESH_MeshEditor::HEXA_TO_5 )
connVariants = theHexTo5, nbTet = 5;
else
// each facet of a volume is split into triangles and
// each of triangles and a volume barycenter form a tetrahedron.
+ const bool isHex27 = ( vol.Element()->GetEntityType() == SMDSEntity_TriQuad_Hexa );
+
int* connectivity = new int[ maxTetConnSize + 1 ];
method._connectivity = connectivity;
method._ownConn = true;
- method._baryNode = true;
+ method._baryNode = !isHex27; // to create central node or not
int connSize = 0;
- int baryCenInd = vol.NbNodes();
+ int baryCenInd = vol.NbNodes() - int( isHex27 );
for ( int iF = 0; iF < vol.NbFaces(); ++iF )
{
const int nbNodes = vol.NbFaceNodes( iF ) / iQ;
const SMDS_MeshNode** nodes = vol.GetFaceNodes( iF );
int nbVariants = ( nbNodes == 4 ? 2 : nbNodes );
for ( int iVar = 0; iVar < nbVariants; ++iVar, ++iCommon )
+ {
+ double badness = 0;
for ( int iLast = iCommon+2; iLast < iCommon+nbNodes; ++iLast )
{
SMDS_FaceOfNodes tria ( nodes[ iQ*( iCommon )],
nodes[ iQ*((iLast-1)%nbNodes)],
nodes[ iQ*((iLast )%nbNodes)]);
- double badness = getBadRate( &tria, aspectRatio );
- badness2iCommon.insert( make_pair( badness, iCommon ));
+ badness += getBadRate( &tria, aspectRatio );
}
+ badness2iCommon.insert( make_pair( badness, iCommon ));
+ }
// use iCommon with lowest badness
iCommon = badness2iCommon.begin()->second;
}
int nbTet = nbNodes - 2;
if ( is24TetMode && nbNodes > 3 && triaSplits.empty())
{
- method._faceBaryNode.insert( make_pair( iF, (const SMDS_MeshNode*)0 ));
- int faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
+ int faceBaryCenInd;
+ if ( isHex27 )
+ {
+ faceBaryCenInd = vol.GetCenterNodeIndex( iF );
+ method._faceBaryNode[ iF ] = vol.GetNodes()[ faceBaryCenInd ];
+ }
+ else
+ {
+ method._faceBaryNode[ iF ] = 0;
+ faceBaryCenInd = baryCenInd + method._faceBaryNode.size();
+ }
nbTet = nbNodes;
for ( int i = 0; i < nbTet; ++i )
{
}
}
method._nbTetra += nbTet;
- }
+
+ } // loop on volume faces
+
connectivity[ connSize++ ] = -1;
- }
+
+ } // end of generic solution
+
return method;
}
//================================================================================
while ( volIt1->more() )
{
const SMDS_MeshElement* v = volIt1->next();
- if ( v->GetEntityType() != ( v->IsQuadratic() ? SMDSEntity_Quad_Tetra : SMDSEntity_Tetra ))
+ SMDSAbs_EntityType type = v->GetEntityType();
+ if ( type != SMDSEntity_Tetra && type != SMDSEntity_Quad_Tetra )
continue;
- SMDS_ElemIteratorPtr volIt2 = n2->GetInverseElementIterator(SMDSAbs_Volume);
- while ( volIt2->more() )
- if ( v != volIt2->next() )
- continue;
- SMDS_ElemIteratorPtr volIt3 = n3->GetInverseElementIterator(SMDSAbs_Volume);
- while ( volIt3->more() )
- if ( v == volIt3->next() )
- return true;
+ if ( type == SMDSEntity_Quad_Tetra && v->GetNodeIndex( n1 ) > 3 )
+ continue; // medium node not allowed
+ const int ind2 = v->GetNodeIndex( n2 );
+ if ( ind2 < 0 || 3 < ind2 )
+ continue;
+ const int ind3 = v->GetNodeIndex( n3 );
+ if ( ind3 < 0 || 3 < ind3 )
+ continue;
+ return true;
}
return false;
}
*/
//=======================================================================
- struct TVolumeFaceKey: pair< int, pair< int, int> >
+ struct TVolumeFaceKey: pair< pair< int, int>, pair< int, int> >
{
TVolumeFaceKey( SMDS_VolumeTool& vol, int iF )
{
for ( int i = 0; i < nbNodes; i += iQ )
sortedNodes.insert( fNodes[i] );
TIDSortedNodeSet::iterator n = sortedNodes.begin();
- first = (*(n++))->GetID();
- second.first = (*(n++))->GetID();
- second.second = (*(n++))->GetID();
+ first.first = (*(n++))->GetID();
+ first.second = (*(n++))->GetID();
+ second.first = (*(n++))->GetID();
+ second.second = ( sortedNodes.size() > 3 ) ? (*(n++))->GetID() : 0;
}
};
} // namespace
//=======================================================================
//function : SplitVolumesIntoTetra
-//purpose : Split volumic elements into tetrahedra.
+//purpose : Split volume elements into tetrahedra.
//=======================================================================
void SMESH_MeshEditor::SplitVolumesIntoTetra (const TIDSortedElemSet & theElems,
SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
-
+
SMESH_SequenceOfElemPtr newNodes, newElems;
// map face of volume to it's baricenrtic node
TIDSortedElemSet::const_iterator elem = theElems.begin();
for ( ; elem != theElems.end(); ++elem )
{
+ if ( (*elem)->GetType() != SMDSAbs_Volume )
+ continue;
SMDSAbs_EntityType geomType = (*elem)->GetEntityType();
- if ( geomType <= SMDSEntity_Quad_Tetra )
- continue; // tetra or face or ...
+ if ( geomType == SMDSEntity_Tetra || geomType == SMDSEntity_Quad_Tetra )
+ continue;
- if ( !volTool.Set( *elem )) continue; // not volume? strange...
+ if ( !volTool.Set( *elem, /*ignoreCentralNodes=*/false )) continue; // strange...
TSplitMethod splitMethod = getSplitMethod( volTool, theMethodFlags );
if ( splitMethod._nbTetra < 1 ) continue;
for ( int iF = 0; iF < volTool.NbFaces(); ++iF )
{
const SMDS_MeshNode** fNodes = volTool.GetFaceNodes( iF );
- for ( int iN = 0; iN < volTool.NbFaceNodes( iF ); iN += iQ )
- helper.AddTLinkNode( fNodes[iF], fNodes[iF+2], fNodes[iF+1] );
+ int nbN = volTool.NbFaceNodes( iF ) - bool( volTool.GetCenterNodeIndex(iF) > 0 );
+ for ( int iN = 0; iN < nbN; iN += iQ )
+ helper.AddTLinkNode( fNodes[iN], fNodes[iN+2], fNodes[iN+1] );
}
helper.SetIsQuadratic( true );
}
helper.SetIsQuadratic( false );
}
vector<const SMDS_MeshNode*> nodes( (*elem)->begin_nodes(), (*elem)->end_nodes() );
+ helper.SetElementsOnShape( true );
if ( splitMethod._baryNode )
{
// make a node at barycenter
{
map< TVolumeFaceKey, const SMDS_MeshNode* >::iterator f_n =
volFace2BaryNode.insert
- ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), (const SMDS_MeshNode*)0) ).first;
+ ( make_pair( TVolumeFaceKey( volTool,iF_n->first ), iF_n->second )).first;
if ( !f_n->second )
{
volTool.GetFaceBaryCenter( iF_n->first, bc[0], bc[1], bc[2] );
}
// make tetras
- helper.SetElementsOnShape( true );
vector<const SMDS_MeshElement* > tetras( splitMethod._nbTetra ); // splits of a volume
const int* tetConn = splitMethod._connectivity;
for ( int i = 0; i < splitMethod._nbTetra; ++i, tetConn += 4 )
// find an existing face
vector<const SMDS_MeshNode*> fNodes( volTool.GetFaceNodes( iF ),
- volTool.GetFaceNodes( iF ) + nbNodes*iQ );
- while ( const SMDS_MeshElement* face = GetMeshDS()->FindFace( fNodes ))
+ volTool.GetFaceNodes( iF ) + volTool.NbFaceNodes( iF ));
+ while ( const SMDS_MeshElement* face = GetMeshDS()->FindElement( fNodes, SMDSAbs_Face,
+ /*noMedium=*/false))
{
// make triangles
helper.SetElementsOnShape( false );
vector< const SMDS_MeshElement* > triangles;
+ // find submesh to add new triangles in
+ if ( !fSubMesh || !fSubMesh->Contains( face ))
+ {
+ int shapeID = FindShape( face );
+ fSubMesh = GetMeshDS()->MeshElements( shapeID );
+ }
map<int, const SMDS_MeshNode*>::iterator iF_n = splitMethod._faceBaryNode.find(iF);
if ( iF_n != splitMethod._faceBaryNode.end() )
{
for ( int iN = 0; iN < nbNodes*iQ; iN += iQ )
{
const SMDS_MeshNode* n1 = fNodes[iN];
- const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%nbNodes*iQ];
+ const SMDS_MeshNode *n2 = fNodes[(iN+iQ)%(nbNodes*iQ)];
const SMDS_MeshNode *n3 = iF_n->second;
if ( !volTool.IsFaceExternal( iF ))
swap( n2, n3 );
triangles.push_back( helper.AddFace( n1,n2,n3 ));
+
+ if ( fSubMesh && n3->getshapeId() < 1 )
+ fSubMesh->AddNode( n3 );
}
}
else
volNodes[ facet->_n3 ]));
}
}
- // find submesh to add new triangles in
- if ( !fSubMesh || !fSubMesh->Contains( face ))
- {
- int shapeID = FindShape( face );
- fSubMesh = GetMeshDS()->MeshElements( shapeID );
- }
for ( int i = 0; i < triangles.size(); ++i )
{
if ( !triangles[i] ) continue;
GetMeshDS()->RemoveFreeElement( *elem, subMesh, /*fromGroups=*/false );
+ if ( geomType == SMDSEntity_TriQuad_Hexa )
+ {
+ // remove medium nodes that could become free
+ for ( int i = 20; i < volTool.NbNodes(); ++i )
+ if ( volNodes[i]->NbInverseElements() == 0 )
+ GetMeshDS()->RemoveNode( volNodes[i] );
+ }
} // loop on volumes to split
myLastCreatedNodes = newNodes;
// create a new element
const SMDS_MeshElement* newElem1 = 0;
const SMDS_MeshElement* newElem2 = 0;
- const SMDS_MeshNode* N[6];
if ( the13Diag ) {
- N[0] = aNodes[0];
- N[1] = aNodes[1];
- N[2] = aNodes[2];
- N[3] = aNodes[4];
- N[4] = aNodes[5];
- N[5] = newN;
newElem1 = aMesh->AddFace(aNodes[2], aNodes[3], aNodes[0],
aNodes[6], aNodes[7], newN );
newElem2 = aMesh->AddFace(aNodes[2], aNodes[0], aNodes[1],
newN, aNodes[4], aNodes[5] );
}
else {
- N[0] = aNodes[1];
- N[1] = aNodes[2];
- N[2] = aNodes[3];
- N[3] = aNodes[5];
- N[4] = aNodes[6];
- N[5] = newN;
newElem1 = aMesh->AddFace(aNodes[3], aNodes[0], aNodes[1],
aNodes[7], aNodes[4], newN );
newElem2 = aMesh->AddFace(aNodes[3], aNodes[1], aNodes[2],
const SMDS_MeshNode * n1,
const SMDS_MeshNode * n2)
{
- double angle = 2*PI; // bad angle
+ double angle = 2. * M_PI; // bad angle
// get normals
SMESH::Controls::TSequenceOfXYZ P1, P2;
while ( elemIt->more() )
{
const SMDS_MeshElement* elem = elemIt->next();
+ if(elem->GetType() == SMDSAbs_0DElement)
+ continue;
+
SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
if ( elem->GetType() == SMDSAbs_Volume )
{
if ( projector.IsDone() ) {
double u, v, minVal = DBL_MAX;
for ( int i = projector.NbExt(); i > 0; i-- )
+#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
+ if ( projector.SquareDistance( i ) < minVal ) {
+ minVal = projector.SquareDistance( i );
+#else
if ( projector.Value( i ) < minVal ) {
minVal = projector.Value( i );
+#endif
projector.Point( i ).Parameter( u, v );
}
result.SetCoord( u, v );
SMDS_FaceIteratorPtr fIt = aMesh->facesIterator();
while ( fIt->more() ) {
const SMDS_MeshElement* face = fIt->next();
- theElems.insert( face );
+ theElems.insert( theElems.end(), face );
}
}
// get all face ids theElems are on
Handle(Geom_Surface) surface;
SMESHDS_SubMesh* faceSubMesh = 0;
TopoDS_Face face;
- double fToler2 = 0, vPeriod = 0., uPeriod = 0., f,l;
+ double fToler2 = 0, f,l;
double u1 = 0, u2 = 0, v1 = 0, v2 = 0;
bool isUPeriodic = false, isVPeriodic = false;
if ( *fId ) {
fToler2 *= fToler2 * 10.;
isUPeriodic = surface->IsUPeriodic();
if ( isUPeriodic )
- vPeriod = surface->UPeriod();
+ surface->UPeriod();
isVPeriodic = surface->IsVPeriodic();
if ( isVPeriodic )
- uPeriod = surface->VPeriod();
+ surface->VPeriod();
surface->Bounds( u1, u2, v1, v2 );
}
// ---------------------------------------------------------
// fix nodes on mesh boundary
if ( checkBoundaryNodes ) {
- map< NLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
- map< NLink, int >::iterator link_nb;
+ map< SMESH_TLink, int > linkNbMap; // how many times a link encounters in elemsOnFace
+ map< SMESH_TLink, int >::iterator link_nb;
// put all elements links to linkNbMap
list< const SMDS_MeshElement* >::iterator elemIt = elemsOnFace.begin();
for ( ; elemIt != elemsOnFace.end(); ++elemIt ) {
const SMDS_MeshElement* elem = (*elemIt);
- int nbn = elem->NbNodes();
- if(elem->IsQuadratic())
- nbn = nbn/2;
+ int nbn = elem->NbCornerNodes();
// loop on elem links: insert them in linkNbMap
- const SMDS_MeshNode* curNode, *prevNode = elem->GetNodeWrap( nbn );
for ( int iN = 0; iN < nbn; ++iN ) {
- curNode = elem->GetNode( iN );
- NLink link;
- if ( curNode < prevNode ) link = make_pair( curNode , prevNode );
- else link = make_pair( prevNode , curNode );
- prevNode = curNode;
- link_nb = linkNbMap.find( link );
- if ( link_nb == linkNbMap.end() )
- linkNbMap.insert( make_pair ( link, 1 ));
- else
- link_nb->second++;
+ const SMDS_MeshNode* n1 = elem->GetNode( iN );
+ const SMDS_MeshNode* n2 = elem->GetNode(( iN+1 ) % nbn);
+ SMESH_TLink link( n1, n2 );
+ link_nb = linkNbMap.insert( make_pair( link, 0 )).first;
+ link_nb->second++;
}
}
// remove nodes that are in links encountered only once from setMovableNodes
for ( link_nb = linkNbMap.begin(); link_nb != linkNbMap.end(); ++link_nb ) {
if ( link_nb->second == 1 ) {
- setMovableNodes.erase( link_nb->first.first );
- setMovableNodes.erase( link_nb->first.second );
+ setMovableNodes.erase( link_nb->first.node1() );
+ setMovableNodes.erase( link_nb->first.node2() );
}
}
}
//function : isReverse
//purpose : Return true if normal of prevNodes is not co-directied with
// gp_Vec(prevNodes[iNotSame],nextNodes[iNotSame]).
-// iNotSame is where prevNodes and nextNodes are different
+// iNotSame is where prevNodes and nextNodes are different.
+// If result is true then future volume orientation is OK
//=======================================================================
-static bool isReverse(vector<const SMDS_MeshNode*> prevNodes,
- vector<const SMDS_MeshNode*> nextNodes,
- const int nbNodes,
- const int iNotSame)
+static bool isReverse(const SMDS_MeshElement* face,
+ const vector<const SMDS_MeshNode*>& prevNodes,
+ const vector<const SMDS_MeshNode*>& nextNodes,
+ const int iNotSame)
{
- int iBeforeNotSame = ( iNotSame == 0 ? nbNodes - 1 : iNotSame - 1 );
- int iAfterNotSame = ( iNotSame + 1 == nbNodes ? 0 : iNotSame + 1 );
-
- const SMDS_MeshNode* nB = prevNodes[ iBeforeNotSame ];
- const SMDS_MeshNode* nA = prevNodes[ iAfterNotSame ];
- const SMDS_MeshNode* nP = prevNodes[ iNotSame ];
- const SMDS_MeshNode* nN = nextNodes[ iNotSame ];
- gp_Pnt pB ( nB->X(), nB->Y(), nB->Z() );
- gp_Pnt pA ( nA->X(), nA->Y(), nA->Z() );
- gp_Pnt pP ( nP->X(), nP->Y(), nP->Z() );
- gp_Pnt pN ( nN->X(), nN->Y(), nN->Z() );
+ SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
+ SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
+ gp_XYZ extrDir( pN - pP ), faceNorm;
+ SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
- gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
-
- return (vA ^ vB) * vN < 0.0;
+ return faceNorm * extrDir < 0.0;
}
//=======================================================================
//MESSAGE("sweepElement " << nbSteps);
SMESHDS_Mesh* aMesh = GetMeshDS();
+ const int nbNodes = elem->NbNodes();
+ const int nbCorners = elem->NbCornerNodes();
+ SMDSAbs_EntityType baseType = elem->GetEntityType(); /* it can change in case of
+ polyhedron creation !!! */
// Loop on elem nodes:
// find new nodes and detect same nodes indices
- int nbNodes = elem->NbNodes();
vector < list< const SMDS_MeshNode* >::const_iterator > itNN( nbNodes );
vector<const SMDS_MeshNode*> prevNod( nbNodes );
vector<const SMDS_MeshNode*> nextNod( nbNodes );
vector<const SMDS_MeshNode*> midlNod( nbNodes );
- int iNode, nbSame = 0, iNotSameNode = 0, iSameNode = 0;
+ int iNode, nbSame = 0, nbDouble = 0, iNotSameNode = 0;
vector<int> sames(nbNodes);
- vector<bool> issimple(nbNodes);
+ vector<bool> isSingleNode(nbNodes);
for ( iNode = 0; iNode < nbNodes; iNode++ ) {
- TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
- const SMDS_MeshNode* node = nnIt->first;
+ TNodeOfNodeListMapItr nnIt = newNodesItVec[ iNode ];
+ const SMDS_MeshNode* node = nnIt->first;
const list< const SMDS_MeshNode* > & listNewNodes = nnIt->second;
- if ( listNewNodes.empty() ) {
+ if ( listNewNodes.empty() )
return;
- }
- issimple[iNode] = (listNewNodes.size()==nbSteps); // is node medium
-
- itNN[ iNode ] = listNewNodes.begin();
+ itNN [ iNode ] = listNewNodes.begin();
prevNod[ iNode ] = node;
nextNod[ iNode ] = listNewNodes.front();
- if( !elem->IsQuadratic() || !issimple[iNode] ) {
- if ( prevNod[ iNode ] != nextNod [ iNode ])
- iNotSameNode = iNode;
- else {
- iSameNode = iNode;
- //nbSame++;
+
+ isSingleNode[iNode] = (listNewNodes.size()==nbSteps); /* medium node of quadratic or
+ corner node of linear */
+ if ( prevNod[ iNode ] != nextNod [ iNode ])
+ nbDouble += !isSingleNode[iNode];
+
+ if( iNode < nbCorners ) { // check corners only
+ if ( prevNod[ iNode ] == nextNod [ iNode ])
sames[nbSame++] = iNode;
- }
+ else
+ iNotSameNode = iNode;
}
}
- //cerr<<" nbSame = "<<nbSame<<endl;
if ( nbSame == nbNodes || nbSame > 2) {
MESSAGE( " Too many same nodes of element " << elem->GetID() );
- //INFOS( " Too many same nodes of element " << elem->GetID() );
return;
}
- // if( elem->IsQuadratic() && nbSame>0 ) {
- // MESSAGE( "Can not rotate quadratic element " << elem->GetID() );
- // return;
- // }
-
- int iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
- int nbBaseNodes = ( elem->IsQuadratic() ? nbNodes/2 : nbNodes );
- if ( nbSame > 0 ) {
- iBeforeSame = ( iSameNode == 0 ? nbBaseNodes - 1 : iSameNode - 1 );
- iAfterSame = ( iSameNode + 1 == nbBaseNodes ? 0 : iSameNode + 1 );
- iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
+ if ( elem->GetType() == SMDSAbs_Face && !isReverse( elem, prevNod, nextNod, iNotSameNode ))
+ {
+ // fix nodes order to have bottom normal external
+ if ( baseType == SMDSEntity_Polygon )
+ {
+ std::reverse( itNN.begin(), itNN.end() );
+ std::reverse( prevNod.begin(), prevNod.end() );
+ std::reverse( midlNod.begin(), midlNod.end() );
+ std::reverse( nextNod.begin(), nextNod.end() );
+ std::reverse( isSingleNode.begin(), isSingleNode.end() );
+ }
+ else
+ {
+ const vector<int>& ind = SMDS_MeshCell::reverseSmdsOrder( baseType );
+ SMDS_MeshCell::applyInterlace( ind, itNN );
+ SMDS_MeshCell::applyInterlace( ind, prevNod );
+ SMDS_MeshCell::applyInterlace( ind, nextNod );
+ SMDS_MeshCell::applyInterlace( ind, midlNod );
+ SMDS_MeshCell::applyInterlace( ind, isSingleNode );
+ if ( nbSame > 0 )
+ {
+ sames[nbSame] = iNotSameNode;
+ for ( int j = 0; j <= nbSame; ++j )
+ for ( size_t i = 0; i < ind.size(); ++i )
+ if ( ind[i] == sames[j] )
+ {
+ sames[j] = i;
+ break;
+ }
+ iNotSameNode = sames[nbSame];
+ }
+ }
}
- //if(nbNodes==8)
- //cout<<" prevNod[0]="<< prevNod[0]<<" prevNod[1]="<< prevNod[1]
- // <<" prevNod[2]="<< prevNod[2]<<" prevNod[3]="<< prevNod[4]
- // <<" prevNod[4]="<< prevNod[4]<<" prevNod[5]="<< prevNod[5]
- // <<" prevNod[6]="<< prevNod[6]<<" prevNod[7]="<< prevNod[7]<<endl;
-
- // check element orientation
- int i0 = 0, i2 = 2;
- if ( nbNodes > 2 && !isReverse( prevNod, nextNod, nbNodes, iNotSameNode )) {
- //MESSAGE("Reversed elem " << elem );
- i0 = 2;
- i2 = 0;
- if ( nbSame > 0 )
- std::swap( iBeforeSame, iAfterSame );
+ int iSameNode = 0, iBeforeSame = 0, iAfterSame = 0, iOpposSame = 0;
+ if ( nbSame > 0 ) {
+ iSameNode = sames[ nbSame-1 ];
+ iBeforeSame = ( iSameNode + nbCorners - 1 ) % nbCorners;
+ iAfterSame = ( iSameNode + 1 ) % nbCorners;
+ iOpposSame = ( iSameNode - 2 < 0 ? iSameNode + 2 : iSameNode - 2 );
}
// make new elements
- const SMDS_MeshElement* lastElem = elem;
- for (int iStep = 0; iStep < nbSteps; iStep++ ) {
+ for (int iStep = 0; iStep < nbSteps; iStep++ )
+ {
// get next nodes
- for ( iNode = 0; iNode < nbNodes; iNode++ ) {
- if(issimple[iNode]) {
- nextNod[ iNode ] = *itNN[ iNode ];
- itNN[ iNode ]++;
- }
- else {
- if( elem->GetType()==SMDSAbs_Node ) {
- // we have to use two nodes
- midlNod[ iNode ] = *itNN[ iNode ];
- itNN[ iNode ]++;
- nextNod[ iNode ] = *itNN[ iNode ];
- itNN[ iNode ]++;
- }
- else if(!elem->IsQuadratic() || lastElem->IsMediumNode(prevNod[iNode]) ) {
- // we have to use each second node
- //itNN[ iNode ]++;
- nextNod[ iNode ] = *itNN[ iNode ];
- itNN[ iNode ]++;
- }
- else {
- // we have to use two nodes
- midlNod[ iNode ] = *itNN[ iNode ];
- itNN[ iNode ]++;
- nextNod[ iNode ] = *itNN[ iNode ];
- itNN[ iNode ]++;
- }
- }
+ for ( iNode = 0; iNode < nbNodes; iNode++ )
+ {
+ midlNod[ iNode ] = isSingleNode[iNode] ? 0 : *itNN[ iNode ]++;
+ nextNod[ iNode ] = *itNN[ iNode ]++;
}
+
SMDS_MeshElement* aNewElem = 0;
- if(!elem->IsPoly()) {
- switch ( nbNodes ) {
- case 0:
- return;
- case 1: { // NODE
+ /*if(!elem->IsPoly())*/ {
+ switch ( baseType ) {
+ case SMDSEntity_0D:
+ case SMDSEntity_Node: { // sweep NODE
if ( nbSame == 0 ) {
- if(issimple[0])
+ if ( isSingleNode[0] )
aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ] );
else
aNewElem = aMesh->AddEdge( prevNod[ 0 ], nextNod[ 0 ], midlNod[ 0 ] );
}
+ else
+ return;
break;
}
- case 2: { // EDGE
- if ( nbSame == 0 )
- aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
- nextNod[ 1 ], nextNod[ 0 ] );
- else
- aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
- nextNod[ iNotSameNode ] );
+ case SMDSEntity_Edge: { // sweep EDGE
+ if ( nbDouble == 0 )
+ {
+ if ( nbSame == 0 ) // ---> quadrangle
+ aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
+ nextNod[ 1 ], nextNod[ 0 ] );
+ else // ---> triangle
+ aNewElem = aMesh->AddFace(prevNod[ 0 ], prevNod[ 1 ],
+ nextNod[ iNotSameNode ] );
+ }
+ else // ---> polygon
+ {
+ vector<const SMDS_MeshNode*> poly_nodes;
+ poly_nodes.push_back( prevNod[0] );
+ poly_nodes.push_back( prevNod[1] );
+ if ( prevNod[1] != nextNod[1] )
+ {
+ if ( midlNod[1]) poly_nodes.push_back( midlNod[1]);
+ poly_nodes.push_back( nextNod[1] );
+ }
+ if ( prevNod[0] != nextNod[0] )
+ {
+ poly_nodes.push_back( nextNod[0] );
+ if ( midlNod[0]) poly_nodes.push_back( midlNod[0]);
+ }
+ switch ( poly_nodes.size() ) {
+ case 3:
+ aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ], poly_nodes[ 2 ]);
+ break;
+ case 4:
+ aNewElem = aMesh->AddFace( poly_nodes[ 0 ], poly_nodes[ 1 ],
+ poly_nodes[ 2 ], poly_nodes[ 3 ]);
+ break;
+ default:
+ aNewElem = aMesh->AddPolygonalFace (poly_nodes);
+ }
+ }
break;
}
+ case SMDSEntity_Triangle: // TRIANGLE --->
+ {
+ if ( nbDouble > 0 ) break;
+ if ( nbSame == 0 ) // ---> pentahedron
+ aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
+ nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ] );
+
+ else if ( nbSame == 1 ) // ---> pyramid
+ aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
+ nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
+ nextNod[ iSameNode ]);
- case 3: { // TRIANGLE or quadratic edge
- if(elem->GetType() == SMDSAbs_Face) { // TRIANGLE
-
- if ( nbSame == 0 ) // --- pentahedron
- aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
- nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ] );
-
- else if ( nbSame == 1 ) // --- pyramid
- aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
- nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
- nextNod[ iSameNode ]);
-
- else // 2 same nodes: --- tetrahedron
- aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ],
+ else // 2 same nodes: ---> tetrahedron
+ aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ],
nextNod[ iNotSameNode ]);
+ break;
}
- else { // quadratic edge
- if(nbSame==0) { // quadratic quadrangle
- aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], nextNod[1], prevNod[1],
- midlNod[0], nextNod[2], midlNod[1], prevNod[2]);
- }
- else if(nbSame==1) { // quadratic triangle
- if(sames[0]==2) {
- return; // medium node on axis
+ case SMDSEntity_Quad_Edge: // sweep quadratic EDGE --->
+ {
+ if ( nbSame == 2 )
+ return;
+ if ( nbDouble+nbSame == 2 )
+ {
+ if(nbSame==0) { // ---> quadratic quadrangle
+ aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
+ prevNod[2], midlNod[1], nextNod[2], midlNod[0]);
}
- else if(sames[0]==0) {
- aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
- nextNod[2], midlNod[1], prevNod[2]);
+ else { //(nbSame==1) // ---> quadratic triangle
+ if(sames[0]==2) {
+ return; // medium node on axis
+ }
+ else if(sames[0]==0)
+ aNewElem = aMesh->AddFace(prevNod[0], nextNod[1], prevNod[1],
+ nextNod[2], midlNod[1], prevNod[2]);
+ else // sames[0]==1
+ aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
+ midlNod[0], nextNod[2], prevNod[2]);
}
- else { // sames[0]==1
- aNewElem = aMesh->AddFace(prevNod[0], nextNod[0], prevNod[1],
- midlNod[0], nextNod[2], prevNod[2]);
+ }
+ else if ( nbDouble == 3 )
+ {
+ if ( nbSame == 0 ) { // ---> bi-quadratic quadrangle
+ aNewElem = aMesh->AddFace(prevNod[0], prevNod[1], nextNod[1], nextNod[0],
+ prevNod[2], midlNod[1], nextNod[2], midlNod[0], midlNod[2]);
}
}
- else {
+ else
return;
- }
+ break;
}
- break;
- }
- case 4: { // QUADRANGLE
+ case SMDSEntity_Quadrangle: { // sweep QUADRANGLE --->
+ if ( nbDouble > 0 ) break;
- if ( nbSame == 0 ) // --- hexahedron
- aNewElem = aMesh->AddVolume (prevNod[ i0 ], prevNod[ 1 ], prevNod[ i2 ], prevNod[ 3 ],
- nextNod[ i0 ], nextNod[ 1 ], nextNod[ i2 ], nextNod[ 3 ]);
+ if ( nbSame == 0 ) // ---> hexahedron
+ aNewElem = aMesh->AddVolume (prevNod[ 0 ], prevNod[ 1 ], prevNod[ 2 ], prevNod[ 3 ],
+ nextNod[ 0 ], nextNod[ 1 ], nextNod[ 2 ], nextNod[ 3 ]);
- else if ( nbSame == 1 ) { // --- pyramid + pentahedron
- aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
- nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
+ else if ( nbSame == 1 ) { // ---> pyramid + pentahedron
+ aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iAfterSame ],
+ nextNod[ iAfterSame ], nextNod[ iBeforeSame ],
nextNod[ iSameNode ]);
newElems.push_back( aNewElem );
- aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
- prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
+ aNewElem = aMesh->AddVolume (prevNod[ iAfterSame ], prevNod[ iOpposSame ],
+ prevNod[ iBeforeSame ], nextNod[ iAfterSame ],
nextNod[ iOpposSame ], nextNod[ iBeforeSame ] );
}
- else if ( nbSame == 2 ) { // pentahedron
+ else if ( nbSame == 2 ) { // ---> pentahedron
if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] )
// iBeforeSame is same too
aNewElem = aMesh->AddVolume (prevNod[ iBeforeSame ], prevNod[ iOpposSame ],
- nextNod[ iOpposSame ], prevNod[ iSameNode ],
+ nextNod[ iOpposSame ], prevNod[ iSameNode ],
prevNod[ iAfterSame ], nextNod[ iAfterSame ]);
else
// iAfterSame is same too
- aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
+ aNewElem = aMesh->AddVolume (prevNod[ iSameNode ], prevNod[ iBeforeSame ],
nextNod[ iBeforeSame ], prevNod[ iAfterSame ],
prevNod[ iOpposSame ], nextNod[ iOpposSame ]);
}
break;
}
- case 6: { // quadratic triangle
- // create pentahedron with 15 nodes
+ case SMDSEntity_Quad_Triangle: { // sweep Quadratic TRIANGLE --->
+ if ( nbDouble+nbSame != 3 ) break;
if(nbSame==0) {
- if(i0>0) { // reversed case
- aNewElem = aMesh->AddVolume (prevNod[0], prevNod[2], prevNod[1],
- nextNod[0], nextNod[2], nextNod[1],
- prevNod[5], prevNod[4], prevNod[3],
- nextNod[5], nextNod[4], nextNod[3],
- midlNod[0], midlNod[2], midlNod[1]);
- }
- else { // not reversed case
- aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
- nextNod[0], nextNod[1], nextNod[2],
- prevNod[3], prevNod[4], prevNod[5],
- nextNod[3], nextNod[4], nextNod[5],
- midlNod[0], midlNod[1], midlNod[2]);
- }
+ // ---> pentahedron with 15 nodes
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
+ nextNod[0], nextNod[1], nextNod[2],
+ prevNod[3], prevNod[4], prevNod[5],
+ nextNod[3], nextNod[4], nextNod[5],
+ midlNod[0], midlNod[1], midlNod[2]);
}
else if(nbSame==1) {
- // 2d order pyramid of 13 nodes
- //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5,
- // int n12,int n23,int n34,int n41,
- // int n15,int n25,int n35,int n45, int ID);
- int n5 = iSameNode;
- int n1,n4,n41,n15,n45;
- if(i0>0) { // reversed case
- n1 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
- n4 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
- n41 = n1 + 3;
- n15 = n5 + 3;
- n45 = n4 + 3;
- }
- else {
- n1 = ( n5 == 0 ? nbBaseNodes - 1 : n5 - 1 );
- n4 = ( n5 + 1 == nbBaseNodes ? 0 : n5 + 1 );
- n41 = n4 + 3;
- n15 = n1 + 3;
- n45 = n5 + 3;
- }
- aNewElem = aMesh->AddVolume(prevNod[n1], nextNod[n1],
- nextNod[n4], prevNod[n4], prevNod[n5],
- midlNod[n1], nextNod[n41],
- midlNod[n4], prevNod[n41],
- prevNod[n15], nextNod[n15],
- nextNod[n45], prevNod[n45]);
+ // ---> 2d order pyramid of 13 nodes
+ int apex = iSameNode;
+ int i0 = ( apex + 1 ) % nbCorners;
+ int i1 = ( apex - 1 + nbCorners ) % nbCorners;
+ int i0a = apex + 3;
+ int i1a = i1 + 3;
+ int i01 = i0 + 3;
+ aNewElem = aMesh->AddVolume(prevNod[i1], prevNod[i0],
+ nextNod[i0], nextNod[i1], prevNod[apex],
+ prevNod[i01], midlNod[i0],
+ nextNod[i01], midlNod[i1],
+ prevNod[i1a], prevNod[i0a],
+ nextNod[i0a], nextNod[i1a]);
}
else if(nbSame==2) {
- // 2d order tetrahedron of 10 nodes
- //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4,
- // int n12,int n23,int n31,
- // int n14,int n24,int n34, int ID);
+ // ---> 2d order tetrahedron of 10 nodes
int n1 = iNotSameNode;
- int n2,n3,n12,n23,n31;
- if(i0>0) { // reversed case
- n2 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
- n3 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
- n12 = n2 + 3;
- n23 = n3 + 3;
- n31 = n1 + 3;
- }
- else {
- n2 = ( n1 + 1 == nbBaseNodes ? 0 : n1 + 1 );
- n3 = ( n1 == 0 ? nbBaseNodes - 1 : n1 - 1 );
- n12 = n1 + 3;
- n23 = n2 + 3;
- n31 = n3 + 3;
- }
+ int n2 = ( n1 + 1 ) % nbCorners;
+ int n3 = ( n1 + nbCorners - 1 ) % nbCorners;
+ int n12 = n1 + 3;
+ int n23 = n2 + 3;
+ int n31 = n3 + 3;
aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], prevNod[n3], nextNod[n1],
prevNod[n12], prevNod[n23], prevNod[n31],
midlNod[n1], nextNod[n12], nextNod[n31]);
}
break;
}
- case 8: { // quadratic quadrangle
- if(nbSame==0) {
- // create hexahedron with 20 nodes
- if(i0>0) { // reversed case
- aNewElem = aMesh->AddVolume (prevNod[0], prevNod[3], prevNod[2], prevNod[1],
- nextNod[0], nextNod[3], nextNod[2], nextNod[1],
- prevNod[7], prevNod[6], prevNod[5], prevNod[4],
- nextNod[7], nextNod[6], nextNod[5], nextNod[4],
- midlNod[0], midlNod[3], midlNod[2], midlNod[1]);
- }
- else { // not reversed case
- aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
- nextNod[0], nextNod[1], nextNod[2], nextNod[3],
- prevNod[4], prevNod[5], prevNod[6], prevNod[7],
- nextNod[4], nextNod[5], nextNod[6], nextNod[7],
- midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
- }
+ case SMDSEntity_Quad_Quadrangle: { // sweep Quadratic QUADRANGLE --->
+ if( nbSame == 0 ) {
+ if ( nbDouble != 4 ) break;
+ // ---> hexahedron with 20 nodes
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
+ nextNod[0], nextNod[1], nextNod[2], nextNod[3],
+ prevNod[4], prevNod[5], prevNod[6], prevNod[7],
+ nextNod[4], nextNod[5], nextNod[6], nextNod[7],
+ midlNod[0], midlNod[1], midlNod[2], midlNod[3]);
}
- else if(nbSame==1) {
- // --- pyramid + pentahedron - can not be created since it is needed
- // additional middle node ot the center of face
+ else if(nbSame==1) {
+ // ---> pyramid + pentahedron - can not be created since it is needed
+ // additional middle node at the center of face
INFOS( " Sweep for face " << elem->GetID() << " can not be created" );
return;
}
- else if(nbSame==2) {
- // 2d order Pentahedron with 15 nodes
- //SMDS_MeshVolume* AddVolumeWithID(int n1, int n2, int n3, int n4, int n5, int n6,
- // int n12,int n23,int n31,int n45,int n56,int n64,
- // int n14,int n25,int n36, int ID);
+ else if( nbSame == 2 ) {
+ if ( nbDouble != 2 ) break;
+ // ---> 2d order Pentahedron with 15 nodes
int n1,n2,n4,n5;
if ( prevNod[ iBeforeSame ] == nextNod[ iBeforeSame ] ) {
// iBeforeSame is same too
n4 = iAfterSame;
n5 = iOpposSame;
}
- int n12,n45,n14,n25;
- if(i0>0) { //reversed case
- n12 = n1 + 4;
- n45 = n5 + 4;
- n14 = n4 + 4;
- n25 = n2 + 4;
- }
- else {
- n12 = n2 + 4;
- n45 = n4 + 4;
- n14 = n1 + 4;
- n25 = n5 + 4;
- }
+ int n12 = n2 + 4;
+ int n45 = n4 + 4;
+ int n14 = n1 + 4;
+ int n25 = n5 + 4;
aNewElem = aMesh->AddVolume (prevNod[n1], prevNod[n2], nextNod[n2],
prevNod[n4], prevNod[n5], nextNod[n5],
prevNod[n12], midlNod[n2], nextNod[n12],
}
break;
}
- default: {
- // realized for extrusion only
- //vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
- //vector<int> quantities (nbNodes + 2);
-
- //quantities[0] = nbNodes; // bottom of prism
- //for (int inode = 0; inode < nbNodes; inode++) {
- // polyedre_nodes[inode] = prevNod[inode];
- //}
-
- //quantities[1] = nbNodes; // top of prism
- //for (int inode = 0; inode < nbNodes; inode++) {
- // polyedre_nodes[nbNodes + inode] = nextNod[inode];
- //}
-
- //for (int iface = 0; iface < nbNodes; iface++) {
- // quantities[iface + 2] = 4;
- // int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
- // polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
- // polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
- // polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
- // polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
- //}
- //aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
+ case SMDSEntity_BiQuad_Quadrangle: { // sweep BiQuadratic QUADRANGLE --->
+
+ if( nbSame == 0 && nbDouble == 9 ) {
+ // ---> tri-quadratic hexahedron with 27 nodes
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2], prevNod[3],
+ nextNod[0], nextNod[1], nextNod[2], nextNod[3],
+ prevNod[4], prevNod[5], prevNod[6], prevNod[7],
+ nextNod[4], nextNod[5], nextNod[6], nextNod[7],
+ midlNod[0], midlNod[1], midlNod[2], midlNod[3],
+ prevNod[8], // bottom center
+ midlNod[4], midlNod[5], midlNod[6], midlNod[7],
+ nextNod[8], // top center
+ midlNod[8]);// elem center
+ }
+ else
+ {
+ return;
+ }
break;
}
- }
- }
-
- if(!aNewElem) {
- // realized for extrusion only
- vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
- vector<int> quantities (nbNodes + 2);
+ case SMDSEntity_Polygon: { // sweep POLYGON
- quantities[0] = nbNodes; // bottom of prism
- for (int inode = 0; inode < nbNodes; inode++) {
- polyedre_nodes[inode] = prevNod[inode];
+ if ( nbNodes == 6 && nbSame == 0 && nbDouble == 0 ) {
+ // ---> hexagonal prism
+ aNewElem = aMesh->AddVolume (prevNod[0], prevNod[1], prevNod[2],
+ prevNod[3], prevNod[4], prevNod[5],
+ nextNod[0], nextNod[1], nextNod[2],
+ nextNod[3], nextNod[4], nextNod[5]);
+ }
+ break;
}
+ case SMDSEntity_Ball:
+ return;
- quantities[1] = nbNodes; // top of prism
- for (int inode = 0; inode < nbNodes; inode++) {
- polyedre_nodes[nbNodes + inode] = nextNod[inode];
+ default:
+ break;
}
+ }
- for (int iface = 0; iface < nbNodes; iface++) {
- quantities[iface + 2] = 4;
- int inextface = (iface == nbNodes - 1) ? 0 : iface + 1;
- polyedre_nodes[2*nbNodes + 4*iface + 0] = prevNod[iface];
- polyedre_nodes[2*nbNodes + 4*iface + 1] = prevNod[inextface];
- polyedre_nodes[2*nbNodes + 4*iface + 2] = nextNod[inextface];
- polyedre_nodes[2*nbNodes + 4*iface + 3] = nextNod[iface];
+ if ( !aNewElem && elem->GetType() == SMDSAbs_Face ) // try to create a polyherdal prism
+ {
+ if ( baseType != SMDSEntity_Polygon )
+ {
+ const std::vector<int>& ind = SMDS_MeshCell::interlacedSmdsOrder(baseType);
+ SMDS_MeshCell::applyInterlace( ind, prevNod );
+ SMDS_MeshCell::applyInterlace( ind, nextNod );
+ SMDS_MeshCell::applyInterlace( ind, midlNod );
+ SMDS_MeshCell::applyInterlace( ind, itNN );
+ SMDS_MeshCell::applyInterlace( ind, isSingleNode );
+ baseType = SMDSEntity_Polygon; // WARNING: change baseType !!!!
+ }
+ vector<const SMDS_MeshNode*> polyedre_nodes (nbNodes*2 + 4*nbNodes);
+ vector<int> quantities (nbNodes + 2);
+ polyedre_nodes.clear();
+ quantities.clear();
+
+ // bottom of prism
+ for (int inode = 0; inode < nbNodes; inode++)
+ polyedre_nodes.push_back( prevNod[inode] );
+ quantities.push_back( nbNodes );
+
+ // top of prism
+ polyedre_nodes.push_back( nextNod[0] );
+ for (int inode = nbNodes; inode-1; --inode )
+ polyedre_nodes.push_back( nextNod[inode-1] );
+ quantities.push_back( nbNodes );
+
+ // side faces
+ for (int iface = 0; iface < nbNodes; iface++)
+ {
+ const int prevNbNodes = polyedre_nodes.size();
+ int inextface = (iface+1) % nbNodes;
+ polyedre_nodes.push_back( prevNod[inextface] );
+ polyedre_nodes.push_back( prevNod[iface] );
+ if ( prevNod[iface] != nextNod[iface] )
+ {
+ if ( midlNod[ iface ]) polyedre_nodes.push_back( midlNod[ iface ]);
+ polyedre_nodes.push_back( nextNod[iface] );
+ }
+ if ( prevNod[inextface] != nextNod[inextface] )
+ {
+ polyedre_nodes.push_back( nextNod[inextface] );
+ if ( midlNod[ inextface ]) polyedre_nodes.push_back( midlNod[ inextface ]);
+ }
+ const int nbFaceNodes = polyedre_nodes.size() - prevNbNodes;
+ if ( nbFaceNodes > 2 )
+ quantities.push_back( nbFaceNodes );
+ else // degenerated face
+ polyedre_nodes.resize( prevNbNodes );
}
aNewElem = aMesh->AddPolyhedralVolume (polyedre_nodes, quantities);
}
newElems.push_back( aNewElem );
myLastCreatedElems.Append(aNewElem);
srcElements.Append( elem );
- lastElem = aNewElem;
}
// set new prev nodes
const int nbSteps,
SMESH_SequenceOfElemPtr& srcElements)
{
- MESSAGE("makeWalls");
ASSERT( newElemsMap.size() == elemNewNodesMap.size() );
SMESHDS_Mesh* aMesh = GetMeshDS();
// Find nodes belonging to only one initial element - sweep them to get edges.
TNodeOfNodeListMapItr nList = mapNewNodes.begin();
- for ( ; nList != mapNewNodes.end(); nList++ ) {
+ for ( ; nList != mapNewNodes.end(); nList++ )
+ {
const SMDS_MeshNode* node =
static_cast<const SMDS_MeshNode*>( nList->first );
+ if ( newElemsMap.count( node ))
+ continue; // node was extruded into edge
SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
int nbInitElems = 0;
const SMDS_MeshElement* el = 0;
nbInitElems = 0;
highType = type;
}
- if ( elemSet.find(el) != elemSet.end() )
- nbInitElems++;
+ nbInitElems += elemSet.count(el);
}
if ( nbInitElems < 2 ) {
- bool NotCreateEdge = el && el->IsQuadratic() && el->IsMediumNode(node);
+ bool NotCreateEdge = el && el->IsMediumNode(node);
if(!NotCreateEdge) {
vector<TNodeOfNodeListMapItr> newNodesItVec( 1, nList );
list<const SMDS_MeshElement*> newEdges;
TElemOfElemListMap::iterator itElem = newElemsMap.begin();
TElemOfVecOfNnlmiMap::iterator itElemNodes = elemNewNodesMap.begin();
- for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ ) {
+ for ( ; itElem != newElemsMap.end(); itElem++, itElemNodes++ )
+ {
const SMDS_MeshElement* elem = itElem->first;
vector<TNodeOfNodeListMapItr>& vecNewNodes = itElemNodes->second;
if(itElem->second.size()==0) continue;
+ const bool isQuadratic = elem->IsQuadratic();
+
if ( elem->GetType() == SMDSAbs_Edge ) {
// create a ceiling edge
- if (!elem->IsQuadratic()) {
+ if ( !isQuadratic ) {
if ( !aMesh->FindEdge( vecNewNodes[ 0 ]->second.back(),
vecNewNodes[ 1 ]->second.back())) {
myLastCreatedElems.Append(aMesh->AddEdge(vecNewNodes[ 0 ]->second.back(),
set<const SMDS_MeshNode*> aFaceLastNodes;
int iNode, nbNodes = vecNewNodes.size();
- if(!elem->IsQuadratic()) {
+ if ( !isQuadratic ) {
// loop on the face nodes
for ( iNode = 0; iNode < nbNodes; iNode++ ) {
aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
int iNext = ( iNode + 1 == nbn ) ? 0 : iNode + 1;
const SMDS_MeshNode* n1 = vecNewNodes[ iNode ]->first;
const SMDS_MeshNode* n2 = vecNewNodes[ iNext ]->first;
+ const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
// check if a link is free
- if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet )) {
+ if ( ! SMESH_MeshEditor::FindFaceInSet ( n1, n2, elemSet, avoidSet ) &&
+ ! SMESH_MeshEditor::FindFaceInSet ( n1, n3, elemSet, avoidSet ) &&
+ ! SMESH_MeshEditor::FindFaceInSet ( n3, n2, elemSet, avoidSet ) ) {
hasFreeLinks = true;
// make an edge and a ceiling for a new edge
// find medium node
- const SMDS_MeshNode* n3 = vecNewNodes[ iNode+nbn ]->first;
if ( !aMesh->FindEdge( n1, n2, n3 )) {
myLastCreatedElems.Append(aMesh->AddEdge( n1, n2, n3 )); // free link edge
srcElements.Append( myLastCreatedElems.Last() );
}
}
}
- for ( iNode = nbn; iNode < 2*nbn; iNode++ ) {
+ for ( iNode = nbn; iNode < nbNodes; iNode++ ) {
aFaceLastNodes.insert( vecNewNodes[ iNode ]->second.back() );
}
}
}
for ( volNb = 0; volNb < nbVolumesByStep; volNb++ ) {
list<const SMDS_MeshElement*>::iterator v = newVolumes.begin();
- iVol = 0;
- while ( iVol++ < volNb ) v++;
+ std::advance( v, volNb );
// find indices of free faces of a volume and their source edges
list< int > freeInd;
list< const SMDS_MeshElement* > srcEdges; // source edges of free faces
- SMDS_VolumeTool vTool( *v );
+ SMDS_VolumeTool vTool( *v, /*ignoreCentralNodes=*/false );
int iF, nbF = vTool.NbFaces();
for ( iF = 0; iF < nbF; iF ++ ) {
if (vTool.IsFreeFace( iF ) &&
// create faces for all steps;
// if such a face has been already created by sweep of edge,
// assure that its orientation is OK
- for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
- vTool.Set( *v );
+ for ( int iStep = 0; iStep < nbSteps; iStep++ ) {
+ vTool.Set( *v, /*ignoreCentralNodes=*/false );
vTool.SetExternalNormal();
+ const int nextShift = vTool.IsForward() ? +1 : -1;
list< int >::iterator ind = freeInd.begin();
list< const SMDS_MeshElement* >::iterator srcEdge = srcEdges.begin();
for ( ; ind != freeInd.end(); ++ind, ++srcEdge ) // loop on free faces
{
const SMDS_MeshNode** nodes = vTool.GetFaceNodes( *ind );
int nbn = vTool.NbFaceNodes( *ind );
- switch ( nbn ) {
- case 3: { ///// triangle
- const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
- if ( !f )
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
- else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
- {
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
- aMesh->RemoveElement(f);
- }
- break;
+ const SMDS_MeshElement * f = 0;
+ if ( nbn == 3 ) ///// triangle
+ {
+ f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]);
+ if ( !f ||
+ nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
+ {
+ const SMDS_MeshNode* newOrder[3] = { nodes[ 1 - nextShift ],
+ nodes[ 1 ],
+ nodes[ 1 + nextShift ] };
+ if ( f )
+ aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+ else
+ myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
+ newOrder[ 2 ] ));
+ }
}
- case 4: { ///// quadrangle
- const SMDS_MeshFace * f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
- if ( !f )
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
- else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
- {
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
- aMesh->RemoveElement(f);
- }
- break;
+ else if ( nbn == 4 ) ///// quadrangle
+ {
+ f = aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]);
+ if ( !f ||
+ nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ]) + nextShift ))
+ {
+ const SMDS_MeshNode* newOrder[4] = { nodes[ 0 ], nodes[ 2-nextShift ],
+ nodes[ 2 ], nodes[ 2+nextShift ] };
+ if ( f )
+ aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+ else
+ myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ], newOrder[ 1 ],
+ newOrder[ 2 ], newOrder[ 3 ]));
+ }
}
- default:
- if( (*v)->IsQuadratic() ) {
- if(nbn==6) { /////// quadratic triangle
- const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4],
- nodes[1], nodes[3], nodes[5] );
- if ( !f ) {
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
- nodes[1], nodes[3], nodes[5]));
- }
- else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
- const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[6];
- tmpnodes[0] = nodes[0];
- tmpnodes[1] = nodes[2];
- tmpnodes[2] = nodes[4];
- tmpnodes[3] = nodes[1];
- tmpnodes[4] = nodes[3];
- tmpnodes[5] = nodes[5];
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
- nodes[1], nodes[3], nodes[5]));
- aMesh->RemoveElement(f);
- }
- }
- else { /////// quadratic quadrangle
- const SMDS_MeshFace * f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7] );
- if ( !f ) {
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7]));
- }
- else if ( nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 )) {
- const SMDS_MeshNode** tmpnodes = new const SMDS_MeshNode*[8];
- tmpnodes[0] = nodes[0];
- tmpnodes[1] = nodes[2];
- tmpnodes[2] = nodes[4];
- tmpnodes[3] = nodes[6];
- tmpnodes[4] = nodes[1];
- tmpnodes[5] = nodes[3];
- tmpnodes[6] = nodes[5];
- tmpnodes[7] = nodes[7];
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7]));
- aMesh->RemoveElement(f);
- }
- }
+ else if ( nbn == 6 && isQuadratic ) /////// quadratic triangle
+ {
+ f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5] );
+ if ( !f ||
+ nodes[2] != f->GetNodeWrap( f->GetNodeIndex( nodes[0] ) + 2*nextShift ))
+ {
+ const SMDS_MeshNode* newOrder[6] = { nodes[2 - 2*nextShift],
+ nodes[2],
+ nodes[2 + 2*nextShift],
+ nodes[3 - 2*nextShift],
+ nodes[3],
+ nodes[3 + 2*nextShift]};
+ if ( f )
+ aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+ else
+ myLastCreatedElems.Append(aMesh->AddFace( newOrder[ 0 ],
+ newOrder[ 1 ],
+ newOrder[ 2 ],
+ newOrder[ 3 ],
+ newOrder[ 4 ],
+ newOrder[ 5 ] ));
}
- else { //////// polygon
- vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
- const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
- if ( !f )
- myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
- else if ( nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 1 ))
- {
- // TODO problem ChangeElementNodes : not the same number of nodes, not the same type
- MESSAGE("ChangeElementNodes");
- aMesh->ChangeElementNodes( f, nodes, nbn );
- }
+ }
+ else if ( nbn == 8 && isQuadratic ) /////// quadratic quadrangle
+ {
+ f = aMesh->FindFace( nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7] );
+ if ( !f ||
+ nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
+ {
+ const SMDS_MeshNode* newOrder[8] = { nodes[0],
+ nodes[4 - 2*nextShift],
+ nodes[4],
+ nodes[4 + 2*nextShift],
+ nodes[1],
+ nodes[5 - 2*nextShift],
+ nodes[5],
+ nodes[5 + 2*nextShift] };
+ if ( f )
+ aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+ else
+ myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
+ newOrder[ 2 ], newOrder[ 3 ],
+ newOrder[ 4 ], newOrder[ 5 ],
+ newOrder[ 6 ], newOrder[ 7 ]));
+ }
+ }
+ else if ( nbn == 9 && isQuadratic ) /////// bi-quadratic quadrangle
+ {
+ f = aMesh->FindElement( vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
+ SMDSAbs_Face, /*noMedium=*/false);
+ if ( !f ||
+ nodes[ 2 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + 2*nextShift ))
+ {
+ const SMDS_MeshNode* newOrder[9] = { nodes[0],
+ nodes[4 - 2*nextShift],
+ nodes[4],
+ nodes[4 + 2*nextShift],
+ nodes[1],
+ nodes[5 - 2*nextShift],
+ nodes[5],
+ nodes[5 + 2*nextShift],
+ nodes[8] };
+ if ( f )
+ aMesh->ChangeElementNodes( f, &newOrder[0], nbn );
+ else
+ myLastCreatedElems.Append(aMesh->AddFace(newOrder[ 0 ], newOrder[ 1 ],
+ newOrder[ 2 ], newOrder[ 3 ],
+ newOrder[ 4 ], newOrder[ 5 ],
+ newOrder[ 6 ], newOrder[ 7 ],
+ newOrder[ 8 ]));
+ }
+ }
+ else //////// polygon
+ {
+ vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes+nbn );
+ const SMDS_MeshFace * f = aMesh->FindFace( polygon_nodes );
+ if ( !f ||
+ nodes[ 1 ] != f->GetNodeWrap( f->GetNodeIndex( nodes[ 0 ] ) + nextShift ))
+ {
+ if ( !vTool.IsForward() )
+ std::reverse( polygon_nodes.begin(), polygon_nodes.end());
+ if ( f )
+ aMesh->ChangeElementNodes( f, &polygon_nodes[0], nbn );
+ else
+ AddElement(polygon_nodes, SMDSAbs_Face, polygon_nodes.size()>4);
}
}
+
while ( srcElements.Length() < myLastCreatedElems.Length() )
srcElements.Append( *srcEdge );
// go to the next volume
iVol = 0;
while ( iVol++ < nbVolumesByStep ) v++;
- }
- }
+
+ } // loop on steps
+ } // loop on volumes of one step
} // sweep free links into faces
// Make a ceiling face with a normal external to a volume
- SMDS_VolumeTool lastVol( itElem->second.back() );
+ SMDS_VolumeTool lastVol( itElem->second.back(), /*ignoreCentralNodes=*/false );
int iF = lastVol.GetFaceIndex( aFaceLastNodes );
if ( iF >= 0 ) {
lastVol.SetExternalNormal();
const SMDS_MeshNode** nodes = lastVol.GetFaceNodes( iF );
int nbn = lastVol.NbFaceNodes( iF );
- switch ( nbn ) {
- case 3:
+ if ( nbn == 3 ) {
if (!hasFreeLinks ||
!aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ]))
myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ] ));
- break;
- case 4:
+ }
+ else if ( nbn == 4 )
+ {
if (!hasFreeLinks ||
!aMesh->FindFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]))
- myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ] ));
- break;
- default:
- if(itElem->second.back()->IsQuadratic()) {
- if(nbn==6) {
- if (!hasFreeLinks ||
- !aMesh->FindFace(nodes[0], nodes[2], nodes[4],
- nodes[1], nodes[3], nodes[5]) ) {
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
- nodes[1], nodes[3], nodes[5]));
- }
- }
- else { // nbn==8
- if (!hasFreeLinks ||
- !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7]) )
- myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
- nodes[1], nodes[3], nodes[5], nodes[7]));
- }
- }
- else {
- vector<const SMDS_MeshNode*> polygon_nodes ( nodes, &nodes[nbn] );
- if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
- myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
- }
- } // switch
+ myLastCreatedElems.Append(aMesh->AddFace( nodes[ 0 ], nodes[ 1 ], nodes[ 2 ], nodes[ 3 ]));
+ }
+ else if ( nbn == 6 && isQuadratic )
+ {
+ if (!hasFreeLinks ||
+ !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[1], nodes[3], nodes[5]) )
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4],
+ nodes[1], nodes[3], nodes[5]));
+ }
+ else if ( nbn == 8 && isQuadratic )
+ {
+ if (!hasFreeLinks ||
+ !aMesh->FindFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]) )
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7]));
+ }
+ else if ( nbn == 9 && isQuadratic )
+ {
+ if (!hasFreeLinks ||
+ !aMesh->FindElement(vector<const SMDS_MeshNode*>( nodes, nodes+nbn ),
+ SMDSAbs_Face, /*noMedium=*/false) )
+ myLastCreatedElems.Append(aMesh->AddFace(nodes[0], nodes[2], nodes[4], nodes[6],
+ nodes[1], nodes[3], nodes[5], nodes[7],
+ nodes[8]));
+ }
+ else {
+ vector<const SMDS_MeshNode*> polygon_nodes ( nodes, nodes + nbn );
+ if (!hasFreeLinks || !aMesh->FindFace(polygon_nodes))
+ myLastCreatedElems.Append(aMesh->AddPolygonalFace(polygon_nodes));
+ }
while ( srcElements.Length() < myLastCreatedElems.Length() )
srcElements.Append( myLastCreatedElems.Last() );
TElemOfVecOfNnlmiMap mapElemNewNodes;
TElemOfElemListMap newElemsMap;
+ const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
+ myMesh->NbFaces(ORDER_QUADRATIC) +
+ myMesh->NbVolumes(ORDER_QUADRATIC) );
// loop on theElems
TIDSortedElemSet::iterator itElem;
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
// loop on elem nodes
SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() ) {
+ while ( itN->more() )
+ {
// check if a node has been already sweeped
const SMDS_MeshNode* node = cast2Node( itN->next() );
aXYZ.Coord( coord[0], coord[1], coord[2] );
bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
- TNodeOfNodeListMapItr nIt = mapNewNodes.find( node );
- if ( nIt == mapNewNodes.end() ) {
- nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
- list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+ TNodeOfNodeListMapItr nIt =
+ mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+ list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+ if ( listNewNodes.empty() )
+ {
+ // check if we are to create medium nodes between corner ones
+ bool needMediumNodes = false;
+ if ( isQuadraticMesh )
+ {
+ SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
+ while (it->more() && !needMediumNodes )
+ {
+ const SMDS_MeshElement* invElem = it->next();
+ if ( invElem != elem && !theElems.count( invElem )) continue;
+ needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
+ if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+ needMediumNodes = true;
+ }
+ }
// make new nodes
- //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
- //double coord[3];
- //aXYZ.Coord( coord[0], coord[1], coord[2] );
- //bool isOnAxis = ( aLine.SquareDistance( aXYZ ) <= aSqTol );
const SMDS_MeshNode * newNode = node;
for ( int i = 0; i < theNbSteps; i++ ) {
if ( !isOnAxis ) {
- if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
- // create two nodes
+ if ( needMediumNodes ) // create a medium node
+ {
aTrsf2.Transforms( coord[0], coord[1], coord[2] );
- //aTrsf.Transforms( coord[0], coord[1], coord[2] );
newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
myLastCreatedNodes.Append(newNode);
srcNodes.Append( node );
listNewNodes.push_back( newNode );
aTrsf2.Transforms( coord[0], coord[1], coord[2] );
- //aTrsf.Transforms( coord[0], coord[1], coord[2] );
}
else {
aTrsf.Transforms( coord[0], coord[1], coord[2] );
}
+ // create a corner node
newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
myLastCreatedNodes.Append(newNode);
srcNodes.Append( node );
}
else {
listNewNodes.push_back( newNode );
- if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
- listNewNodes.push_back( newNode );
- }
+ // if ( needMediumNodes )
+ // listNewNodes.push_back( newNode );
}
}
}
- /*
- else {
- // if current elem is quadratic and current node is not medium
- // we have to check - may be it is needed to insert additional nodes
- if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
- list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
- if(listNewNodes.size()==theNbSteps) {
- listNewNodes.clear();
- // make new nodes
- //gp_XYZ aXYZ( node->X(), node->Y(), node->Z() );
- //double coord[3];
- //aXYZ.Coord( coord[0], coord[1], coord[2] );
- const SMDS_MeshNode * newNode = node;
- if ( !isOnAxis ) {
- for(int i = 0; i<theNbSteps; i++) {
- aTrsf2.Transforms( coord[0], coord[1], coord[2] );
- newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
- cout<<" 3 AddNode: "<<newNode;
- myLastCreatedNodes.Append(newNode);
- listNewNodes.push_back( newNode );
- srcNodes.Append( node );
- aTrsf2.Transforms( coord[0], coord[1], coord[2] );
- newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
- cout<<" 4 AddNode: "<<newNode;
- myLastCreatedNodes.Append(newNode);
- srcNodes.Append( node );
- listNewNodes.push_back( newNode );
- }
- }
- else {
- listNewNodes.push_back( newNode );
- }
- }
- }
- }
- */
newNodesItVec.push_back( nIt );
}
// make new elements
const double tolnode,
SMESH_SequenceOfNode& aNodes)
{
- myLastCreatedElems.Clear();
- myLastCreatedNodes.Clear();
+ // myLastCreatedElems.Clear();
+ // myLastCreatedNodes.Clear();
gp_Pnt P1(x,y,z);
SMESHDS_Mesh * aMesh = myMesh->GetMeshDS();
// create new node and return it
const SMDS_MeshNode* NewNode = aMesh->AddNode(x,y,z);
- myLastCreatedNodes.Append(NewNode);
+ //myLastCreatedNodes.Append(NewNode);
return NewNode;
}
const int theFlags,
const double theTolerance)
{
- MESSAGE("ExtrusionSweep " << theMakeGroups << " " << theFlags << " " << theTolerance);
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
TElemOfVecOfNnlmiMap mapElemNewNodes;
//TElemOfVecOfMapNodesMap mapElemNewNodes;
+ const bool isQuadraticMesh = bool( myMesh->NbEdges(ORDER_QUADRATIC) +
+ myMesh->NbFaces(ORDER_QUADRATIC) +
+ myMesh->NbVolumes(ORDER_QUADRATIC) );
// loop on theElems
TIDSortedElemSet::iterator itElem;
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
continue;
vector<TNodeOfNodeListMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
- //vector<TNodeOfNodeVecMapItr> & newNodesItVec = mapElemNewNodes[ elem ];
newNodesItVec.reserve( elem->NbNodes() );
// loop on elem nodes
{
// check if a node has been already sweeped
const SMDS_MeshNode* node = cast2Node( itN->next() );
- TNodeOfNodeListMap::iterator nIt = mapNewNodes.find( node );
- //TNodeOfNodeVecMap::iterator nIt = mapNewNodes.find( node );
- if ( nIt == mapNewNodes.end() ) {
- nIt = mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
- //nIt = mapNewNodes.insert( make_pair( node, vector<const SMDS_MeshNode*>() )).first;
- list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
- //vector<const SMDS_MeshNode*>& vecNewNodes = nIt->second;
- //vecNewNodes.reserve(nbsteps);
-
+ TNodeOfNodeListMap::iterator nIt =
+ mapNewNodes.insert( make_pair( node, list<const SMDS_MeshNode*>() )).first;
+ list<const SMDS_MeshNode*>& listNewNodes = nIt->second;
+ if ( listNewNodes.empty() )
+ {
// make new nodes
+
+ // check if we are to create medium nodes between corner ones
+ bool needMediumNodes = false;
+ if ( isQuadraticMesh )
+ {
+ SMDS_ElemIteratorPtr it = node->GetInverseElementIterator();
+ while (it->more() && !needMediumNodes )
+ {
+ const SMDS_MeshElement* invElem = it->next();
+ if ( invElem != elem && !theElems.count( invElem )) continue;
+ needMediumNodes = ( invElem->IsQuadratic() && !invElem->IsMediumNode(node) );
+ if ( !needMediumNodes && invElem->GetEntityType() == SMDSEntity_BiQuad_Quadrangle )
+ needMediumNodes = true;
+ }
+ }
+
double coord[] = { node->X(), node->Y(), node->Z() };
- //int nbsteps = theParams.mySteps->Length();
- for ( int i = 0; i < nbsteps; i++ ) {
- if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
- // create additional node
+ for ( int i = 0; i < nbsteps; i++ )
+ {
+ if ( needMediumNodes ) // create a medium node
+ {
double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1)/2.;
double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1)/2.;
double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1)/2.;
listNewNodes.push_back( newNode );
}
}
- //aTrsf.Transforms( coord[0], coord[1], coord[2] );
+ // create a corner node
coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
theTolerance, theParams.myNodes);
listNewNodes.push_back( newNode );
- //vecNewNodes[i]=newNode;
}
else {
const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
myLastCreatedNodes.Append(newNode);
srcNodes.Append( node );
listNewNodes.push_back( newNode );
- //vecNewNodes[i]=newNode;
- }
- }
- }
- else {
- // if current elem is quadratic and current node is not medium
- // we have to check - may be it is needed to insert additional nodes
- if( elem->IsQuadratic() && !elem->IsMediumNode(node) ) {
- list< const SMDS_MeshNode* > & listNewNodes = nIt->second;
- if(listNewNodes.size()==nbsteps) {
- listNewNodes.clear();
- double coord[] = { node->X(), node->Y(), node->Z() };
- for ( int i = 0; i < nbsteps; i++ ) {
- double x = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
- double y = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
- double z = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
- if( theFlags & EXTRUSION_FLAG_SEW ) {
- const SMDS_MeshNode * newNode = CreateNode(x, y, z,
- theTolerance, theParams.myNodes);
- listNewNodes.push_back( newNode );
- }
- else {
- const SMDS_MeshNode * newNode = aMesh->AddNode(x, y, z);
- myLastCreatedNodes.Append(newNode);
- srcNodes.Append( node );
- listNewNodes.push_back( newNode );
- }
- coord[0] = coord[0] + theParams.myDir.X()*theParams.mySteps->Value(i+1);
- coord[1] = coord[1] + theParams.myDir.Y()*theParams.mySteps->Value(i+1);
- coord[2] = coord[2] + theParams.myDir.Z()*theParams.mySteps->Value(i+1);
- if( theFlags & EXTRUSION_FLAG_SEW ) {
- const SMDS_MeshNode * newNode = CreateNode(coord[0], coord[1], coord[2],
- theTolerance, theParams.myNodes);
- listNewNodes.push_back( newNode );
- }
- else {
- const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
- myLastCreatedNodes.Append(newNode);
- srcNodes.Append( node );
- listNewNodes.push_back( newNode );
- }
- }
}
}
}
return newGroupIDs;
}
-/*
-//=======================================================================
-//class : SMESH_MeshEditor_PathPoint
-//purpose : auxiliary class
-//=======================================================================
-class SMESH_MeshEditor_PathPoint {
-public:
-SMESH_MeshEditor_PathPoint() {
-myPnt.SetCoord(99., 99., 99.);
-myTgt.SetCoord(1.,0.,0.);
-myAngle=0.;
-myPrm=0.;
-}
-void SetPnt(const gp_Pnt& aP3D){
-myPnt=aP3D;
-}
-void SetTangent(const gp_Dir& aTgt){
-myTgt=aTgt;
-}
-void SetAngle(const double& aBeta){
-myAngle=aBeta;
-}
-void SetParameter(const double& aPrm){
-myPrm=aPrm;
-}
-const gp_Pnt& Pnt()const{
-return myPnt;
-}
-const gp_Dir& Tangent()const{
-return myTgt;
-}
-double Angle()const{
-return myAngle;
-}
-double Parameter()const{
-return myPrm;
-}
-
-protected:
-gp_Pnt myPnt;
-gp_Dir myTgt;
-double myAngle;
-double myPrm;
-};
-*/
-
//=======================================================================
//function : ExtrusionAlongTrack
//purpose :
list<SMESH_MeshEditor_PathPoint> fullList;
const TopoDS_Shape& aS = theTrack->GetSubShape();
- // Sub shape for the Pattern must be an Edge or Wire
+ // Sub-shape for the Pattern must be an Edge or Wire
if( aS.ShapeType() == TopAbs_EDGE ) {
aTrackEdge = TopoDS::Edge( aS );
// the Edge must not be degenerated
}
//Extrusion_Error err =
MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
- }
- else if( aS.ShapeType() == TopAbs_WIRE ) {
+ } else if( aS.ShapeType() == TopAbs_WIRE ) {
list< SMESH_subMesh* > LSM;
TopTools_SequenceOfShape Edges;
SMESH_subMeshIteratorPtr itSM = theTrack->getDependsOnIterator(false,true);
list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
int startNid = theN1->GetID();
TColStd_MapOfInteger UsedNums;
+
int NbEdges = Edges.Length();
int i = 1;
for(; i<=NbEdges; i++) {
list<SMESH_MeshEditor_PathPoint> fullList;
const TopoDS_Shape& aS = theTrack->GetShapeToMesh();
- // Sub shape for the Pattern must be an Edge or Wire
- if( aS.ShapeType() == TopAbs_EDGE ) {
- aTrackEdge = TopoDS::Edge( aS );
- // the Edge must not be degenerated
- if ( BRep_Tool::Degenerated( aTrackEdge ) )
- return EXTR_BAD_PATH_SHAPE;
- TopExp::Vertices( aTrackEdge, aV1, aV2 );
- aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN1 = aItN->next();
- aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN2 = aItN->next();
- // starting node must be aN1 or aN2
- if ( !( aN1 == theN1 || aN2 == theN1 ) )
+
+ if( aS == SMESH_Mesh::PseudoShape() ) {
+ //Mesh without shape
+ const SMDS_MeshNode* currentNode = NULL;
+ const SMDS_MeshNode* prevNode = theN1;
+ std::vector<const SMDS_MeshNode*> aNodesList;
+ aNodesList.push_back(theN1);
+ int nbEdges = 0, conn=0;
+ const SMDS_MeshElement* prevElem = NULL;
+ const SMDS_MeshElement* currentElem = NULL;
+ int totalNbEdges = theTrack->NbEdges();
+ SMDS_ElemIteratorPtr nIt;
+
+ //check start node
+ if( !theTrack->GetMeshDS()->Contains(theN1) ) {
return EXTR_BAD_STARTING_NODE;
- aItN = pMeshDS->nodesIterator();
- while ( aItN->more() ) {
- const SMDS_MeshNode* pNode = aItN->next();
- if( pNode==aN1 || pNode==aN2 ) continue;
- const SMDS_EdgePosition* pEPos =
- static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
- double aT = pEPos->GetUParameter();
- aPrms.push_back( aT );
}
- //Extrusion_Error err =
- MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
- }
- else if( aS.ShapeType() == TopAbs_WIRE ) {
- list< SMESH_subMesh* > LSM;
- TopTools_SequenceOfShape Edges;
- TopExp_Explorer eExp(aS, TopAbs_EDGE);
- for(; eExp.More(); eExp.Next()) {
- TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
- if( BRep_Tool::Degenerated(E) ) continue;
- SMESH_subMesh* SM = theTrack->GetSubMesh(E);
- if(SM) {
- LSM.push_back(SM);
- Edges.Append(E);
+
+ conn = nbEdgeConnectivity(theN1);
+ if(conn > 2)
+ return EXTR_PATH_NOT_EDGE;
+
+ aItE = theN1->GetInverseElementIterator();
+ prevElem = aItE->next();
+ currentElem = prevElem;
+ //Get all nodes
+ if(totalNbEdges == 1 ) {
+ nIt = currentElem->nodesIterator();
+ currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
+ if(currentNode == prevNode)
+ currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
+ aNodesList.push_back(currentNode);
+ } else {
+ nIt = currentElem->nodesIterator();
+ while( nIt->more() ) {
+ currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
+ if(currentNode == prevNode)
+ currentNode = static_cast<const SMDS_MeshNode*>(nIt->next());
+ aNodesList.push_back(currentNode);
+
+ //case of the closed mesh
+ if(currentNode == theN1) {
+ nbEdges++;
+ break;
+ }
+
+ conn = nbEdgeConnectivity(currentNode);
+ if(conn > 2) {
+ return EXTR_PATH_NOT_EDGE;
+ }else if( conn == 1 && nbEdges > 0 ) {
+ //End of the path
+ nbEdges++;
+ break;
+ }else {
+ prevNode = currentNode;
+ aItE = currentNode->GetInverseElementIterator();
+ currentElem = aItE->next();
+ if( currentElem == prevElem)
+ currentElem = aItE->next();
+ nIt = currentElem->nodesIterator();
+ prevElem = currentElem;
+ nbEdges++;
+ }
}
}
+
+ if(nbEdges != totalNbEdges)
+ return EXTR_PATH_NOT_EDGE;
+
+ TopTools_SequenceOfShape Edges;
+ double x1,x2,y1,y2,z1,z2;
list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
int startNid = theN1->GetID();
- TColStd_MapOfInteger UsedNums;
- int NbEdges = Edges.Length();
+ for(int i = 1; i < aNodesList.size(); i++) {
+ x1 = aNodesList[i-1]->X();x2 = aNodesList[i]->X();
+ y1 = aNodesList[i-1]->Y();y2 = aNodesList[i]->Y();
+ z1 = aNodesList[i-1]->Z();z2 = aNodesList[i]->Z();
+ TopoDS_Edge e = BRepBuilderAPI_MakeEdge(gp_Pnt(x1,y1,z1),gp_Pnt(x2,y2,z2));
+ list<SMESH_MeshEditor_PathPoint> LPP;
+ aPrms.clear();
+ MakeEdgePathPoints(aPrms, e, (aNodesList[i-1]->GetID()==startNid), LPP);
+ LLPPs.push_back(LPP);
+ if( aNodesList[i-1]->GetID() == startNid ) startNid = aNodesList[i]->GetID();
+ else startNid = aNodesList[i-1]->GetID();
+
+ }
+
+ list< list<SMESH_MeshEditor_PathPoint> >::iterator itLLPP = LLPPs.begin();
+ list<SMESH_MeshEditor_PathPoint> firstList = *itLLPP;
+ list<SMESH_MeshEditor_PathPoint>::iterator itPP = firstList.begin();
+ for(; itPP!=firstList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+
+ SMESH_MeshEditor_PathPoint PP1 = fullList.back();
+ SMESH_MeshEditor_PathPoint PP2;
+ fullList.pop_back();
+ itLLPP++;
+ for(; itLLPP!=LLPPs.end(); itLLPP++) {
+ list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
+ itPP = currList.begin();
+ PP2 = currList.front();
+ gp_Dir D1 = PP1.Tangent();
+ gp_Dir D2 = PP2.Tangent();
+ gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
+ (D1.Z()+D2.Z())/2 ) );
+ PP1.SetTangent(Dnew);
+ fullList.push_back(PP1);
+ itPP++;
+ for(; itPP!=currList.end(); itPP++) {
+ fullList.push_back( *itPP );
+ }
+ PP1 = fullList.back();
+ fullList.pop_back();
+ }
+ fullList.push_back(PP1);
+
+ } // Sub-shape for the Pattern must be an Edge or Wire
+ else if( aS.ShapeType() == TopAbs_EDGE ) {
+ aTrackEdge = TopoDS::Edge( aS );
+ // the Edge must not be degenerated
+ if ( BRep_Tool::Degenerated( aTrackEdge ) )
+ return EXTR_BAD_PATH_SHAPE;
+ TopExp::Vertices( aTrackEdge, aV1, aV2 );
+ const SMDS_MeshNode* aN1 = 0;
+ const SMDS_MeshNode* aN2 = 0;
+ if ( theTrack->GetSubMesh( aV1 ) && theTrack->GetSubMesh( aV1 )->GetSubMeshDS() ) {
+ aItN = theTrack->GetSubMesh( aV1 )->GetSubMeshDS()->GetNodes();
+ aN1 = aItN->next();
+ }
+ if ( theTrack->GetSubMesh( aV2 ) && theTrack->GetSubMesh( aV2 )->GetSubMeshDS() ) {
+ aItN = theTrack->GetSubMesh( aV2 )->GetSubMeshDS()->GetNodes();
+ aN2 = aItN->next();
+ }
+ // starting node must be aN1 or aN2
+ if ( !( aN1 == theN1 || aN2 == theN1 ) )
+ return EXTR_BAD_STARTING_NODE;
+ aItN = pMeshDS->nodesIterator();
+ while ( aItN->more() ) {
+ const SMDS_MeshNode* pNode = aItN->next();
+ if( pNode==aN1 || pNode==aN2 ) continue;
+ const SMDS_EdgePosition* pEPos =
+ static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
+ double aT = pEPos->GetUParameter();
+ aPrms.push_back( aT );
+ }
+ //Extrusion_Error err =
+ MakeEdgePathPoints(aPrms, aTrackEdge, (aN1==theN1), fullList);
+ }
+ else if( aS.ShapeType() == TopAbs_WIRE ) {
+ list< SMESH_subMesh* > LSM;
+ TopTools_SequenceOfShape Edges;
+ TopExp_Explorer eExp(aS, TopAbs_EDGE);
+ for(; eExp.More(); eExp.Next()) {
+ TopoDS_Edge E = TopoDS::Edge( eExp.Current() );
+ if( BRep_Tool::Degenerated(E) ) continue;
+ SMESH_subMesh* SM = theTrack->GetSubMesh(E);
+ if(SM) {
+ LSM.push_back(SM);
+ Edges.Append(E);
+ }
+ }
+ list< list<SMESH_MeshEditor_PathPoint> > LLPPs;
+ TopoDS_Vertex aVprev;
+ TColStd_MapOfInteger UsedNums;
+ int NbEdges = Edges.Length();
int i = 1;
for(; i<=NbEdges; i++) {
int k = 0;
SMESH_subMesh* locTrack = *itLSM;
SMESHDS_SubMesh* locMeshDS = locTrack->GetSubMeshDS();
TopExp::Vertices( aTrackEdge, aV1, aV2 );
- aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN1 = aItN->next();
- aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
- const SMDS_MeshNode* aN2 = aItN->next();
- // starting node must be aN1 or aN2
- if ( !( aN1->GetID() == startNid || aN2->GetID() == startNid ) ) continue;
+ bool aN1isOK = false, aN2isOK = false;
+ if ( aVprev.IsNull() ) {
+ // if previous vertex is not yet defined, it means that we in the beginning of wire
+ // and we have to find initial vertex corresponding to starting node theN1
+ const SMDS_MeshNode* aN1 = 0;
+ const SMDS_MeshNode* aN2 = 0;
+
+ if ( locTrack->GetFather()->GetSubMesh(aV1) && locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS() ) {
+ aItN = locTrack->GetFather()->GetSubMesh(aV1)->GetSubMeshDS()->GetNodes();
+ aN1 = aItN->next();
+ }
+ if ( locTrack->GetFather()->GetSubMesh(aV2) && locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS() ) {
+ aItN = locTrack->GetFather()->GetSubMesh(aV2)->GetSubMeshDS()->GetNodes();
+ aN2 = aItN->next();
+ }
+ // starting node must be aN1 or aN2
+ aN1isOK = ( aN1 && aN1 == theN1 );
+ aN2isOK = ( aN2 && aN2 == theN1 );
+ }
+ else {
+ // we have specified ending vertex of the previous edge on the previous iteration
+ // and we have just to check that it corresponds to any vertex in current segment
+ aN1isOK = aVprev.IsSame( aV1 );
+ aN2isOK = aVprev.IsSame( aV2 );
+ }
+ if ( !aN1isOK && !aN2isOK ) continue;
// 2. Collect parameters on the track edge
aPrms.clear();
aItN = locMeshDS->GetNodes();
while ( aItN->more() ) {
- const SMDS_MeshNode* pNode = aItN->next();
+ const SMDS_MeshNode* pNode = aItN->next();
const SMDS_EdgePosition* pEPos =
static_cast<const SMDS_EdgePosition*>( pNode->GetPosition() );
double aT = pEPos->GetUParameter();
}
list<SMESH_MeshEditor_PathPoint> LPP;
//Extrusion_Error err =
- MakeEdgePathPoints(aPrms, aTrackEdge,(aN1->GetID()==startNid), LPP);
+ MakeEdgePathPoints(aPrms, aTrackEdge, aN1isOK, LPP);
LLPPs.push_back(LPP);
UsedNums.Add(k);
// update startN for search following egde
- if( aN1->GetID() == startNid ) startNid = aN2->GetID();
- else startNid = aN1->GetID();
+ if ( aN1isOK ) aVprev = aV2;
+ else aVprev = aV1;
break;
}
}
list<SMESH_MeshEditor_PathPoint> currList = *itLLPP;
itPP = currList.begin();
SMESH_MeshEditor_PathPoint PP2 = currList.front();
- gp_Pnt P1 = PP1.Pnt();
- //cout<<" PP1: Pnt("<<P1.X()<<","<<P1.Y()<<","<<P1.Z()<<")"<<endl;
- gp_Pnt P2 = PP2.Pnt();
gp_Dir D1 = PP1.Tangent();
gp_Dir D2 = PP2.Tangent();
- gp_Dir Dnew( gp_Vec( (D1.X()+D2.X())/2, (D1.Y()+D2.Y())/2,
- (D1.Z()+D2.Z())/2 ) );
+ gp_Dir Dnew( ( D1.XYZ() + D2.XYZ() ) / 2 );
PP1.SetTangent(Dnew);
fullList.push_back(PP1);
itPP++;
* \param theCopy - if true, create translated copies of theElems
* \param theMakeGroups - if true and theCopy, create translated groups
* \param theTargetMesh - mesh to copy translated elements into
- * \retval SMESH_MeshEditor::PGroupIDs - list of ids of created groups
+ * \return SMESH_MeshEditor::PGroupIDs - list of ids of created groups
*/
//================================================================================
for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
theElems.insert( *invElemIt );
- // replicate or reverse elements
- // TODO revoir ordre reverse vtk
- enum {
- REV_TETRA = 0, // = nbNodes - 4
- REV_PYRAMID = 1, // = nbNodes - 4
- REV_PENTA = 2, // = nbNodes - 4
- REV_FACE = 3,
- REV_HEXA = 4, // = nbNodes - 4
- FORWARD = 5
- };
- int index[][8] = {
- { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
- { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
- { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
- { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
- { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
- { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
- };
+ // Replicate or reverse elements
+ std::vector<int> iForw;
for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
{
const SMDS_MeshElement* elem = *itElem;
- if ( !elem || elem->GetType() == SMDSAbs_Node )
- continue;
+ if ( !elem ) continue;
- int nbNodes = elem->NbNodes();
- int elemType = elem->GetType();
+ SMDSAbs_GeometryType geomType = elem->GetGeomType();
+ int nbNodes = elem->NbNodes();
+ if ( geomType == SMDSGeom_NONE ) continue; // node
- if (elem->IsPoly()) {
- // Polygon or Polyhedral Volume
- switch ( elemType ) {
- case SMDSAbs_Face:
- {
- vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
- int iNode = 0;
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while (itN->more()) {
- const SMDS_MeshNode* node =
- static_cast<const SMDS_MeshNode*>(itN->next());
- TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
- if (nodeMapIt == nodeMap.end())
- break; // not all nodes transformed
- if (needReverse) {
- // reverse mirrored faces and volumes
- poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
- } else {
- poly_nodes[iNode] = (*nodeMapIt).second;
- }
- iNode++;
- }
- if ( iNode != nbNodes )
- continue; // not all nodes transformed
+ switch ( geomType ) {
- if ( theTargetMesh ) {
- myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
- srcElems.Append( elem );
- }
- else if ( theCopy ) {
- myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
- srcElems.Append( elem );
- }
- else {
- aMesh->ChangePolygonNodes(elem, poly_nodes);
+ case SMDSGeom_POLYGON: // ---------------------- polygon
+ {
+ vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
+ int iNode = 0;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while (itN->more()) {
+ const SMDS_MeshNode* node =
+ static_cast<const SMDS_MeshNode*>(itN->next());
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+ if (nodeMapIt == nodeMap.end())
+ break; // not all nodes transformed
+ if (needReverse) {
+ // reverse mirrored faces and volumes
+ poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
+ } else {
+ poly_nodes[iNode] = (*nodeMapIt).second;
}
+ iNode++;
}
- break;
- case SMDSAbs_Volume:
- {
- // ATTENTION: Reversing is not yet done!!!
- const SMDS_VtkVolume* aPolyedre =
- dynamic_cast<const SMDS_VtkVolume*>( elem );
- if (!aPolyedre) {
- MESSAGE("Warning: bad volumic element");
- continue;
- }
-
- vector<const SMDS_MeshNode*> poly_nodes;
- vector<int> quantities;
-
- bool allTransformed = true;
- int nbFaces = aPolyedre->NbFaces();
- for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
- int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
- for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
- const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
- TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
- if (nodeMapIt == nodeMap.end()) {
- allTransformed = false; // not all nodes transformed
- } else {
- poly_nodes.push_back((*nodeMapIt).second);
- }
- }
- quantities.push_back(nbFaceNodes);
- }
- if ( !allTransformed )
- continue; // not all nodes transformed
+ if ( iNode != nbNodes )
+ continue; // not all nodes transformed
- if ( theTargetMesh ) {
- myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
- srcElems.Append( elem );
- }
- else if ( theCopy ) {
- myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
- srcElems.Append( elem );
- }
- else {
- aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
- }
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
+ srcElems.Append( elem );
+ }
+ else if ( theCopy ) {
+ myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
+ srcElems.Append( elem );
+ }
+ else {
+ aMesh->ChangePolygonNodes(elem, poly_nodes);
}
- break;
- default:;
}
- continue;
- }
+ break;
- // Regular elements
- int* i = index[ FORWARD ];
- if ( needReverse && nbNodes > 2) {// reverse mirrored faces and volumes
- if ( elemType == SMDSAbs_Face )
- i = index[ REV_FACE ];
- else
- i = index[ nbNodes - 4 ];
- }
- if(elem->IsQuadratic()) {
- static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
- i = anIds;
- if(needReverse) {
- if(nbNodes==3) { // quadratic edge
- static int anIds[] = {1,0,2};
- i = anIds;
+ case SMDSGeom_POLYHEDRA: // ------------------ polyhedral volume
+ {
+ const SMDS_VtkVolume* aPolyedre =
+ dynamic_cast<const SMDS_VtkVolume*>( elem );
+ if (!aPolyedre) {
+ MESSAGE("Warning: bad volumic element");
+ continue;
}
- else if(nbNodes==6) { // quadratic triangle
- static int anIds[] = {0,2,1,5,4,3};
- i = anIds;
+
+ vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
+ vector<int> quantities; quantities.reserve( nbNodes );
+
+ bool allTransformed = true;
+ int nbFaces = aPolyedre->NbFaces();
+ for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
+ int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
+ for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
+ const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
+ if (nodeMapIt == nodeMap.end()) {
+ allTransformed = false; // not all nodes transformed
+ } else {
+ poly_nodes.push_back((*nodeMapIt).second);
+ }
+ if ( needReverse && allTransformed )
+ std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
+ }
+ quantities.push_back(nbFaceNodes);
}
- else if(nbNodes==8) { // quadratic quadrangle
- static int anIds[] = {0,3,2,1,7,6,5,4};
- i = anIds;
+ if ( !allTransformed )
+ continue; // not all nodes transformed
+
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
+ srcElems.Append( elem );
}
- else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
- static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
- i = anIds;
+ else if ( theCopy ) {
+ myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
+ srcElems.Append( elem );
}
- else if(nbNodes==13) { // quadratic pyramid of 13 nodes
- static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
- i = anIds;
+ else {
+ aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
}
- else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
- static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
- i = anIds;
+ }
+ break;
+
+ case SMDSGeom_BALL: // -------------------- Ball
+ {
+ if ( !theCopy && !theTargetMesh ) continue;
+
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find( elem->GetNode(0) );
+ if (nodeMapIt == nodeMap.end())
+ continue; // not all nodes transformed
+
+ double diameter = static_cast<const SMDS_BallElement*>(elem)->GetDiameter();
+ if ( theTargetMesh ) {
+ myLastCreatedElems.Append(aTgtMesh->AddBall( nodeMapIt->second, diameter ));
+ srcElems.Append( elem );
}
- else { // nbNodes==20 - quadratic hexahedron with 20 nodes
- static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
- i = anIds;
+ else {
+ myLastCreatedElems.Append(aMesh->AddBall( nodeMapIt->second, diameter ));
+ srcElems.Append( elem );
}
}
- }
+ break;
- // find transformed nodes
- vector<const SMDS_MeshNode*> nodes(nbNodes);
- int iNode = 0;
- SMDS_ElemIteratorPtr itN = elem->nodesIterator();
- while ( itN->more() ) {
- const SMDS_MeshNode* node =
- static_cast<const SMDS_MeshNode*>( itN->next() );
- TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
- if ( nodeMapIt == nodeMap.end() )
- break; // not all nodes transformed
- nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
- }
- if ( iNode != nbNodes )
- continue; // not all nodes transformed
+ default: // ----------------------- Regular elements
- if ( theTargetMesh ) {
- if ( SMDS_MeshElement* copy =
- targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
- myLastCreatedElems.Append( copy );
- srcElems.Append( elem );
+ while ( iForw.size() < nbNodes ) iForw.push_back( iForw.size() );
+ const std::vector<int>& iRev = SMDS_MeshCell::reverseSmdsOrder( elem->GetEntityType() );
+ const std::vector<int>& i = needReverse ? iRev : iForw;
+
+ // find transformed nodes
+ vector<const SMDS_MeshNode*> nodes(nbNodes);
+ int iNode = 0;
+ SMDS_ElemIteratorPtr itN = elem->nodesIterator();
+ while ( itN->more() ) {
+ const SMDS_MeshNode* node =
+ static_cast<const SMDS_MeshNode*>( itN->next() );
+ TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
+ if ( nodeMapIt == nodeMap.end() )
+ break; // not all nodes transformed
+ nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
}
- }
- else if ( theCopy ) {
- if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
- srcElems.Append( elem );
- }
- else {
- // reverse element as it was reversed by transformation
- if ( nbNodes > 2 )
- aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
- }
- }
+ if ( iNode != nbNodes )
+ continue; // not all nodes transformed
+
+ if ( theTargetMesh ) {
+ if ( SMDS_MeshElement* copy =
+ targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
+ myLastCreatedElems.Append( copy );
+ srcElems.Append( elem );
+ }
+ }
+ else if ( theCopy ) {
+ if ( AddElement( nodes, elem->GetType(), elem->IsPoly() ))
+ srcElems.Append( elem );
+ }
+ else {
+ // reverse element as it was reversed by transformation
+ if ( nbNodes > 2 )
+ aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
+ }
+ } // switch ( geomType )
+
+ } // loop on elements
PGroupIDs newGroupIDs;
- if ( theMakeGroups && theCopy ||
- theMakeGroups && theTargetMesh )
+ if ( ( theMakeGroups && theCopy ) ||
+ ( theMakeGroups && theTargetMesh ) )
newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
return newGroupIDs;
}
-
-////=======================================================================
-////function : Scale
-////purpose :
-////=======================================================================
-//
-//SMESH_MeshEditor::PGroupIDs
-//SMESH_MeshEditor::Scale (TIDSortedElemSet & theElems,
-// const gp_Pnt& thePoint,
-// const std::list<double>& theScaleFact,
-// const bool theCopy,
-// const bool theMakeGroups,
-// SMESH_Mesh* theTargetMesh)
-//{
-// MESSAGE("Scale");
-// myLastCreatedElems.Clear();
-// myLastCreatedNodes.Clear();
-//
-// SMESH_MeshEditor targetMeshEditor( theTargetMesh );
-// SMESHDS_Mesh* aTgtMesh = theTargetMesh ? theTargetMesh->GetMeshDS() : 0;
-// SMESHDS_Mesh* aMesh = GetMeshDS();
-//
-// double scaleX=1.0, scaleY=1.0, scaleZ=1.0;
-// std::list<double>::const_iterator itS = theScaleFact.begin();
-// scaleX = (*itS);
-// if(theScaleFact.size()==1) {
-// scaleY = (*itS);
-// scaleZ= (*itS);
-// }
-// if(theScaleFact.size()==2) {
-// itS++;
-// scaleY = (*itS);
-// scaleZ= (*itS);
-// }
-// if(theScaleFact.size()>2) {
-// itS++;
-// scaleY = (*itS);
-// itS++;
-// scaleZ= (*itS);
-// }
-//
-// // map old node to new one
-// TNodeNodeMap nodeMap;
-//
-// // elements sharing moved nodes; those of them which have all
-// // nodes mirrored but are not in theElems are to be reversed
-// TIDSortedElemSet inverseElemSet;
-//
-// // source elements for each generated one
-// SMESH_SequenceOfElemPtr srcElems, srcNodes;
-//
-// // loop on theElems
-// TIDSortedElemSet::iterator itElem;
-// for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ ) {
-// const SMDS_MeshElement* elem = *itElem;
-// if ( !elem )
-// continue;
-//
-// // loop on elem nodes
-// SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-// while ( itN->more() ) {
-//
-// // check if a node has been already transformed
-// const SMDS_MeshNode* node = cast2Node( itN->next() );
-// pair<TNodeNodeMap::iterator,bool> n2n_isnew =
-// nodeMap.insert( make_pair ( node, node ));
-// if ( !n2n_isnew.second )
-// continue;
-//
-// //double coord[3];
-// //coord[0] = node->X();
-// //coord[1] = node->Y();
-// //coord[2] = node->Z();
-// //theTrsf.Transforms( coord[0], coord[1], coord[2] );
-// double dx = (node->X() - thePoint.X()) * scaleX;
-// double dy = (node->Y() - thePoint.Y()) * scaleY;
-// double dz = (node->Z() - thePoint.Z()) * scaleZ;
-// if ( theTargetMesh ) {
-// //const SMDS_MeshNode * newNode = aTgtMesh->AddNode( coord[0], coord[1], coord[2] );
-// const SMDS_MeshNode * newNode =
-// aTgtMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
-// n2n_isnew.first->second = newNode;
-// myLastCreatedNodes.Append(newNode);
-// srcNodes.Append( node );
-// }
-// else if ( theCopy ) {
-// //const SMDS_MeshNode * newNode = aMesh->AddNode( coord[0], coord[1], coord[2] );
-// const SMDS_MeshNode * newNode =
-// aMesh->AddNode( thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
-// n2n_isnew.first->second = newNode;
-// myLastCreatedNodes.Append(newNode);
-// srcNodes.Append( node );
-// }
-// else {
-// //aMesh->MoveNode( node, coord[0], coord[1], coord[2] );
-// aMesh->MoveNode( node, thePoint.X()+dx, thePoint.Y()+dy, thePoint.Z()+dz );
-// // node position on shape becomes invalid
-// const_cast< SMDS_MeshNode* > ( node )->SetPosition
-// ( SMDS_SpacePosition::originSpacePosition() );
-// }
-//
-// // keep inverse elements
-// //if ( !theCopy && !theTargetMesh && needReverse ) {
-// // SMDS_ElemIteratorPtr invElemIt = node->GetInverseElementIterator();
-// // while ( invElemIt->more() ) {
-// // const SMDS_MeshElement* iel = invElemIt->next();
-// // inverseElemSet.insert( iel );
-// // }
-// //}
-// }
-// }
-//
-// // either create new elements or reverse mirrored ones
-// //if ( !theCopy && !needReverse && !theTargetMesh )
-// if ( !theCopy && !theTargetMesh )
-// return PGroupIDs();
-//
-// TIDSortedElemSet::iterator invElemIt = inverseElemSet.begin();
-// for ( ; invElemIt != inverseElemSet.end(); invElemIt++ )
-// theElems.insert( *invElemIt );
-//
-// // replicate or reverse elements
-//
-// enum {
-// REV_TETRA = 0, // = nbNodes - 4
-// REV_PYRAMID = 1, // = nbNodes - 4
-// REV_PENTA = 2, // = nbNodes - 4
-// REV_FACE = 3,
-// REV_HEXA = 4, // = nbNodes - 4
-// FORWARD = 5
-// };
-// int index[][8] = {
-// { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_TETRA
-// { 2, 1, 0, 3, 4, 0, 0, 0 }, // REV_PYRAMID
-// { 2, 1, 0, 5, 4, 3, 0, 0 }, // REV_PENTA
-// { 2, 1, 0, 3, 0, 0, 0, 0 }, // REV_FACE
-// { 2, 1, 0, 3, 6, 5, 4, 7 }, // REV_HEXA
-// { 0, 1, 2, 3, 4, 5, 6, 7 } // FORWARD
-// };
-//
-// for ( itElem = theElems.begin(); itElem != theElems.end(); itElem++ )
-// {
-// const SMDS_MeshElement* elem = *itElem;
-// if ( !elem || elem->GetType() == SMDSAbs_Node )
-// continue;
-//
-// int nbNodes = elem->NbNodes();
-// int elemType = elem->GetType();
-//
-// if (elem->IsPoly()) {
-// // Polygon or Polyhedral Volume
-// switch ( elemType ) {
-// case SMDSAbs_Face:
-// {
-// vector<const SMDS_MeshNode*> poly_nodes (nbNodes);
-// int iNode = 0;
-// SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-// while (itN->more()) {
-// const SMDS_MeshNode* node =
-// static_cast<const SMDS_MeshNode*>(itN->next());
-// TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
-// if (nodeMapIt == nodeMap.end())
-// break; // not all nodes transformed
-// //if (needReverse) {
-// // // reverse mirrored faces and volumes
-// // poly_nodes[nbNodes - iNode - 1] = (*nodeMapIt).second;
-// //} else {
-// poly_nodes[iNode] = (*nodeMapIt).second;
-// //}
-// iNode++;
-// }
-// if ( iNode != nbNodes )
-// continue; // not all nodes transformed
-//
-// if ( theTargetMesh ) {
-// myLastCreatedElems.Append(aTgtMesh->AddPolygonalFace(poly_nodes));
-// srcElems.Append( elem );
-// }
-// else if ( theCopy ) {
-// myLastCreatedElems.Append(aMesh->AddPolygonalFace(poly_nodes));
-// srcElems.Append( elem );
-// }
-// else {
-// aMesh->ChangePolygonNodes(elem, poly_nodes);
-// }
-// }
-// break;
-// case SMDSAbs_Volume:
-// {
-// // ATTENTION: Reversing is not yet done!!!
-// const SMDS_VtkVolume* aPolyedre =
-// dynamic_cast<const SMDS_VtkVolume*>( elem );
-// if (!aPolyedre) {
-// MESSAGE("Warning: bad volumic element");
-// continue;
-// }
-//
-// vector<const SMDS_MeshNode*> poly_nodes;
-// vector<int> quantities;
-//
-// bool allTransformed = true;
-// int nbFaces = aPolyedre->NbFaces();
-// for (int iface = 1; iface <= nbFaces && allTransformed; iface++) {
-// int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
-// for (int inode = 1; inode <= nbFaceNodes && allTransformed; inode++) {
-// const SMDS_MeshNode* node = aPolyedre->GetFaceNode(iface, inode);
-// TNodeNodeMap::iterator nodeMapIt = nodeMap.find(node);
-// if (nodeMapIt == nodeMap.end()) {
-// allTransformed = false; // not all nodes transformed
-// } else {
-// poly_nodes.push_back((*nodeMapIt).second);
-// }
-// }
-// quantities.push_back(nbFaceNodes);
-// }
-// if ( !allTransformed )
-// continue; // not all nodes transformed
-//
-// if ( theTargetMesh ) {
-// myLastCreatedElems.Append(aTgtMesh->AddPolyhedralVolume(poly_nodes, quantities));
-// srcElems.Append( elem );
-// }
-// else if ( theCopy ) {
-// myLastCreatedElems.Append(aMesh->AddPolyhedralVolume(poly_nodes, quantities));
-// srcElems.Append( elem );
-// }
-// else {
-// aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
-// }
-// }
-// break;
-// default:;
-// }
-// continue;
-// }
-//
-// // Regular elements
-// int* i = index[ FORWARD ];
-// //if ( needReverse && nbNodes > 2) // reverse mirrored faces and volumes
-// // if ( elemType == SMDSAbs_Face )
-// // i = index[ REV_FACE ];
-// // else
-// // i = index[ nbNodes - 4 ];
-//
-// if(elem->IsQuadratic()) {
-// static int anIds[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
-// i = anIds;
-// //if(needReverse) {
-// // if(nbNodes==3) { // quadratic edge
-// // static int anIds[] = {1,0,2};
-// // i = anIds;
-// // }
-// // else if(nbNodes==6) { // quadratic triangle
-// // static int anIds[] = {0,2,1,5,4,3};
-// // i = anIds;
-// // }
-// // else if(nbNodes==8) { // quadratic quadrangle
-// // static int anIds[] = {0,3,2,1,7,6,5,4};
-// // i = anIds;
-// // }
-// // else if(nbNodes==10) { // quadratic tetrahedron of 10 nodes
-// // static int anIds[] = {0,2,1,3,6,5,4,7,9,8};
-// // i = anIds;
-// // }
-// // else if(nbNodes==13) { // quadratic pyramid of 13 nodes
-// // static int anIds[] = {0,3,2,1,4,8,7,6,5,9,12,11,10};
-// // i = anIds;
-// // }
-// // else if(nbNodes==15) { // quadratic pentahedron with 15 nodes
-// // static int anIds[] = {0,2,1,3,5,4,8,7,6,11,10,9,12,14,13};
-// // i = anIds;
-// // }
-// // else { // nbNodes==20 - quadratic hexahedron with 20 nodes
-// // static int anIds[] = {0,3,2,1,4,7,6,5,11,10,9,8,15,14,13,12,16,19,18,17};
-// // i = anIds;
-// // }
-// //}
-// }
-//
-// // find transformed nodes
-// vector<const SMDS_MeshNode*> nodes(nbNodes);
-// int iNode = 0;
-// SMDS_ElemIteratorPtr itN = elem->nodesIterator();
-// while ( itN->more() ) {
-// const SMDS_MeshNode* node =
-// static_cast<const SMDS_MeshNode*>( itN->next() );
-// TNodeNodeMap::iterator nodeMapIt = nodeMap.find( node );
-// if ( nodeMapIt == nodeMap.end() )
-// break; // not all nodes transformed
-// nodes[ i [ iNode++ ]] = (*nodeMapIt).second;
-// }
-// if ( iNode != nbNodes )
-// continue; // not all nodes transformed
-//
-// if ( theTargetMesh ) {
-// if ( SMDS_MeshElement* copy =
-// targetMeshEditor.AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
-// myLastCreatedElems.Append( copy );
-// srcElems.Append( elem );
-// }
-// }
-// else if ( theCopy ) {
-// if ( SMDS_MeshElement* copy = AddElement( nodes, elem->GetType(), elem->IsPoly() )) {
-// myLastCreatedElems.Append( copy );
-// srcElems.Append( elem );
-// }
-// }
-// else {
-// // reverse element as it was reversed by transformation
-// if ( nbNodes > 2 )
-// aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
-// }
-// }
-//
-// PGroupIDs newGroupIDs;
-//
-// if ( theMakeGroups && theCopy ||
-// theMakeGroups && theTargetMesh ) {
-// string groupPostfix = "scaled";
-// newGroupIDs = generateGroups( srcNodes, srcElems, groupPostfix, theTargetMesh );
-// }
-//
-// return newGroupIDs;
-//}
-
-
//=======================================================================
/*!
* \brief Create groups of elements made during transformation
// Sort existing groups by types and collect their names
// to store an old group and a generated new one
- typedef pair< SMESHDS_GroupBase*, SMDS_MeshGroup* > TOldNewGroup;
+ typedef pair< SMESHDS_GroupBase*, SMESHDS_Group* > TOldNewGroup;
vector< list< TOldNewGroup > > groupsByType( SMDSAbs_NbElementTypes );
+ vector< TOldNewGroup* > orderedOldNewGroups; // in order of old groups
// group names
set< string > groupNames;
- //
- SMDS_MeshGroup* nullNewGroup = (SMDS_MeshGroup*) 0;
+
SMESH_Mesh::GroupIteratorPtr groupIt = GetMesh()->GetGroups();
- while ( groupIt->more() ) {
+ if ( !groupIt->more() ) return newGroupIDs;
+
+ int newGroupID = mesh->GetGroupIds().back()+1;
+ while ( groupIt->more() )
+ {
SMESH_Group * group = groupIt->next();
if ( !group ) continue;
SMESHDS_GroupBase* groupDS = group->GetGroupDS();
if ( !groupDS || groupDS->IsEmpty() ) continue;
groupNames.insert( group->GetName() );
groupDS->SetStoreName( group->GetName() );
- groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, nullNewGroup ));
+ SMESHDS_Group* newGroup = new SMESHDS_Group( newGroupID++, mesh->GetMeshDS(),
+ groupDS->GetType() );
+ groupsByType[ groupDS->GetType() ].push_back( make_pair( groupDS, newGroup ));
+ orderedOldNewGroups.push_back( & groupsByType[ groupDS->GetType() ].back() );
}
- // Groups creation
+ // Loop on nodes and elements to add them in new groups
- // loop on nodes and elements
for ( int isNodes = 0; isNodes < 2; ++isNodes )
{
const SMESH_SequenceOfElemPtr& gens = isNodes ? nodeGens : elemGens;
continue;
}
list< TOldNewGroup > & groupsOldNew = groupsByType[ sourceElem->GetType() ];
- if ( groupsOldNew.empty() ) {
+ if ( groupsOldNew.empty() ) { // no groups of this type at all
while ( iElem < gens.Length() && gens( iElem+1 ) == sourceElem )
++iElem; // skip all elements made by sourceElem
continue;
if ( const SMDS_MeshElement* resElem = elems( ++iElem ))
if ( resElem != sourceElem )
resultElems.push_back( resElem );
- // do not generate element groups from node ones
- if ( sourceElem->GetType() == SMDSAbs_Node &&
- elems( iElem )->GetType() != SMDSAbs_Node )
- continue;
// add resultElems to groups made by ones the sourceElem belongs to
list< TOldNewGroup >::iterator gOldNew, gLast = groupsOldNew.end();
for ( gOldNew = groupsOldNew.begin(); gOldNew != gLast; ++gOldNew )
{
SMESHDS_GroupBase* oldGroup = gOldNew->first;
- if ( oldGroup->Contains( sourceElem )) // sourceElem in oldGroup
+ if ( oldGroup->Contains( sourceElem )) // sourceElem is in oldGroup
{
- SMDS_MeshGroup* & newGroup = gOldNew->second;
- if ( !newGroup )// create a new group
- {
- // make a name
- string name = oldGroup->GetStoreName();
- if ( !targetMesh ) {
- name += "_";
- name += postfix;
- int nb = 0;
- while ( !groupNames.insert( name ).second ) // name exists
- {
- if ( nb == 0 ) {
- name += "_1";
- }
- else {
- TCollection_AsciiString nbStr(nb+1);
- name.resize( name.rfind('_')+1 );
- name += nbStr.ToCString();
- }
- ++nb;
- }
- }
- // make a group
- int id;
- SMESH_Group* group = mesh->AddGroup( resultElems.back()->GetType(),
- name.c_str(), id );
- SMESHDS_Group* groupDS = static_cast<SMESHDS_Group*>(group->GetGroupDS());
- newGroup = & groupDS->SMDSGroup();
- newGroupIDs->push_back( id );
- }
-
// fill in a new group
+ SMDS_MeshGroup & newGroup = gOldNew->second->SMDSGroup();
list< const SMDS_MeshElement* >::iterator resLast = resultElems.end(), resElemIt;
for ( resElemIt = resultElems.begin(); resElemIt != resLast; ++resElemIt )
- newGroup->Add( *resElemIt );
+ newGroup.Add( *resElemIt );
}
}
} // loop on created elements
}// loop on nodes and elements
+ // Create new SMESH_Groups from SMESHDS_Groups and remove empty SMESHDS_Groups
+
+ for ( size_t i = 0; i < orderedOldNewGroups.size(); ++i )
+ {
+ SMESHDS_GroupBase* oldGroupDS = orderedOldNewGroups[i]->first;
+ SMESHDS_Group* newGroupDS = orderedOldNewGroups[i]->second;
+ if ( newGroupDS->IsEmpty() )
+ {
+ mesh->GetMeshDS()->RemoveGroup( newGroupDS );
+ }
+ else
+ {
+ // make a name
+ string name = oldGroupDS->GetStoreName();
+ if ( !targetMesh ) {
+ name += "_";
+ name += postfix;
+ int nb = 1;
+ while ( !groupNames.insert( name ).second ) // name exists
+ name = SMESH_Comment( oldGroupDS->GetStoreName() ) << "_" << postfix << "_" << nb++;
+ }
+ newGroupDS->SetStoreName( name.c_str() );
+
+ // make a SMESH_Groups
+ mesh->AddGroup( newGroupDS );
+ newGroupIDs->push_back( newGroupDS->GetID() );
+
+ // set group type
+ newGroupDS->SetType( newGroupDS->GetElements()->next()->GetType() );
+ }
+ }
+
return newGroupIDs;
}
}
else if ( tree->NbNodes() ) // put a tree to the treeMap
{
- const Bnd_B3d& box = tree->getBox();
+ const Bnd_B3d& box = *tree->getBox();
double sqDist = thePnt.SquareDistance( 0.5 * ( box.CornerMin() + box.CornerMax() ));
pair<TDistTreeMap::iterator,bool> it_in = treeMap.insert( make_pair( sqDist, tree ));
if ( !it_in.second ) // not unique distance to box center
TDistTreeMap::iterator sqDist_tree = treeMap.begin();
if ( treeMap.size() > 5 ) {
SMESH_OctreeNode* closestTree = sqDist_tree->second;
- const Bnd_B3d& box = closestTree->getBox();
+ const Bnd_B3d& box = *closestTree->getBox();
double limit = sqrt( sqDist_tree->first ) + sqrt ( box.SquareExtent() );
sqLimit = limit * limit;
}
*/
//=======================================================================
-SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
+SMESH_NodeSearcher* SMESH_MeshEditor::GetNodeSearcher()
{
return new SMESH_NodeSearcherImpl( GetMeshDS() );
}
{
public:
- ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(), double tolerance = NodeRadius );
- void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems);
+ ElementBndBoxTree(const SMDS_Mesh& mesh,
+ SMDSAbs_ElementType elemType,
+ SMDS_ElemIteratorPtr theElemIt = SMDS_ElemIteratorPtr(),
+ double tolerance = NodeRadius );
+ void getElementsNearPoint( const gp_Pnt& point, TIDSortedElemSet& foundElems );
void getElementsNearLine ( const gp_Ax1& line, TIDSortedElemSet& foundElems);
+ void getElementsInSphere ( const gp_XYZ& center,
+ const double radius, TIDSortedElemSet& foundElems);
+ size_t getSize() { return std::max( _size, _elements.size() ); }
~ElementBndBoxTree();
protected:
- ElementBndBoxTree() {}
- SMESH_Octree* allocateOctreeChild() const { return new ElementBndBoxTree; }
- void buildChildrenData();
- Bnd_B3d* buildRootBox();
+ ElementBndBoxTree():_size(0) {}
+ SMESH_Octree* newChild() const { return new ElementBndBoxTree; }
+ void buildChildrenData();
+ Bnd_B3d* buildRootBox();
private:
//!< Bounding box of element
struct ElementBox : public Bnd_B3d
ElementBox(const SMDS_MeshElement* elem, double tolerance);
};
vector< ElementBox* > _elements;
+ size_t _size;
};
//================================================================================
//================================================================================
ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
- :SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
+ :SMESH_Octree( new SMESH_TreeLimit( MaxLevel, /*minSize=*/0. ))
{
int nbElems = mesh.GetMeshInfo().NbElements( elemType );
_elements.reserve( nbElems );
while ( elemIt->more() )
_elements.push_back( new ElementBox( elemIt->next(),tolerance ));
- if ( _elements.size() > MaxNbElemsInLeaf )
- compute();
- else
- myIsLeaf = true;
+ compute();
}
//================================================================================
{
for (int j = 0; j < 8; j++)
{
- if ( !_elements[i]->IsOut( myChildren[j]->getBox() ))
+ if ( !_elements[i]->IsOut( *myChildren[j]->getBox() ))
{
_elements[i]->_refCount++;
((ElementBndBoxTree*)myChildren[j])->_elements.push_back( _elements[i]);
}
_elements[i]->_refCount--;
}
- _elements.clear();
+ _size = _elements.size();
+ SMESHUtils::FreeVector( _elements ); // = _elements.clear() + free memory
for (int j = 0; j < 8; j++)
{
child->myIsLeaf = true;
if ( child->_elements.capacity() - child->_elements.size() > 1000 )
- child->_elements.resize( child->_elements.size() ); // compact
+ SMESHUtils::CompactVector( child->_elements );
}
}
void ElementBndBoxTree::getElementsNearPoint( const gp_Pnt& point,
TIDSortedElemSet& foundElems)
{
- if ( level() && getBox().IsOut( point.XYZ() ))
+ if ( getBox()->IsOut( point.XYZ() ))
return;
if ( isLeaf() )
void ElementBndBoxTree::getElementsNearLine( const gp_Ax1& line,
TIDSortedElemSet& foundElems)
{
- if ( level() && getBox().IsOut( line ))
+ if ( getBox()->IsOut( line ))
return;
if ( isLeaf() )
}
}
+ //================================================================================
+ /*!
+ * \brief Return elements from leaves intersecting the sphere
+ */
+ //================================================================================
+
+ void ElementBndBoxTree::getElementsInSphere ( const gp_XYZ& center,
+ const double radius,
+ TIDSortedElemSet& foundElems)
+ {
+ if ( getBox()->IsOut( center, radius ))
+ return;
+
+ if ( isLeaf() )
+ {
+ for ( int i = 0; i < _elements.size(); ++i )
+ if ( !_elements[i]->IsOut( center, radius ))
+ foundElems.insert( _elements[i]->_element );
+ }
+ else
+ {
+ for (int i = 0; i < 8; i++)
+ ((ElementBndBoxTree*) myChildren[i])->getElementsInSphere( center, radius, foundElems );
+ }
+ }
+
//================================================================================
/*!
* \brief Construct the element box
_refCount = 1;
SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
while ( nIt->more() )
- Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
+ Add( SMESH_TNodeXYZ( nIt->next() ));
Enlarge( tolerance );
}
SMDSAbs_ElementType type,
vector< const SMDS_MeshElement* >& foundElements);
virtual TopAbs_State GetPointState(const gp_Pnt& point);
+ virtual const SMDS_MeshElement* FindClosestTo( const gp_Pnt& point,
+ SMDSAbs_ElementType type );
void GetElementsNearLine( const gp_Ax1& line,
SMDSAbs_ElementType type,
GeomAPI_ExtremaCurveCurve anExtCC;
Handle(Geom_Curve) lineCurve = new Geom_Line( line );
-
+
int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
{
GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
- SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
+ SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
anExtCC.Init( lineCurve, edge);
if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
{
while (( f = SMESH_MeshEditor::FindFaceInSet(link.node1(), link.node2(), emptySet, faces )))
faces.insert( f );
- // select another outer face among the found
+ // select another outer face among the found
const SMDS_MeshElement* outerFace2 = 0;
if ( faces.size() == 2 )
{
continue;
gp_Vec dirInF = gp_Vec( fNorm ) ^ n1n2;
double angle = dirInOF.AngleWithRef( dirInF, n1n2 );
- if ( angle < 0 ) angle += 2*PI;
+ if ( angle < 0 ) angle += 2. * M_PI;
angle2Face.insert( make_pair( angle, *face ));
}
if ( !angle2Face.empty() )
// There are internal boundaries touching the outher one,
// find all faces of internal boundaries in order to find
// faces of boundaries of holes, if any.
-
+
}
else
{
* \brief Find elements of given type where the given point is IN or ON.
* Returns nb of found elements and elements them-selves.
*
- * 'ALL' type means elements of any type excluding nodes and 0D elements
+ * 'ALL' type means elements of any type excluding nodes, balls and 0D elements
*/
//=======================================================================
double tolerance = getTolerance();
// =================================================================================
- if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement )
+ if ( type == SMDSAbs_Node || type == SMDSAbs_0DElement || type == SMDSAbs_Ball)
{
if ( !_nodeSearcher )
_nodeSearcher = new SMESH_NodeSearcherImpl( _mesh );
}
else
{
- SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( SMDSAbs_0DElement );
+ SMDS_ElemIteratorPtr elemIt = closeNode->GetInverseElementIterator( type );
while ( elemIt->more() )
foundElements.push_back( elemIt->next() );
}
_ebbTree->getElementsNearPoint( point, suspectElems );
TIDSortedElemSet::iterator elem = suspectElems.begin();
for ( ; elem != suspectElems.end(); ++elem )
- if ( !SMESH_MeshEditor::isOut( *elem, point, tolerance ))
+ if ( !SMESH_MeshEditor::IsOut( *elem, point, tolerance ))
foundElements.push_back( *elem );
}
return foundElements.size();
}
-//================================================================================
+//=======================================================================
/*!
- * \brief Classify the given point in the closed 2D mesh
+ * \brief Find an element of given type most close to the given point
+ *
+ * WARNING: Only face search is implemeneted so far
*/
-//================================================================================
+//=======================================================================
-TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
+const SMDS_MeshElement*
+SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point,
+ SMDSAbs_ElementType type )
{
- double tolerance = getTolerance();
- if ( !_ebbTree || _elementType != SMDSAbs_Face )
+ const SMDS_MeshElement* closestElem = 0;
+
+ if ( type == SMDSAbs_Face )
+ {
+ if ( !_ebbTree || _elementType != type )
+ {
+ if ( _ebbTree ) delete _ebbTree;
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
+ }
+ TIDSortedElemSet suspectElems;
+ _ebbTree->getElementsNearPoint( point, suspectElems );
+
+ if ( suspectElems.empty() && _ebbTree->maxSize() > 0 )
+ {
+ gp_Pnt boxCenter = 0.5 * ( _ebbTree->getBox()->CornerMin() +
+ _ebbTree->getBox()->CornerMax() );
+ double radius;
+ if ( _ebbTree->getBox()->IsOut( point.XYZ() ))
+ radius = point.Distance( boxCenter ) - 0.5 * _ebbTree->maxSize();
+ else
+ radius = _ebbTree->maxSize() / pow( 2., _ebbTree->getHeight()) / 2;
+ while ( suspectElems.empty() )
+ {
+ _ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
+ radius *= 1.1;
+ }
+ }
+ double minDist = std::numeric_limits<double>::max();
+ multimap< double, const SMDS_MeshElement* > dist2face;
+ TIDSortedElemSet::iterator elem = suspectElems.begin();
+ for ( ; elem != suspectElems.end(); ++elem )
+ {
+ double dist = SMESH_MeshEditor::GetDistance( dynamic_cast<const SMDS_MeshFace*>(*elem),
+ point );
+ if ( dist < minDist + 1e-10)
+ {
+ minDist = dist;
+ dist2face.insert( dist2face.begin(), make_pair( dist, *elem ));
+ }
+ }
+ if ( !dist2face.empty() )
+ {
+ multimap< double, const SMDS_MeshElement* >::iterator d2f = dist2face.begin();
+ closestElem = d2f->second;
+ // if there are several elements at the same distance, select one
+ // with GC closest to the point
+ typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
+ double minDistToGC = 0;
+ for ( ++d2f; d2f != dist2face.end() && fabs( d2f->first - minDist ) < 1e-10; ++d2f )
+ {
+ if ( minDistToGC == 0 )
+ {
+ gp_XYZ gc(0,0,0);
+ gc = accumulate( TXyzIterator(closestElem->nodesIterator()),
+ TXyzIterator(), gc ) / closestElem->NbNodes();
+ minDistToGC = point.SquareDistance( gc );
+ }
+ gp_XYZ gc(0,0,0);
+ gc = accumulate( TXyzIterator( d2f->second->nodesIterator()),
+ TXyzIterator(), gc ) / d2f->second->NbNodes();
+ double d = point.SquareDistance( gc );
+ if ( d < minDistToGC )
+ {
+ minDistToGC = d;
+ closestElem = d2f->second;
+ }
+ }
+ // cout << "FindClosestTo( " <<point.X()<<", "<<point.Y()<<", "<<point.Z()<<" ) FACE "
+ // <<closestElem->GetID() << " DIST " << minDist << endl;
+ }
+ }
+ else
+ {
+ // NOT IMPLEMENTED SO FAR
+ }
+ return closestElem;
+}
+
+
+//================================================================================
+/*!
+ * \brief Classify the given point in the closed 2D mesh
+ */
+//================================================================================
+
+TopAbs_State SMESH_ElementSearcherImpl::GetPointState(const gp_Pnt& point)
+{
+ double tolerance = getTolerance();
+ if ( !_ebbTree || _elementType != SMDSAbs_Face )
{
if ( _ebbTree ) delete _ebbTree;
_ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
else if ( ! intersection.IsParallel() && intersection.NbPoints() > 0 )
{
gp_Pnt intersectionPoint = intersection.Point(1);
- if ( !SMESH_MeshEditor::isOut( *face, intersectionPoint, tolerance ))
+ if ( !SMESH_MeshEditor::IsOut( *face, intersectionPoint, tolerance ))
u2inters.insert(make_pair( intersection.ParamOnConic(1), TInters( *face, fNorm )));
}
}
int nbInter = u2inters.size();
if ( nbInter == 0 )
- return TopAbs_OUT;
+ return TopAbs_OUT;
double f = u2inters.begin()->first, l = u2inters.rbegin()->first;
if ( nbInter == 1 ) // not closed mesh
return TopAbs_ON;
if ( nbIntBeforePoint == 0 || nbIntAfterPoint == 0)
- return TopAbs_OUT;
+ return TopAbs_OUT;
if ( nbIntBeforePoint + nbIntAfterPoint == 1 ) // not closed mesh
return fabs( f ) < tolerance ? TopAbs_ON : TopAbs_UNKNOWN;
//=======================================================================
/*!
- * \brief Return SMESH_ElementSearcher
+ * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
*/
//=======================================================================
*/
//=======================================================================
-bool SMESH_MeshEditor::isOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
+bool SMESH_MeshEditor::IsOut( const SMDS_MeshElement* element, const gp_Pnt& point, double tol )
{
if ( element->GetType() == SMDSAbs_Volume)
{
for ( i = 0; i < nbNodes; ++i )
{
SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] );
- if ( !isOut( &edge, point, tol ))
+ if ( !IsOut( &edge, point, tol ))
return false;
}
return true;
return true;
}
+//=======================================================================
+
+namespace
+{
+ // Position of a point relative to a segment
+ // . .
+ // . LEFT .
+ // . .
+ // VERTEX 1 o----ON-----> VERTEX 2
+ // . .
+ // . RIGHT .
+ // . .
+ enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
+ POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
+ struct PointPos
+ {
+ PositionName _name;
+ int _index; // index of vertex or segment
+
+ PointPos( PositionName n, int i=-1 ): _name(n), _index(i) {}
+ bool operator < (const PointPos& other ) const
+ {
+ if ( _name == other._name )
+ return ( _index < 0 || other._index < 0 ) ? false : _index < other._index;
+ return _name < other._name;
+ }
+ };
+
+ //================================================================================
+ /*!
+ * \brief Return of a point relative to a segment
+ * \param point2D - the point to analyze position of
+ * \param xyVec - end points of segments
+ * \param index0 - 0-based index of the first point of segment
+ * \param posToFindOut - flags of positions to detect
+ * \retval PointPos - point position
+ */
+ //================================================================================
+
+ PointPos getPointPosition( const gp_XY& point2D,
+ const gp_XY* segEnds,
+ const int index0 = 0,
+ const int posToFindOut = POS_ALL)
+ {
+ const gp_XY& p1 = segEnds[ index0 ];
+ const gp_XY& p2 = segEnds[ index0+1 ];
+ const gp_XY grad = p2 - p1;
+
+ if ( posToFindOut & POS_VERTEX )
+ {
+ // check if the point2D is at "vertex 1" zone
+ gp_XY pp1[2] = { p1, gp_XY( p1.X() - grad.Y(),
+ p1.Y() + grad.X() ) };
+ if ( getPointPosition( point2D, pp1, 0, POS_LEFT|POS_RIGHT )._name == POS_LEFT )
+ return PointPos( POS_VERTEX, index0 );
+
+ // check if the point2D is at "vertex 2" zone
+ gp_XY pp2[2] = { p2, gp_XY( p2.X() - grad.Y(),
+ p2.Y() + grad.X() ) };
+ if ( getPointPosition( point2D, pp2, 0, POS_LEFT|POS_RIGHT )._name == POS_RIGHT )
+ return PointPos( POS_VERTEX, index0 + 1);
+ }
+ double edgeEquation =
+ ( point2D.X() - p1.X() ) * grad.Y() - ( point2D.Y() - p1.Y() ) * grad.X();
+ return PointPos( edgeEquation < 0 ? POS_LEFT : POS_RIGHT, index0 );
+ }
+}
+
+//=======================================================================
+/*!
+ * \brief Return minimal distance from a point to a face
+ *
+ * Currently we ignore non-planarity and 2nd order of face
+ */
+//=======================================================================
+
+double SMESH_MeshEditor::GetDistance( const SMDS_MeshFace* face,
+ const gp_Pnt& point )
+{
+ double badDistance = -1;
+ if ( !face ) return badDistance;
+
+ // coordinates of nodes (medium nodes, if any, ignored)
+ typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
+ vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
+ xyz.resize( face->NbCornerNodes()+1 );
+
+ // transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
+ // and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
+ gp_Trsf trsf;
+ gp_Vec OZ ( xyz[0], xyz[1] );
+ gp_Vec OX ( xyz[0], xyz[2] );
+ if ( OZ.Magnitude() < std::numeric_limits<double>::min() )
+ {
+ if ( xyz.size() < 4 ) return badDistance;
+ OZ = gp_Vec ( xyz[0], xyz[2] );
+ OX = gp_Vec ( xyz[0], xyz[3] );
+ }
+ gp_Ax3 tgtCS;
+ try {
+ tgtCS = gp_Ax3( xyz[0], OZ, OX );
+ }
+ catch ( Standard_Failure ) {
+ return badDistance;
+ }
+ trsf.SetTransformation( tgtCS );
+
+ // move all the nodes to 2D
+ vector<gp_XY> xy( xyz.size() );
+ for ( size_t i = 0;i < xyz.size()-1; ++i )
+ {
+ gp_XYZ p3d = xyz[i];
+ trsf.Transforms( p3d );
+ xy[i].SetCoord( p3d.X(), p3d.Z() );
+ }
+ xyz.back() = xyz.front();
+ xy.back() = xy.front();
+
+ // // move the point in 2D
+ gp_XYZ tmpPnt = point.XYZ();
+ trsf.Transforms( tmpPnt );
+ gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
+
+ // loop on segments of the face to analyze point position ralative to the face
+ set< PointPos > pntPosSet;
+ for ( size_t i = 1; i < xy.size(); ++i )
+ {
+ PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
+ pntPosSet.insert( pos );
+ }
+
+ // compute distance
+ PointPos pos = *pntPosSet.begin();
+ // cout << "Face " << face->GetID() << " DIST: ";
+ switch ( pos._name )
+ {
+ case POS_LEFT: {
+ // point is most close to a segment
+ gp_Vec p0p1( point, xyz[ pos._index ] );
+ gp_Vec p1p2( xyz[ pos._index ], xyz[ pos._index+1 ]); // segment vector
+ p1p2.Normalize();
+ double projDist = p0p1 * p1p2; // distance projected to the segment
+ gp_Vec projVec = p1p2 * projDist;
+ gp_Vec distVec = p0p1 - projVec;
+ // cout << distVec.Magnitude() << ", SEG " << face->GetNode(pos._index)->GetID()
+ // << " - " << face->GetNodeWrap(pos._index+1)->GetID() << endl;
+ return distVec.Magnitude();
+ }
+ case POS_RIGHT: {
+ // point is inside the face
+ double distToFacePlane = tmpPnt.Y();
+ // cout << distToFacePlane << ", INSIDE " << endl;
+ return Abs( distToFacePlane );
+ }
+ case POS_VERTEX: {
+ // point is most close to a node
+ gp_Vec distVec( point, xyz[ pos._index ]);
+ // cout << distVec.Magnitude() << " VERTEX " << face->GetNode(pos._index)->GetID() << endl;
+ return distVec.Magnitude();
+ }
+ }
+ return badDistance;
+}
+
//=======================================================================
//function : SimplifyFace
//purpose :
}
}
// BUG 0020185: end
- iRepl[ nbRepl++ ] = iCur;
}
curNodes[ iCur ] = n;
bool isUnique = nodeSet.insert( n ).second;
if ( isUnique )
uniqueNodes[ iUnique++ ] = n;
+ else
+ iRepl[ nbRepl++ ] = iCur;
iCur++;
}
}
continue;
- }
+ } // poly element
// Regular elements
// TODO not all the possible cases are solved. Find something more generic?
isOk = false;
SMDS_VolumeTool hexa (elem);
hexa.SetExternalNormal();
- if ( nbUniqueNodes == 4 && nbRepl == 6 ) {
- //////////////////////// ---> tetrahedron
+ if ( nbUniqueNodes == 4 && nbRepl == 4 ) {
+ //////////////////////// HEX ---> 1 tetrahedron
for ( int iFace = 0; iFace < 6; iFace++ ) {
const int *ind = hexa.GetFaceNodesIndices( iFace ); // indices of face nodes
if (curNodes[ind[ 0 ]] == curNodes[ind[ 1 ]] &&
int iOppFace = hexa.GetOppFaceIndex( iFace );
ind = hexa.GetFaceNodesIndices( iOppFace );
int nbStick = 0;
- iUnique = 2; // reverse a tetrahedron bottom
for ( iCur = 0; iCur < 4 && nbStick < 2; iCur++ ) {
if ( curNodes[ind[ iCur ]] == curNodes[ind[ iCur + 1 ]] )
nbStick++;
- else if ( iUnique >= 0 )
- uniqueNodes[ iUnique-- ] = curNodes[ind[ iCur ]];
}
if ( nbStick == 1 ) {
// ... and the opposite one - into a triangle.
}
}
}
+ else if ( nbUniqueNodes == 6 && nbRepl == 2 ) {
+ //////////////////////// HEX ---> 1 prism
+ int nbTria = 0, iTria[3];
+ const int *ind; // indices of face nodes
+ // look for triangular faces
+ for ( int iFace = 0; iFace < 6 && nbTria < 3; iFace++ ) {
+ ind = hexa.GetFaceNodesIndices( iFace );
+ TIDSortedNodeSet faceNodes;
+ for ( iCur = 0; iCur < 4; iCur++ )
+ faceNodes.insert( curNodes[ind[iCur]] );
+ if ( faceNodes.size() == 3 )
+ iTria[ nbTria++ ] = iFace;
+ }
+ // check if triangles are opposite
+ if ( nbTria == 2 && iTria[0] == hexa.GetOppFaceIndex( iTria[1] ))
+ {
+ isOk = true;
+ // set nodes of the bottom triangle
+ ind = hexa.GetFaceNodesIndices( iTria[ 0 ]);
+ vector<int> indB;
+ for ( iCur = 0; iCur < 4; iCur++ )
+ if ( ind[iCur] != iRepl[0] && ind[iCur] != iRepl[1])
+ indB.push_back( ind[iCur] );
+ if ( !hexa.IsForward() )
+ std::swap( indB[0], indB[2] );
+ for ( iCur = 0; iCur < 3; iCur++ )
+ uniqueNodes[ iCur ] = curNodes[indB[iCur]];
+ // set nodes of the top triangle
+ const int *indT = hexa.GetFaceNodesIndices( iTria[ 1 ]);
+ for ( iCur = 0; iCur < 3; ++iCur )
+ for ( int j = 0; j < 4; ++j )
+ if ( hexa.IsLinked( indB[ iCur ], indT[ j ] ))
+ {
+ uniqueNodes[ iCur + 3 ] = curNodes[ indT[ j ]];
+ break;
+ }
+ }
+ break;
+ }
else if (nbUniqueNodes == 5 && nbRepl == 4 ) {
//////////////////// HEXAHEDRON ---> 2 tetrahedrons
for ( int iFace = 0; iFace < 6; iFace++ ) {
}
}
} // if ( nbUniqueNodes == 6 && nbRepl == 4 )
+ else
+ {
+ MESSAGE("MergeNodes() removes hexahedron "<< elem);
+ }
break;
} // HEXAHEDRON
} // if ( nbNodes != nbUniqueNodes ) // some nodes stick
- if ( isOk ) {
- if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
+ if ( isOk ) { // the elem remains valid after sticking nodes
+ if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume)
+ {
// Change nodes of polyedre
const SMDS_VtkVolume* aPolyedre =
dynamic_cast<const SMDS_VtkVolume*>( elem );
aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
}
}
- else {
- //int elemId = elem->GetID();
- //MESSAGE("Change regular element or polygon " << elemId);
- SMDSAbs_ElementType etyp = elem->GetType();
+ else // replace non-polyhedron elements
+ {
+ const SMDSAbs_ElementType etyp = elem->GetType();
+ const int elemId = elem->GetID();
+ const bool isPoly = (elem->GetEntityType() == SMDSEntity_Polygon);
uniqueNodes.resize(nbUniqueNodes);
- SMDS_MeshElement* newElem = 0;
- if (elem->GetEntityType() == SMDSEntity_Polygon)
- newElem = this->AddElement(uniqueNodes, etyp, true);
- else
- newElem = this->AddElement(uniqueNodes, etyp, false);
- if (newElem)
- {
- myLastCreatedElems.Append(newElem);
- if ( aShapeId )
- aMesh->SetMeshElementOnShape( newElem, aShapeId );
- }
- aMesh->RemoveElement(elem);
+
+ SMESHDS_SubMesh * sm = aShapeId > 0 ? aMesh->MeshElements(aShapeId) : 0;
+
+ aMesh->RemoveFreeElement(elem, sm, /*fromGroups=*/false);
+ SMDS_MeshElement* newElem = this->AddElement(uniqueNodes, etyp, isPoly, elemId);
+ if ( sm && newElem )
+ sm->AddElement( newElem );
+ if ( elem != newElem )
+ ReplaceElemInGroups( elem, newElem, aMesh );
}
}
else {
// Remove invalid regular element or invalid polygon
- //MESSAGE("Remove invalid " << elem->GetID());
rmElemIds.push_back( elem->GetID() );
}
//purpose : Return list of group of elements built on the same nodes.
// Search among theElements or in the whole mesh if theElements is empty
//=======================================================================
-void SMESH_MeshEditor::FindEqualElements(set<const SMDS_MeshElement*> & theElements,
- TListOfListOfElementsID & theGroupsOfElementsID)
+
+void SMESH_MeshEditor::FindEqualElements(TIDSortedElemSet & theElements,
+ TListOfListOfElementsID & theGroupsOfElementsID)
{
myLastCreatedElems.Clear();
myLastCreatedNodes.Clear();
- typedef set<const SMDS_MeshElement*> TElemsSet;
typedef map< SortableElement, int > TMapOfNodeSet;
typedef list<int> TGroupOfElems;
- TElemsSet elems;
if ( theElements.empty() )
{ // get all elements in the mesh
SMDS_ElemIteratorPtr eIt = GetMeshDS()->elementsIterator();
while ( eIt->more() )
- elems.insert( elems.end(), eIt->next());
+ theElements.insert( theElements.end(), eIt->next());
}
- else
- elems = theElements;
vector< TGroupOfElems > arrayOfGroups;
TGroupOfElems groupOfElems;
TMapOfNodeSet mapOfNodeSet;
- TElemsSet::iterator elemIt = elems.begin();
- for ( int i = 0, j=0; elemIt != elems.end(); ++elemIt, ++j ) {
+ TIDSortedElemSet::iterator elemIt = theElements.begin();
+ for ( int i = 0, j=0; elemIt != theElements.end(); ++elemIt, ++j ) {
const SMDS_MeshElement* curElem = *elemIt;
SortableElement SE(curElem);
int ind = -1;
void SMESH_MeshEditor::MergeEqualElements()
{
- set<const SMDS_MeshElement*> aMeshElements; /* empty input -
- to merge equal elements in the whole mesh */
+ TIDSortedElemSet aMeshElements; /* empty input ==
+ to merge equal elements in the whole mesh */
TListOfListOfElementsID aGroupsOfElementsID;
FindEqualElements(aMeshElements, aGroupsOfElementsID);
MergeElements(aGroupsOfElementsID);
}
}
+namespace
+{
+ //================================================================================
+ /*!
+ * \brief Transform any volume into data of SMDSEntity_Polyhedra
+ */
+ //================================================================================
+
+ void volumeToPolyhedron( const SMDS_MeshElement* elem,
+ vector<const SMDS_MeshNode *> & nodes,
+ vector<int> & nbNodeInFaces )
+ {
+ nodes.clear();
+ nbNodeInFaces.clear();
+ SMDS_VolumeTool vTool ( elem );
+ for ( int iF = 0; iF < vTool.NbFaces(); ++iF )
+ {
+ const SMDS_MeshNode** fNodes = vTool.GetFaceNodes( iF );
+ nodes.insert( nodes.end(), fNodes, fNodes + vTool.NbFaceNodes( iF ));
+ nbNodeInFaces.push_back( vTool.NbFaceNodes( iF ));
+ }
+ }
+}
+
//=======================================================================
/*!
* \brief Convert elements contained in a submesh to quadratic
- * \retval int - nb of checked elements
+ * \return int - nb of checked elements
*/
//=======================================================================
if( !theSm ) return nbElem;
vector<int> nbNodeInFaces;
+ vector<const SMDS_MeshNode *> nodes;
SMDS_ElemIteratorPtr ElemItr = theSm->GetElements();
while(ElemItr->more())
{
const SMDS_MeshElement* elem = ElemItr->next();
if( !elem || elem->IsQuadratic() ) continue;
- int id = elem->GetID();
- //MESSAGE("elem " << id);
- id = 0; // get a free number for new elements
- int nbNodes = elem->NbNodes();
- SMDSAbs_ElementType aType = elem->GetType();
-
- vector<const SMDS_MeshNode *> nodes (elem->begin_nodes(), elem->end_nodes());
- if ( elem->GetEntityType() == SMDSEntity_Polyhedra )
+ // get elem data needed to re-create it
+ //
+ const int id = elem->GetID();
+ const int nbNodes = elem->NbNodes();
+ const SMDSAbs_ElementType aType = elem->GetType();
+ const SMDSAbs_EntityType aGeomType = elem->GetEntityType();
+ nodes.assign(elem->begin_nodes(), elem->end_nodes());
+ if ( aGeomType == SMDSEntity_Polyhedra )
nbNodeInFaces = static_cast<const SMDS_VtkVolume* >( elem )->GetQuantities();
+ else if ( aGeomType == SMDSEntity_Hexagonal_Prism )
+ volumeToPolyhedron( elem, nodes, nbNodeInFaces );
+
+ // remove a linear element
+ GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
const SMDS_MeshElement* NewElem = 0;
}
case SMDSAbs_Volume :
{
- switch(nbNodes)
+ switch( aGeomType )
{
- case 4:
+ case SMDSEntity_Tetra:
NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
break;
- case 5:
+ case SMDSEntity_Pyramid:
NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], id, theForce3d);
break;
- case 6:
+ case SMDSEntity_Penta:
NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], nodes[4], nodes[5], id, theForce3d);
break;
- case 8:
+ case SMDSEntity_Hexa:
NewElem = theHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
break;
+ case SMDSEntity_Hexagonal_Prism:
default:
NewElem = theHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
}
ReplaceElemInGroups( elem, NewElem, GetMeshDS());
if( NewElem )
theSm->AddElement( NewElem );
-
- GetMeshDS()->RemoveFreeElement(elem, theSm, /*fromGroups=*/false);
}
-// if (!GetMeshDS()->isCompacted())
-// GetMeshDS()->compactMesh();
return nbElem;
}
//function : ConvertToQuadratic
//purpose :
//=======================================================================
+
void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d)
{
SMESHDS_Mesh* meshDS = GetMeshDS();
const SMDS_MeshFace* face = aFaceItr->next();
if(!face || face->IsQuadratic() ) continue;
- int id = face->GetID();
- int nbNodes = face->NbNodes();
+ const int id = face->GetID();
+ const SMDSAbs_EntityType type = face->GetEntityType();
vector<const SMDS_MeshNode *> nodes ( face->begin_nodes(), face->end_nodes());
meshDS->RemoveFreeElement(face, smDS, /*fromGroups=*/false);
SMDS_MeshFace * NewFace = 0;
- switch(nbNodes)
+ switch( type )
{
- case 3:
+ case SMDSEntity_Triangle:
NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], id, theForce3d);
break;
- case 4:
+ case SMDSEntity_Quadrangle:
NewFace = aHelper.AddFace(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
break;
default:
const SMDS_MeshVolume* volume = aVolumeItr->next();
if(!volume || volume->IsQuadratic() ) continue;
- int id = volume->GetID();
- int nbNodes = volume->NbNodes();
+ const int id = volume->GetID();
+ const SMDSAbs_EntityType type = volume->GetEntityType();
vector<const SMDS_MeshNode *> nodes (volume->begin_nodes(), volume->end_nodes());
- if ( volume->GetEntityType() == SMDSEntity_Polyhedra )
+ if ( type == SMDSEntity_Polyhedra )
nbNodeInFaces = static_cast<const SMDS_VtkVolume* >(volume)->GetQuantities();
+ else if ( type == SMDSEntity_Hexagonal_Prism )
+ volumeToPolyhedron( volume, nodes, nbNodeInFaces );
meshDS->RemoveFreeElement(volume, smDS, /*fromGroups=*/false);
SMDS_MeshVolume * NewVolume = 0;
- switch(nbNodes)
+ switch ( type )
{
- case 4:
- NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
- nodes[3], id, theForce3d );
+ case SMDSEntity_Tetra:
+ NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d );
+ break;
+ case SMDSEntity_Hexa:
+ NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
break;
- case 5:
+ case SMDSEntity_Pyramid:
NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
nodes[3], nodes[4], id, theForce3d);
break;
- case 6:
+ case SMDSEntity_Penta:
NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2],
nodes[3], nodes[4], nodes[5], id, theForce3d);
break;
- case 8:
- NewVolume = aHelper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
- nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
- break;
+ case SMDSEntity_Hexagonal_Prism:
default:
NewVolume = aHelper.AddPolyhedralVolume(nodes, nbNodeInFaces, id, theForce3d);
}
}
}
- if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
+ if ( !theForce3d )
{ // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
aHelper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
- aHelper.FixQuadraticElements();
+ aHelper.FixQuadraticElements(myError);
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Makes given elements quadratic
+ * \param theForce3d - if true, the medium nodes will be placed in the middle of link
+ * \param theElements - elements to make quadratic
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ConvertToQuadratic(const bool theForce3d,
+ TIDSortedElemSet& theElements)
+{
+ if ( theElements.empty() ) return;
+
+ // we believe that all theElements are of the same type
+ const SMDSAbs_ElementType elemType = (*theElements.begin())->GetType();
+
+ // get all nodes shared by theElements
+ TIDSortedNodeSet allNodes;
+ TIDSortedElemSet::iterator eIt = theElements.begin();
+ for ( ; eIt != theElements.end(); ++eIt )
+ allNodes.insert( (*eIt)->begin_nodes(), (*eIt)->end_nodes() );
+
+ // complete theElements with elements of lower dim whose all nodes are in allNodes
+
+ TIDSortedElemSet quadAdjacentElems [ SMDSAbs_NbElementTypes ]; // quadratic adjacent elements
+ TIDSortedElemSet checkedAdjacentElems [ SMDSAbs_NbElementTypes ];
+ TIDSortedNodeSet::iterator nIt = allNodes.begin();
+ for ( ; nIt != allNodes.end(); ++nIt )
+ {
+ const SMDS_MeshNode* n = *nIt;
+ SMDS_ElemIteratorPtr invIt = n->GetInverseElementIterator();
+ while ( invIt->more() )
+ {
+ const SMDS_MeshElement* e = invIt->next();
+ if ( e->IsQuadratic() )
+ {
+ quadAdjacentElems[ e->GetType() ].insert( e );
+ continue;
+ }
+ if ( e->GetType() >= elemType )
+ {
+ continue; // same type of more complex linear element
+ }
+
+ if ( !checkedAdjacentElems[ e->GetType() ].insert( e ).second )
+ continue; // e is already checked
+
+ // check nodes
+ bool allIn = true;
+ SMDS_ElemIteratorPtr nodeIt = e->nodesIterator();
+ while ( nodeIt->more() && allIn )
+ allIn = allNodes.count( cast2Node( nodeIt->next() ));
+ if ( allIn )
+ theElements.insert(e );
+ }
+ }
+
+ SMESH_MesherHelper helper(*myMesh);
+ helper.SetIsQuadratic( true );
+
+ // add links of quadratic adjacent elements to the helper
+
+ if ( !quadAdjacentElems[SMDSAbs_Edge].empty() )
+ for ( eIt = quadAdjacentElems[SMDSAbs_Edge].begin();
+ eIt != quadAdjacentElems[SMDSAbs_Edge].end(); ++eIt )
+ {
+ helper.AddTLinks( static_cast< const SMDS_MeshEdge*> (*eIt) );
+ }
+ if ( !quadAdjacentElems[SMDSAbs_Face].empty() )
+ for ( eIt = quadAdjacentElems[SMDSAbs_Face].begin();
+ eIt != quadAdjacentElems[SMDSAbs_Face].end(); ++eIt )
+ {
+ helper.AddTLinks( static_cast< const SMDS_MeshFace*> (*eIt) );
+ }
+ if ( !quadAdjacentElems[SMDSAbs_Volume].empty() )
+ for ( eIt = quadAdjacentElems[SMDSAbs_Volume].begin();
+ eIt != quadAdjacentElems[SMDSAbs_Volume].end(); ++eIt )
+ {
+ helper.AddTLinks( static_cast< const SMDS_MeshVolume*> (*eIt) );
+ }
+
+ // make quadratic elements instead of linear ones
+
+ SMESHDS_Mesh* meshDS = GetMeshDS();
+ SMESHDS_SubMesh* smDS = 0;
+ for ( eIt = theElements.begin(); eIt != theElements.end(); ++eIt )
+ {
+ const SMDS_MeshElement* elem = *eIt;
+ if( elem->IsQuadratic() || elem->NbNodes() < 2 || elem->IsPoly() )
+ continue;
+
+ const int id = elem->GetID();
+ const SMDSAbs_ElementType type = elem->GetType();
+ vector<const SMDS_MeshNode *> nodes ( elem->begin_nodes(), elem->end_nodes());
+
+ if ( !smDS || !smDS->Contains( elem ))
+ smDS = meshDS->MeshElements( elem->getshapeId() );
+ meshDS->RemoveFreeElement(elem, smDS, /*fromGroups=*/false);
+
+ SMDS_MeshElement * newElem = 0;
+ switch( nodes.size() )
+ {
+ case 4: // cases for most frequently used element types go first (for optimization)
+ if ( type == SMDSAbs_Volume )
+ newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+ else
+ newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], nodes[3], id, theForce3d);
+ break;
+ case 8:
+ newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5], nodes[6], nodes[7], id, theForce3d);
+ break;
+ case 3:
+ newElem = helper.AddFace (nodes[0], nodes[1], nodes[2], id, theForce3d);
+ break;
+ case 2:
+ newElem = helper.AddEdge(nodes[0], nodes[1], id, theForce3d);
+ break;
+ case 5:
+ newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], id, theForce3d);
+ break;
+ case 6:
+ newElem = helper.AddVolume(nodes[0], nodes[1], nodes[2], nodes[3],
+ nodes[4], nodes[5], id, theForce3d);
+ break;
+ default:;
+ }
+ ReplaceElemInGroups( elem, newElem, meshDS);
+ if( newElem && smDS )
+ smDS->AddElement( newElem );
+ }
+
+ if ( !theForce3d && !getenv("NO_FixQuadraticElements"))
+ { // setenv NO_FixQuadraticElements to know if FixQuadraticElements() is guilty of bad conversion
+ helper.SetSubShape(0); // apply FixQuadraticElements() to the whole mesh
+ helper.FixQuadraticElements( myError );
}
- if (!GetMeshDS()->isCompacted())
- GetMeshDS()->compactMesh();
}
//=======================================================================
/*!
* \brief Convert quadratic elements to linear ones and remove quadratic nodes
- * \retval int - nb of checked elements
+ * \return int - nb of checked elements
*/
//=======================================================================
{
int nbElem = 0;
SMESHDS_Mesh* meshDS = GetMeshDS();
- const bool notFromGroups = false;
while( theItr->more() )
{
nbElem++;
if( elem && elem->IsQuadratic())
{
- int id = elem->GetID();
- int nbNodes = elem->NbNodes();
- vector<const SMDS_MeshNode *> nodes, mediumNodes;
- nodes.reserve( nbNodes );
- mediumNodes.reserve( nbNodes );
-
- for(int i = 0; i < nbNodes; i++)
- {
- const SMDS_MeshNode* n = elem->GetNode(i);
-
- if( elem->IsMediumNode( n ) )
- mediumNodes.push_back( n );
- else
- nodes.push_back( n );
- }
- if( nodes.empty() ) continue;
+ int id = elem->GetID();
+ int nbCornerNodes = elem->NbCornerNodes();
SMDSAbs_ElementType aType = elem->GetType();
- //remove old quadratic element
- meshDS->RemoveFreeElement( elem, theSm, notFromGroups );
+ vector<const SMDS_MeshNode *> nodes( elem->begin_nodes(), elem->end_nodes() );
- SMDS_MeshElement * NewElem = AddElement( nodes, aType, false, id );
- ReplaceElemInGroups(elem, NewElem, meshDS);
- if( theSm && NewElem )
- theSm->AddElement( NewElem );
+ //remove a quadratic element
+ if ( !theSm || !theSm->Contains( elem ))
+ theSm = meshDS->MeshElements( elem->getshapeId() );
+ meshDS->RemoveFreeElement( elem, theSm, /*fromGroups=*/false );
// remove medium nodes
- vector<const SMDS_MeshNode*>::iterator nIt = mediumNodes.begin();
- for ( ; nIt != mediumNodes.end(); ++nIt ) {
- const SMDS_MeshNode* n = *nIt;
- if ( n->NbInverseElements() == 0 ) {
- if ( n->getshapeId() != theShapeID )
- meshDS->RemoveFreeNode( n, meshDS->MeshElements
- ( n->getshapeId() ));
- else
- meshDS->RemoveFreeNode( n, theSm );
- }
- }
+ for ( unsigned i = nbCornerNodes; i < nodes.size(); ++i )
+ if ( nodes[i]->NbInverseElements() == 0 )
+ meshDS->RemoveFreeNode( nodes[i], theSm );
+
+ // add a linear element
+ nodes.resize( nbCornerNodes );
+ SMDS_MeshElement * newElem = AddElement( nodes, aType, false, id );
+ ReplaceElemInGroups(elem, newElem, meshDS);
+ if( theSm && newElem )
+ theSm->AddElement( newElem );
}
}
return nbElem;
//function : ConvertFromQuadratic
//purpose :
//=======================================================================
-bool SMESH_MeshEditor::ConvertFromQuadratic()
+
+bool SMESH_MeshEditor::ConvertFromQuadratic()
{
int nbCheckedElems = 0;
if ( myMesh->HasShapeToMesh() )
return true;
}
+namespace
+{
+ //================================================================================
+ /*!
+ * \brief Return true if all medium nodes of the element are in the node set
+ */
+ //================================================================================
+
+ bool allMediumNodesIn(const SMDS_MeshElement* elem, TIDSortedNodeSet& nodeSet )
+ {
+ for ( int i = elem->NbCornerNodes(); i < elem->NbNodes(); ++i )
+ if ( !nodeSet.count( elem->GetNode(i) ))
+ return false;
+ return true;
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Makes given elements linear
+ */
+//================================================================================
+
+void SMESH_MeshEditor::ConvertFromQuadratic(TIDSortedElemSet& theElements)
+{
+ if ( theElements.empty() ) return;
+
+ // collect IDs of medium nodes of theElements; some of these nodes will be removed
+ set<int> mediumNodeIDs;
+ TIDSortedElemSet::iterator eIt = theElements.begin();
+ for ( ; eIt != theElements.end(); ++eIt )
+ {
+ const SMDS_MeshElement* e = *eIt;
+ for ( int i = e->NbCornerNodes(); i < e->NbNodes(); ++i )
+ mediumNodeIDs.insert( e->GetNode(i)->GetID() );
+ }
+
+ // replace given elements by linear ones
+ typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::iterator> TSetIterator;
+ SMDS_ElemIteratorPtr elemIt( new TSetIterator( theElements.begin(), theElements.end() ));
+ removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
+
+ // we need to convert remaining elements whose all medium nodes are in mediumNodeIDs
+ // except those elements sharing medium nodes of quadratic element whose medium nodes
+ // are not all in mediumNodeIDs
+
+ // get remaining medium nodes
+ TIDSortedNodeSet mediumNodes;
+ set<int>::iterator nIdsIt = mediumNodeIDs.begin();
+ for ( ; nIdsIt != mediumNodeIDs.end(); ++nIdsIt )
+ if ( const SMDS_MeshNode* n = GetMeshDS()->FindNode( *nIdsIt ))
+ mediumNodes.insert( mediumNodes.end(), n );
+
+ // find more quadratic elements to convert
+ TIDSortedElemSet moreElemsToConvert;
+ TIDSortedNodeSet::iterator nIt = mediumNodes.begin();
+ for ( ; nIt != mediumNodes.end(); ++nIt )
+ {
+ SMDS_ElemIteratorPtr invIt = (*nIt)->GetInverseElementIterator();
+ while ( invIt->more() )
+ {
+ const SMDS_MeshElement* e = invIt->next();
+ if ( e->IsQuadratic() && allMediumNodesIn( e, mediumNodes ))
+ {
+ // find a more complex element including e and
+ // whose medium nodes are not in mediumNodes
+ bool complexFound = false;
+ for ( int type = e->GetType() + 1; type < SMDSAbs_0DElement; ++type )
+ {
+ SMDS_ElemIteratorPtr invIt2 =
+ (*nIt)->GetInverseElementIterator( SMDSAbs_ElementType( type ));
+ while ( invIt2->more() )
+ {
+ const SMDS_MeshElement* eComplex = invIt2->next();
+ if ( eComplex->IsQuadratic() && !allMediumNodesIn( eComplex, mediumNodes))
+ {
+ int nbCommonNodes = SMESH_Algo::GetCommonNodes( e, eComplex ).size();
+ if ( nbCommonNodes == e->NbNodes())
+ {
+ complexFound = true;
+ type = SMDSAbs_NbElementTypes; // to quit from the outer loop
+ break;
+ }
+ }
+ }
+ }
+ if ( !complexFound )
+ moreElemsToConvert.insert( e );
+ }
+ }
+ }
+ elemIt = SMDS_ElemIteratorPtr
+ (new TSetIterator( moreElemsToConvert.begin(), moreElemsToConvert.end() ));
+ removeQuadElem( /*theSm=*/0, elemIt, /*theShapeID=*/0 );
+}
+
//=======================================================================
//function : SewSideElements
//purpose :
SMESHDS_Mesh* aMesh = GetMeshDS();
// TODO algoritm not OK with vtkUnstructuredGrid: 2 meshes can't share nodes
//SMDS_Mesh aTmpFacesMesh; // try to use the same mesh
- set<const SMDS_MeshElement*> faceSet1, faceSet2;
+ TIDSortedElemSet faceSet1, faceSet2;
set<const SMDS_MeshElement*> volSet1, volSet2;
set<const SMDS_MeshNode*> nodeSet1, nodeSet2;
- set<const SMDS_MeshElement*> * faceSetPtr[] = { &faceSet1, &faceSet2 };
- set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
+ TIDSortedElemSet * faceSetPtr[] = { &faceSet1, &faceSet2 };
+ set<const SMDS_MeshElement*> * volSetPtr[] = { &volSet1, &volSet2 };
set<const SMDS_MeshNode*> * nodeSetPtr[] = { &nodeSet1, &nodeSet2 };
- TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
+ TIDSortedElemSet * elemSetPtr[] = { &theSide1, &theSide2 };
int iSide, iFace, iNode;
list<const SMDS_MeshElement* > tempFaceList;
for ( iSide = 0; iSide < 2; iSide++ ) {
set<const SMDS_MeshNode*> * nodeSet = nodeSetPtr[ iSide ];
- TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
- set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
+ TIDSortedElemSet * elemSet = elemSetPtr[ iSide ];
+ TIDSortedElemSet * faceSet = faceSetPtr[ iSide ];
set<const SMDS_MeshElement*> * volSet = volSetPtr [ iSide ];
set<const SMDS_MeshElement*>::iterator vIt;
TIDSortedElemSet::iterator eIt;
bool isNewFace = setOfFaceNodeSet.insert( faceNodeSet ).second;
if ( isNewFace ) {
// no such a face is given but it still can exist, check it
- if ( nbNodes == 3 ) {
- aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2] );
- }
- else if ( nbNodes == 4 ) {
- aFreeFace = aMesh->FindFace( fNodes[0],fNodes[1],fNodes[2],fNodes[3] );
- }
- else {
- vector<const SMDS_MeshNode *> poly_nodes ( fNodes, & fNodes[nbNodes]);
- aFreeFace = aMesh->FindFace(poly_nodes);
- }
- }
- if ( !aFreeFace ) {
- // create a temporary face
+ vector<const SMDS_MeshNode *> nodes ( fNodes, fNodes + nbNodes);
+ aFreeFace = aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false );
+ }
+ if ( !aFreeFace ) {
+ // create a temporary face
if ( nbNodes == 3 ) {
//aFreeFace = aTmpFacesMesh.AddFace( fNodes[0],fNodes[1],fNodes[2] );
aFreeFace = aMesh->AddFace( fNodes[0],fNodes[1],fNodes[2] );
//aFreeFace = aTmpFacesMesh.AddPolygonalFace(poly_nodes);
aFreeFace = aMesh->AddPolygonalFace(poly_nodes);
}
+ if ( aFreeFace )
+ tempFaceList.push_back( aFreeFace );
}
- if ( aFreeFace ) {
+
+ if ( aFreeFace )
freeFaceList.push_back( aFreeFace );
- tempFaceList.push_back( aFreeFace );
- }
} // loop on faces of a volume
- // choose one of several free faces
- // --------------------------------------
+ // choose one of several free faces of a volume
+ // --------------------------------------------
if ( freeFaceList.size() > 1 ) {
// choose a face having max nb of nodes shared by other elems of a side
- int maxNbNodes = -1/*, nbExcludedFaces = 0*/;
+ int maxNbNodes = -1;
list<const SMDS_MeshElement* >::iterator fIt = freeFaceList.begin();
while ( fIt != freeFaceList.end() ) { // loop on free faces
int nbSharedNodes = 0;
SMDS_ElemIteratorPtr invElemIt = n->GetInverseElementIterator();
while ( invElemIt->more() ) {
const SMDS_MeshElement* e = invElemIt->next();
- if ( faceSet->find( e ) != faceSet->end() )
- nbSharedNodes++;
- if ( elemSet->find( e ) != elemSet->end() )
- nbSharedNodes++;
+ nbSharedNodes += faceSet->count( e );
+ nbSharedNodes += elemSet->count( e );
}
}
- if ( nbSharedNodes >= maxNbNodes ) {
+ if ( nbSharedNodes > maxNbNodes ) {
maxNbNodes = nbSharedNodes;
+ freeFaceList.erase( freeFaceList.begin(), fIt++ );
+ }
+ else if ( nbSharedNodes == maxNbNodes ) {
fIt++;
}
- else
+ else {
freeFaceList.erase( fIt++ ); // here fIt++ occurs before erase
+ }
}
if ( freeFaceList.size() > 1 )
{
TNodeNodeMap nReplaceMap; // bind a node to remove to a node to put instead
if ( theFirstNode1 != theFirstNode2 )
- nReplaceMap.insert( TNodeNodeMap::value_type( theFirstNode1, theFirstNode2 ));
+ nReplaceMap.insert( make_pair( theFirstNode1, theFirstNode2 ));
if ( theSecondNode1 != theSecondNode2 )
- nReplaceMap.insert( TNodeNodeMap::value_type( theSecondNode1, theSecondNode2 ));
+ nReplaceMap.insert( make_pair( theSecondNode1, theSecondNode2 ));
LinkID_Gen aLinkID_Gen( GetMeshDS() );
set< long > linkIdSet; // links to process
// loop on links in linkList; find faces by links and append links
// of the found faces to linkList
list< NLink >::iterator linkIt[] = { linkList[0].begin(), linkList[1].begin() } ;
- for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ ) {
+ for ( ; linkIt[0] != linkList[0].end(); linkIt[0]++, linkIt[1]++ )
+ {
NLink link[] = { *linkIt[0], *linkIt[1] };
long linkID = aLinkID_Gen.GetLinkID( link[0].first, link[0].second );
- if ( linkIdSet.find( linkID ) == linkIdSet.end() )
+ if ( !linkIdSet.count( linkID ) )
continue;
// by links, find faces in the face sets,
// ---------------------------------------------------------------
const SMDS_MeshElement* face[] = { 0, 0 };
- //const SMDS_MeshNode* faceNodes[ 2 ][ 5 ];
- vector<const SMDS_MeshNode*> fnodes1(9);
- vector<const SMDS_MeshNode*> fnodes2(9);
- //const SMDS_MeshNode* notLinkNodes[ 2 ][ 2 ] = {{ 0, 0 },{ 0, 0 }} ;
- vector<const SMDS_MeshNode*> notLinkNodes1(6);
- vector<const SMDS_MeshNode*> notLinkNodes2(6);
+ vector<const SMDS_MeshNode*> fnodes[2];
int iLinkNode[2][2];
+ TIDSortedElemSet avoidSet;
for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
const SMDS_MeshNode* n1 = link[iSide].first;
const SMDS_MeshNode* n2 = link[iSide].second;
- set<const SMDS_MeshElement*> * faceSet = faceSetPtr[ iSide ];
- set< const SMDS_MeshElement* > fMap;
- for ( int i = 0; i < 2; i++ ) { // loop on 2 nodes of a link
- const SMDS_MeshNode* n = i ? n1 : n2; // a node of a link
- SMDS_ElemIteratorPtr fIt = n->GetInverseElementIterator(SMDSAbs_Face);
- while ( fIt->more() ) { // loop on faces sharing a node
- const SMDS_MeshElement* f = fIt->next();
- if (faceSet->find( f ) != faceSet->end() && // f is in face set
- ! fMap.insert( f ).second ) // f encounters twice
- {
- if ( face[ iSide ] ) {
- MESSAGE( "2 faces per link " );
- aResult = iSide ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES;
- break;
- }
- face[ iSide ] = f;
- faceSet->erase( f );
- // get face nodes and find ones of a link
- iNode = 0;
- int nbl = -1;
- if(f->IsPoly()) {
- if(iSide==0) {
- fnodes1.resize(f->NbNodes()+1);
- notLinkNodes1.resize(f->NbNodes()-2);
- }
- else {
- fnodes2.resize(f->NbNodes()+1);
- notLinkNodes2.resize(f->NbNodes()-2);
- }
- }
- if(!f->IsQuadratic()) {
- SMDS_ElemIteratorPtr nIt = f->nodesIterator();
- while ( nIt->more() ) {
- const SMDS_MeshNode* n =
- static_cast<const SMDS_MeshNode*>( nIt->next() );
- if ( n == n1 ) {
- iLinkNode[ iSide ][ 0 ] = iNode;
- }
- else if ( n == n2 ) {
- iLinkNode[ iSide ][ 1 ] = iNode;
- }
- //else if ( notLinkNodes[ iSide ][ 0 ] )
- // notLinkNodes[ iSide ][ 1 ] = n;
- //else
- // notLinkNodes[ iSide ][ 0 ] = n;
- else {
- nbl++;
- if(iSide==0)
- notLinkNodes1[nbl] = n;
- //notLinkNodes1.push_back(n);
- else
- notLinkNodes2[nbl] = n;
- //notLinkNodes2.push_back(n);
- }
- //faceNodes[ iSide ][ iNode++ ] = n;
- if(iSide==0) {
- fnodes1[iNode++] = n;
- }
- else {
- fnodes2[iNode++] = n;
- }
- }
- }
- else { // f->IsQuadratic()
- const SMDS_VtkFace* F =
- dynamic_cast<const SMDS_VtkFace*>(f);
- if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
- // use special nodes iterator
- SMDS_ElemIteratorPtr anIter = F->interlacedNodesElemIterator();
- while ( anIter->more() ) {
- const SMDS_MeshNode* n =
- static_cast<const SMDS_MeshNode*>( anIter->next() );
- if ( n == n1 ) {
- iLinkNode[ iSide ][ 0 ] = iNode;
- }
- else if ( n == n2 ) {
- iLinkNode[ iSide ][ 1 ] = iNode;
- }
- else {
- nbl++;
- if(iSide==0) {
- notLinkNodes1[nbl] = n;
- }
- else {
- notLinkNodes2[nbl] = n;
- }
- }
- if(iSide==0) {
- fnodes1[iNode++] = n;
- }
- else {
- fnodes2[iNode++] = n;
- }
- }
- }
- //faceNodes[ iSide ][ iNode ] = faceNodes[ iSide ][ 0 ];
- if(iSide==0) {
- fnodes1[iNode] = fnodes1[0];
- }
- else {
- fnodes2[iNode] = fnodes1[0];
- }
- }
+ //cout << "Side " << iSide << " ";
+ //cout << "L( " << n1->GetID() << ", " << n2->GetID() << " ) " << endl;
+ // find a face by two link nodes
+ face[ iSide ] = FindFaceInSet( n1, n2, *faceSetPtr[ iSide ], avoidSet,
+ &iLinkNode[iSide][0], &iLinkNode[iSide][1] );
+ if ( face[ iSide ])
+ {
+ //cout << " F " << face[ iSide]->GetID() <<endl;
+ faceSetPtr[ iSide ]->erase( face[ iSide ]);
+ // put face nodes to fnodes
+ if ( face[ iSide ]->IsQuadratic() )
+ {
+ // use interlaced nodes iterator
+ const SMDS_VtkFace* F = dynamic_cast<const SMDS_VtkFace*>( face[ iSide ]);
+ if (!F) throw SALOME_Exception(LOCALIZED("not an SMDS_VtkFace"));
+ SMDS_ElemIteratorPtr nIter = F->interlacedNodesElemIterator();
+ while ( nIter->more() )
+ fnodes[ iSide ].push_back( cast2Node( nIter->next() ));
+ }
+ else
+ {
+ fnodes[ iSide ].assign( face[ iSide ]->begin_nodes(),
+ face[ iSide ]->end_nodes() );
}
+ fnodes[ iSide ].push_back( fnodes[ iSide ].front());
}
}
// check similarity of elements of the sides
- if (aResult == SEW_OK && ( face[0] && !face[1] ) || ( !face[0] && face[1] )) {
+ if (aResult == SEW_OK && (( face[0] && !face[1] ) || ( !face[0] && face[1] ))) {
MESSAGE("Correspondent face not found on side " << ( face[0] ? 1 : 0 ));
if ( nReplaceMap.size() == 2 ) { // faces on input nodes not found
aResult = ( face[0] ? SEW_BAD_SIDE2_NODES : SEW_BAD_SIDE1_NODES );
else {
aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
}
- break; // do not return because it s necessary to remove tmp faces
+ break; // do not return because it's necessary to remove tmp faces
}
// set nodes to merge
// -------------------
if ( face[0] && face[1] ) {
- int nbNodes = face[0]->NbNodes();
+ const int nbNodes = face[0]->NbNodes();
if ( nbNodes != face[1]->NbNodes() ) {
MESSAGE("Diff nb of face nodes");
aResult = SEW_TOPO_DIFF_SETS_OF_ELEMENTS;
break; // do not return because it s necessary to remove tmp faces
}
- bool reverse[] = { false, false }; // order of notLinkNodes of quadrangle
- if ( nbNodes == 3 ) {
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
- nReplaceMap.insert( TNodeNodeMap::value_type
- ( notLinkNodes1[0], notLinkNodes2[0] ));
+ bool reverse[] = { false, false }; // order of nodes in the link
+ for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
+ // analyse link orientation in faces
+ int i1 = iLinkNode[ iSide ][ 0 ];
+ int i2 = iLinkNode[ iSide ][ 1 ];
+ reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
}
- else {
- for ( iSide = 0; iSide < 2; iSide++ ) { // loop on 2 sides
- // analyse link orientation in faces
- int i1 = iLinkNode[ iSide ][ 0 ];
- int i2 = iLinkNode[ iSide ][ 1 ];
- reverse[ iSide ] = Abs( i1 - i2 ) == 1 ? i1 > i2 : i2 > i1;
- // if notLinkNodes are the first and the last ones, then
- // their order does not correspond to the link orientation
- if (( i1 == 1 && i2 == 2 ) ||
- ( i1 == 2 && i2 == 1 ))
- reverse[ iSide ] = !reverse[ iSide ];
- }
- if ( reverse[0] == reverse[1] ) {
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][0], notLinkNodes[1][0] ));
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][1], notLinkNodes[1][1] ));
- for(int nn=0; nn<nbNodes-2; nn++) {
- nReplaceMap.insert( TNodeNodeMap::value_type
- ( notLinkNodes1[nn], notLinkNodes2[nn] ));
- }
- }
- else {
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][0], notLinkNodes[1][1] ));
- //nReplaceMap.insert( TNodeNodeMap::value_type
- // ( notLinkNodes[0][1], notLinkNodes[1][0] ));
- for(int nn=0; nn<nbNodes-2; nn++) {
- nReplaceMap.insert( TNodeNodeMap::value_type
- ( notLinkNodes1[nn], notLinkNodes2[nbNodes-3-nn] ));
- }
- }
+ int di1 = reverse[0] ? -1 : +1, i1 = iLinkNode[0][1] + di1;
+ int di2 = reverse[1] ? -1 : +1, i2 = iLinkNode[1][1] + di2;
+ for ( int i = nbNodes - 2; i > 0; --i, i1 += di1, i2 += di2 )
+ {
+ nReplaceMap.insert ( make_pair ( fnodes[0][ ( i1 + nbNodes ) % nbNodes ],
+ fnodes[1][ ( i2 + nbNodes ) % nbNodes ]));
}
// add other links of the faces to linkList
// -----------------------------------------
- //const SMDS_MeshNode** nodes = faceNodes[ 0 ];
for ( iNode = 0; iNode < nbNodes; iNode++ ) {
- //linkID = aLinkID_Gen.GetLinkID( nodes[iNode], nodes[iNode+1] );
- linkID = aLinkID_Gen.GetLinkID( fnodes1[iNode], fnodes1[iNode+1] );
+ linkID = aLinkID_Gen.GetLinkID( fnodes[0][iNode], fnodes[0][iNode+1] );
pair< set<long>::iterator, bool > iter_isnew = linkIdSet.insert( linkID );
if ( !iter_isnew.second ) { // already in a set: no need to process
linkIdSet.erase( iter_isnew.first );
}
else // new in set == encountered for the first time: add
{
- //const SMDS_MeshNode* n1 = nodes[ iNode ];
- //const SMDS_MeshNode* n2 = nodes[ iNode + 1];
- const SMDS_MeshNode* n1 = fnodes1[ iNode ];
- const SMDS_MeshNode* n2 = fnodes1[ iNode + 1];
+ const SMDS_MeshNode* n1 = fnodes[0][ iNode ];
+ const SMDS_MeshNode* n2 = fnodes[0][ iNode + 1];
linkList[0].push_back ( NLink( n1, n2 ));
linkList[1].push_back ( NLink( nReplaceMap[n1], nReplaceMap[n2] ));
}
}
} // 2 faces found
+
+ if ( faceSetPtr[0]->empty() || faceSetPtr[1]->empty() )
+ break;
+
} // loop on link lists
if ( aResult == SEW_OK &&
- ( linkIt[0] != linkList[0].end() ||
+ ( //linkIt[0] != linkList[0].end() ||
!faceSetPtr[0]->empty() || !faceSetPtr[1]->empty() )) {
MESSAGE( (linkIt[0] != linkList[0].end()) <<" "<< (faceSetPtr[0]->empty()) <<
" " << (faceSetPtr[1]->empty()));
// 3. Replace nodes in elements of the side 1 and remove replaced nodes
// ====================================================================
- // delete temporary faces: they are in reverseElements of actual nodes
+ // delete temporary faces
// SMDS_FaceIteratorPtr tmpFaceIt = aTmpFacesMesh.facesIterator();
// while ( tmpFaceIt->more() )
// aTmpFacesMesh.RemoveElement( tmpFaceIt->next() );
-// list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
-// for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
-// aMesh->RemoveElement(*tmpFaceIt);
+ list<const SMDS_MeshElement* >::iterator tmpFaceIt = tempFaceList.begin();
+ for (; tmpFaceIt !=tempFaceList.end(); ++tmpFaceIt)
+ aMesh->RemoveElement(*tmpFaceIt);
if ( aResult != SEW_OK)
return aResult;
* \param theSecondNode1 - a boundary node of set 1 linked with theFirstNode1
* \param theSecondNode2 - a node of set 2 corresponding to theSecondNode1
* \param nReplaceMap - output map of corresponding nodes
- * \retval bool - is a success or not
+ * \return bool - is a success or not
*/
//================================================================================
\param theElems - the list of elements (edges or faces) to be replicated
The nodes for duplication could be found from these elements
\param theNodesNot - list of nodes to NOT replicate
- \param theAffectedElems - the list of elements (cells and edges) to which the
+ \param theAffectedElems - the list of elements (cells and edges) to which the
replicated nodes should be associated to.
\return TRUE if operation has been completed successfully, FALSE otherwise
*/
std::vector<const SMDS_MeshNode*> newNodes( anElem->NbNodes() );
SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
int ind = 0;
- while ( anIter->more() )
- {
+ while ( anIter->more() )
+ {
SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
SMDS_MeshNode* aNewNode = aCurrNode;
/*!
\brief Creates a hole in a mesh by doubling the nodes of some particular elements
\param theNodes - identifiers of nodes to be doubled
- \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
- nodes. If list of element identifiers is empty then nodes are doubled but
+ \param theModifiedElems - identifiers of elements to be updated by the new (doubled)
+ nodes. If list of element identifiers is empty then nodes are doubled but
they not assigned to elements
\return TRUE if operation has been completed successfully, FALSE otherwise
*/
//================================================================================
-bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
+bool SMESH_MeshEditor::DoubleNodes( const std::list< int >& theListOfNodes,
const std::list< int >& theListOfModifiedElems )
{
MESSAGE("DoubleNodes");
std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> > anElemToNodes;
std::list< int >::const_iterator anElemIter;
- for ( anElemIter = theListOfModifiedElems.begin();
+ for ( anElemIter = theListOfModifiedElems.begin();
anElemIter != theListOfModifiedElems.end(); ++anElemIter )
{
int aCurr = *anElemIter;
SMDS_ElemIteratorPtr anIter = anElem->nodesIterator();
int ind = 0;
- while ( anIter->more() )
- {
+ while ( anIter->more() )
+ {
SMDS_MeshNode* aCurrNode = (SMDS_MeshNode*)anIter->next();
if ( aCurr && anOldNodeToNewNode.find( aCurrNode ) != anOldNodeToNewNode.end() )
{
anElemToNodes[ anElem ] = aNodeArr;
}
- // Change nodes of elements
+ // Change nodes of elements
std::map< SMDS_MeshElement*, vector<const SMDS_MeshNode*> >::iterator
anElemToNodesIter = anElemToNodes.begin();
_extremum.Perform(aPnt);
if ( _extremum.IsDone() )
for ( int iSol = 1; iSol <= _extremum.NbExt() && _state == TopAbs_OUT; ++iSol)
+#if OCC_VERSION_LARGE > 0x06040000 // Porting to OCCT6.5.1
+ _state = ( _extremum.SquareDistance(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
+#else
_state = ( _extremum.Value(iSol) <= theTol ? TopAbs_IN : TopAbs_OUT );
+#endif
}
TopAbs_State State() const
{
};
}
+//================================================================================
+/*!
+ \brief Identify the elements that will be affected by node duplication (actual duplication is not performed.
+ This method is the first step of DoubleNodeElemGroupsInRegion.
+ \param theElems - list of groups of elements (edges or faces) to be replicated
+ \param theNodesNot - list of groups of nodes not to replicated
+ \param theShape - shape to detect affected elements (element which geometric center
+ located on or inside shape).
+ The replicated nodes should be associated to affected elements.
+ \return groups of affected elements
+ \sa DoubleNodeElemGroupsInRegion()
+ */
+//================================================================================
+
+bool SMESH_MeshEditor::AffectedElemGroupsInRegion( const TIDSortedElemSet& theElems,
+ const TIDSortedElemSet& theNodesNot,
+ const TopoDS_Shape& theShape,
+ TIDSortedElemSet& theAffectedElems)
+{
+ if ( theShape.IsNull() )
+ return false;
+
+ const double aTol = Precision::Confusion();
+ auto_ptr< BRepClass3d_SolidClassifier> bsc3d;
+ auto_ptr<_FaceClassifier> aFaceClassifier;
+ if ( theShape.ShapeType() == TopAbs_SOLID )
+ {
+ bsc3d.reset( new BRepClass3d_SolidClassifier(theShape));;
+ bsc3d->PerformInfinitePoint(aTol);
+ }
+ else if (theShape.ShapeType() == TopAbs_FACE )
+ {
+ aFaceClassifier.reset( new _FaceClassifier(TopoDS::Face(theShape)));
+ }
+
+ // iterates on indicated elements and get elements by back references from their nodes
+ TIDSortedElemSet::const_iterator elemItr = theElems.begin();
+ for ( ; elemItr != theElems.end(); ++elemItr )
+ {
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*)*elemItr;
+ if (!anElem)
+ continue;
+
+ SMDS_ElemIteratorPtr nodeItr = anElem->nodesIterator();
+ while ( nodeItr->more() )
+ {
+ const SMDS_MeshNode* aNode = cast2Node(nodeItr->next());
+ if ( !aNode || theNodesNot.find(aNode) != theNodesNot.end() )
+ continue;
+ SMDS_ElemIteratorPtr backElemItr = aNode->GetInverseElementIterator();
+ while ( backElemItr->more() )
+ {
+ const SMDS_MeshElement* curElem = backElemItr->next();
+ if ( curElem && theElems.find(curElem) == theElems.end() &&
+ ( bsc3d.get() ?
+ isInside( curElem, *bsc3d, aTol ) :
+ isInside( curElem, *aFaceClassifier, aTol )))
+ theAffectedElems.insert( curElem );
+ }
+ }
+ }
+ return true;
+}
+
//================================================================================
/*!
\brief Creates a hole in a mesh by doubling the nodes of some particular elements
return DoubleNodes( theElems, theNodesNot, anAffected );
}
+/*!
+ * \brief compute an oriented angle between two planes defined by four points.
+ * The vector (p0,p1) defines the intersection of the 2 planes (p0,p1,g1) and (p0,p1,g2)
+ * @param p0 base of the rotation axe
+ * @param p1 extremity of the rotation axe
+ * @param g1 belongs to the first plane
+ * @param g2 belongs to the second plane
+ */
+double SMESH_MeshEditor::OrientedAngle(const gp_Pnt& p0, const gp_Pnt& p1, const gp_Pnt& g1, const gp_Pnt& g2)
+{
+// MESSAGE(" p0: " << p0.X() << " " << p0.Y() << " " << p0.Z());
+// MESSAGE(" p1: " << p1.X() << " " << p1.Y() << " " << p1.Z());
+// MESSAGE(" g1: " << g1.X() << " " << g1.Y() << " " << g1.Z());
+// MESSAGE(" g2: " << g2.X() << " " << g2.Y() << " " << g2.Z());
+ gp_Vec vref(p0, p1);
+ gp_Vec v1(p0, g1);
+ gp_Vec v2(p0, g2);
+ gp_Vec n1 = vref.Crossed(v1);
+ gp_Vec n2 = vref.Crossed(v2);
+ return n2.AngleWithRef(n1, vref);
+}
+
/*!
* \brief Double nodes on shared faces between groups of volumes and create flat elements on demand.
* The list of groups must describe a partition of the mesh volumes.
* The nodes of the internal faces at the boundaries of the groups are doubled.
* In option, the internal faces are replaced by flat elements.
* Triangles are transformed in prisms, and quadrangles in hexahedrons.
+ * The flat elements are stored in groups of volumes.
* @param theElems - list of groups of volumes, where a group of volume is a set of
* SMDS_MeshElements sorted by Id.
* @param createJointElems - if TRUE, create the elements
bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSortedElemSet>& theElems,
bool createJointElems)
{
- MESSAGE("------------------------------------------------------");
- MESSAGE("SMESH_MeshEditor::CreateJointElementsOnGroupBoundaries");
- MESSAGE("------------------------------------------------------");
+ MESSAGE("----------------------------------------------");
+ MESSAGE("SMESH_MeshEditor::doubleNodesOnGroupBoundaries");
+ MESSAGE("----------------------------------------------");
SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
- meshDS->BuildDownWardConnectivity(false);
+ meshDS->BuildDownWardConnectivity(true);
CHRONO(50);
SMDS_UnstructuredGrid *grid = meshDS->getGrid();
// --- build the list of faces shared by 2 domains (group of elements), with their domain and volume indexes
+ // build the list of cells with only a node or an edge on the border, with their domain and volume indexes
// build the list of nodes shared by 2 or more domains, with their domain indexes
- std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // 2x(id domain --> id volume)
- std::map<int, std::map<int,int> > nodeDomains; //oldId -> (domainId -> newId)
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> faceDomains; // face --> (id domain --> id volume)
+ std::map<int,int>celldom; // cell vtkId --> domain
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> cellDomains; // oldNode --> (id domain --> id cell)
+ std::map<int, std::map<int,int> > nodeDomains; // oldId --> (domainId --> newId)
faceDomains.clear();
+ celldom.clear();
+ cellDomains.clear();
nodeDomains.clear();
std::map<int,int> emptyMap;
+ std::set<int> emptySet;
emptyMap.clear();
for (int idom = 0; idom < theElems.size(); idom++)
// --- build a map (face to duplicate --> volume to modify)
// with all the faces shared by 2 domains (group of elements)
// and corresponding volume of this domain, for each shared face.
- // a volume has a face shared by 2 domains if it has a neighbor which is not in is domain.
+ // a volume has a face shared by 2 domains if it has a neighbor which is not in his domain.
+ //MESSAGE("Domain " << idom);
const TIDSortedElemSet& domain = theElems[idom];
TIDSortedElemSet::const_iterator elemItr = domain.begin();
for (; elemItr != domain.end(); ++elemItr)
if (!anElem)
continue;
int vtkId = anElem->getVtkId();
+ //MESSAGE(" vtkId " << vtkId << " smdsId " << anElem->GetID());
int neighborsVtkIds[NBMAXNEIGHBORS];
int downIds[NBMAXNEIGHBORS];
unsigned char downTypes[NBMAXNEIGHBORS];
if (!faceDomains[face].count(idom))
{
faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+ celldom[vtkId] = idom;
+ //MESSAGE(" cell with a border " << vtkId << " domain " << idom);
}
}
}
}
}
- MESSAGE("Number of shared faces " << faceDomains.size());
+ //MESSAGE("Number of shared faces " << faceDomains.size());
+ std::map<DownIdType, std::map<int, int>, DownIdCompare>::iterator itface;
- // --- for each shared face, get the nodes
+ // --- explore the shared faces domain by domain,
+ // explore the nodes of the face and see if they belong to a cell in the domain,
+ // which has only a node or an edge on the border (not a shared face)
+
+ for (int idomain = 0; idomain < theElems.size(); idomain++)
+ {
+ //MESSAGE("Domain " << idomain);
+ const TIDSortedElemSet& domain = theElems[idomain];
+ itface = faceDomains.begin();
+ for (; itface != faceDomains.end(); ++itface)
+ {
+ std::map<int, int> domvol = itface->second;
+ if (!domvol.count(idomain))
+ continue;
+ DownIdType face = itface->first;
+ //MESSAGE(" --- face " << face.cellId);
+ std::set<int> oldNodes;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ std::set<int>::iterator itn = oldNodes.begin();
+ for (; itn != oldNodes.end(); ++itn)
+ {
+ int oldId = *itn;
+ //MESSAGE(" node " << oldId);
+ vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
+ for (int i=0; i<l.ncells; i++)
+ {
+ int vtkId = l.cells[i];
+ const SMDS_MeshElement* anElem = GetMeshDS()->FindElement(GetMeshDS()->fromVtkToSmds(vtkId));
+ if (!domain.count(anElem))
+ continue;
+ int vtkType = grid->GetCellType(vtkId);
+ int downId = grid->CellIdToDownId(vtkId);
+ if (downId < 0)
+ {
+ MESSAGE("doubleNodesOnGroupBoundaries: internal algorithm problem");
+ continue; // not OK at this stage of the algorithm:
+ //no cells created after BuildDownWardConnectivity
+ }
+ DownIdType aCell(downId, vtkType);
+ if (!cellDomains.count(aCell))
+ cellDomains[aCell] = emptyMap; // create an empty entry for cell
+ cellDomains[aCell][idomain] = vtkId;
+ celldom[vtkId] = idomain;
+ //MESSAGE(" cell " << vtkId << " domain " << idomain);
+ }
+ }
+ }
+ }
+
+ // --- explore the shared faces domain by domain, to duplicate the nodes in a coherent way
+ // for each shared face, get the nodes
// for each node, for each domain of the face, create a clone of the node
- std::map<DownIdType, std::map<int,int>, DownIdCompare>::iterator itface = faceDomains.begin();
- for( ; itface != faceDomains.end();++itface )
+ // --- edges at the intersection of 3 or 4 domains, with the order of domains to build
+ // junction elements of type prism or hexa. the key is the pair of nodesId (lower first)
+ // the value is the ordered domain ids. (more than 4 domains not taken into account)
+
+ std::map<std::vector<int>, std::vector<int> > edgesMultiDomains; // nodes of edge --> ordered domains
+ std::map<int, std::vector<int> > mutipleNodes; // nodes multi domains with domain order
+ std::map<int, std::vector<int> > mutipleNodesToFace; // nodes multi domains with domain order to transform in Face (junction between 3 or more 2D domains)
+
+ for (int idomain = 0; idomain < theElems.size(); idomain++)
{
- DownIdType face = itface->first;
- std::map<int,int> domvol = itface->second;
- std::set<int> oldNodes;
- oldNodes.clear();
- grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
- std::set<int>::iterator itn = oldNodes.begin();
- for (;itn != oldNodes.end(); ++itn)
+ itface = faceDomains.begin();
+ for (; itface != faceDomains.end(); ++itface)
{
- int oldId = *itn;
- if (!nodeDomains.count(oldId))
- nodeDomains[oldId] = emptyMap; // create an empty entry for node
- std::map<int,int>::iterator itdom = domvol.begin();
- for(; itdom != domvol.end(); ++itdom)
+ std::map<int, int> domvol = itface->second;
+ if (!domvol.count(idomain))
+ continue;
+ DownIdType face = itface->first;
+ //MESSAGE(" --- face " << face.cellId);
+ std::set<int> oldNodes;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ std::set<int>::iterator itn = oldNodes.begin();
+ for (; itn != oldNodes.end(); ++itn)
{
- int idom = itdom->first;
- if ( nodeDomains[oldId].empty() )
- nodeDomains[oldId][idom] = oldId; // keep the old node in the first domain
- else
+ int oldId = *itn;
+ //MESSAGE("-+-+-a node " << oldId);
+ if (!nodeDomains.count(oldId))
+ nodeDomains[oldId] = emptyMap; // create an empty entry for node
+ if (nodeDomains[oldId].empty())
+ {
+ nodeDomains[oldId][idomain] = oldId; // keep the old node in the first domain
+ //MESSAGE("-+-+-b oldNode " << oldId << " domain " << idomain);
+ }
+ std::map<int, int>::iterator itdom = domvol.begin();
+ for (; itdom != domvol.end(); ++itdom)
{
- double *coords = grid->GetPoint(oldId);
- SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
- int newId = newNode->getVtkId();
- nodeDomains[oldId][idom] = newId; // cloned node for other domains
+ int idom = itdom->first;
+ //MESSAGE(" domain " << idom);
+ if (!nodeDomains[oldId].count(idom)) // --- node to clone
+ {
+ if (nodeDomains[oldId].size() >= 2) // a multiple node
+ {
+ vector<int> orderedDoms;
+ //MESSAGE("multiple node " << oldId);
+ if (mutipleNodes.count(oldId))
+ orderedDoms = mutipleNodes[oldId];
+ else
+ {
+ map<int,int>::iterator it = nodeDomains[oldId].begin();
+ for (; it != nodeDomains[oldId].end(); ++it)
+ orderedDoms.push_back(it->first);
+ }
+ orderedDoms.push_back(idom); // TODO order ==> push_front or back
+ //stringstream txt;
+ //for (int i=0; i<orderedDoms.size(); i++)
+ // txt << orderedDoms[i] << " ";
+ //MESSAGE("orderedDoms " << txt.str());
+ mutipleNodes[oldId] = orderedDoms;
+ }
+ double *coords = grid->GetPoint(oldId);
+ SMDS_MeshNode *newNode = meshDS->AddNode(coords[0], coords[1], coords[2]);
+ int newId = newNode->getVtkId();
+ nodeDomains[oldId][idom] = newId; // cloned node for other domains
+ //MESSAGE("-+-+-c oldNode " << oldId << " domain " << idomain << " newNode " << newId << " domain " << idom << " size=" <<nodeDomains[oldId].size());
+ }
+ }
+ }
+ }
+ }
+
+ for (int idomain = 0; idomain < theElems.size(); idomain++)
+ {
+ itface = faceDomains.begin();
+ for (; itface != faceDomains.end(); ++itface)
+ {
+ std::map<int, int> domvol = itface->second;
+ if (!domvol.count(idomain))
+ continue;
+ DownIdType face = itface->first;
+ //MESSAGE(" --- face " << face.cellId);
+ std::set<int> oldNodes;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ int nbMultipleNodes = 0;
+ std::set<int>::iterator itn = oldNodes.begin();
+ for (; itn != oldNodes.end(); ++itn)
+ {
+ int oldId = *itn;
+ if (mutipleNodes.count(oldId))
+ nbMultipleNodes++;
+ }
+ if (nbMultipleNodes > 1) // check if an edge of the face is shared between 3 or more domains
+ {
+ //MESSAGE("multiple Nodes detected on a shared face");
+ int downId = itface->first.cellId;
+ unsigned char cellType = itface->first.cellType;
+ // --- shared edge or shared face ?
+ if ((cellType == VTK_LINE) || (cellType == VTK_QUADRATIC_EDGE)) // shared edge (between two faces)
+ {
+ int nodes[3];
+ int nbNodes = grid->getDownArray(cellType)->getNodes(downId, nodes);
+ for (int i=0; i< nbNodes; i=i+nbNodes-1) // i=0 , i=nbNodes-1
+ if (mutipleNodes.count(nodes[i]))
+ if (!mutipleNodesToFace.count(nodes[i]))
+ mutipleNodesToFace[nodes[i]] = mutipleNodes[nodes[i]];
+ }
+ else // shared face (between two volumes)
+ {
+ int nbEdges = grid->getDownArray(cellType)->getNumberOfDownCells(downId);
+ const int* downEdgeIds = grid->getDownArray(cellType)->getDownCells(downId);
+ const unsigned char* edgeType = grid->getDownArray(cellType)->getDownTypes(downId);
+ for (int ie =0; ie < nbEdges; ie++)
+ {
+ int nodes[3];
+ int nbNodes = grid->getDownArray(edgeType[ie])->getNodes(downEdgeIds[ie], nodes);
+ if (mutipleNodes.count(nodes[0]) && mutipleNodes.count(nodes[nbNodes-1]))
+ {
+ vector<int> vn0 = mutipleNodes[nodes[0]];
+ vector<int> vn1 = mutipleNodes[nodes[nbNodes - 1]];
+ vector<int> doms;
+ for (int i0 = 0; i0 < vn0.size(); i0++)
+ for (int i1 = 0; i1 < vn1.size(); i1++)
+ if (vn0[i0] == vn1[i1])
+ doms.push_back(vn0[i0]);
+ if (doms.size() >2)
+ {
+ //MESSAGE(" detect edgesMultiDomains " << nodes[0] << " " << nodes[nbNodes - 1]);
+ double *coords = grid->GetPoint(nodes[0]);
+ gp_Pnt p0(coords[0], coords[1], coords[2]);
+ coords = grid->GetPoint(nodes[nbNodes - 1]);
+ gp_Pnt p1(coords[0], coords[1], coords[2]);
+ gp_Pnt gref;
+ int vtkVolIds[1000]; // an edge can belong to a lot of volumes
+ map<int, SMDS_VtkVolume*> domvol; // domain --> a volume with the edge
+ map<int, double> angleDom; // oriented angles between planes defined by edge and volume centers
+ int nbvol = grid->GetParentVolumes(vtkVolIds, downEdgeIds[ie], edgeType[ie]);
+ for (int id=0; id < doms.size(); id++)
+ {
+ int idom = doms[id];
+ for (int ivol=0; ivol<nbvol; ivol++)
+ {
+ int smdsId = meshDS->fromVtkToSmds(vtkVolIds[ivol]);
+ SMDS_MeshElement* elem = (SMDS_MeshElement*)meshDS->FindElement(smdsId);
+ if (theElems[idom].count(elem))
+ {
+ SMDS_VtkVolume* svol = dynamic_cast<SMDS_VtkVolume*>(elem);
+ domvol[idom] = svol;
+ //MESSAGE(" domain " << idom << " volume " << elem->GetID());
+ double values[3];
+ vtkIdType npts = 0;
+ vtkIdType* pts = 0;
+ grid->GetCellPoints(vtkVolIds[ivol], npts, pts);
+ SMDS_VtkVolume::gravityCenter(grid, pts, npts, values);
+ if (id ==0)
+ {
+ gref.SetXYZ(gp_XYZ(values[0], values[1], values[2]));
+ angleDom[idom] = 0;
+ }
+ else
+ {
+ gp_Pnt g(values[0], values[1], values[2]);
+ angleDom[idom] = OrientedAngle(p0, p1, gref, g); // -pi<angle<+pi
+ //MESSAGE(" angle=" << angleDom[idom]);
+ }
+ break;
+ }
+ }
+ }
+ map<double, int> sortedDom; // sort domains by angle
+ for (map<int, double>::iterator ia = angleDom.begin(); ia != angleDom.end(); ++ia)
+ sortedDom[ia->second] = ia->first;
+ vector<int> vnodes;
+ vector<int> vdom;
+ for (map<double, int>::iterator ib = sortedDom.begin(); ib != sortedDom.end(); ++ib)
+ {
+ vdom.push_back(ib->second);
+ //MESSAGE(" ordered domain " << ib->second << " angle " << ib->first);
+ }
+ for (int ino = 0; ino < nbNodes; ino++)
+ vnodes.push_back(nodes[ino]);
+ edgesMultiDomains[vnodes] = vdom; // nodes vector --> ordered domains
+ }
+ }
+ }
}
}
}
// get node id's of the face (id SMDS = id VTK)
// create flat element with old and new nodes if requested
+ // --- new quad nodes on flat quad elements: oldId --> ((domain1 X domain2) --> newId)
+ // (domain1 X domain2) = domain1 + MAXINT*domain2
+
+ std::map<int, std::map<long,int> > nodeQuadDomains;
+ std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
+
if (createJointElems)
{
+ int idg;
+ string joints2DName = "joints2D";
+ mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
+ SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
+ string joints3DName = "joints3D";
+ mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
+ SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
+
itface = faceDomains.begin();
- for( ; itface != faceDomains.end();++itface )
+ for (; itface != faceDomains.end(); ++itface)
{
DownIdType face = itface->first;
std::set<int> oldNodes;
std::set<int>::iterator itn;
oldNodes.clear();
grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
- std::map<int,int> localClonedNodeIds;
- std::map<int,int> domvol = itface->second;
- std::map<int,int>::iterator itdom = domvol.begin();
+ std::map<int, int> domvol = itface->second;
+ std::map<int, int>::iterator itdom = domvol.begin();
int dom1 = itdom->first;
int vtkVolId = itdom->second;
itdom++;
int dom2 = itdom->first;
+ SMDS_MeshCell *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
+ nodeQuadDomains);
+ stringstream grpname;
+ grpname << "j_";
+ if (dom1 < dom2)
+ grpname << dom1 << "_" << dom2;
+ else
+ grpname << dom2 << "_" << dom1;
+ string namegrp = grpname.str();
+ if (!mapOfJunctionGroups.count(namegrp))
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+ if (sgrp)
+ sgrp->Add(vol->GetID());
+ if (vol->GetType() == SMDSAbs_Volume)
+ joints3DGrp->Add(vol->GetID());
+ else if (vol->GetType() == SMDSAbs_Face)
+ joints2DGrp->Add(vol->GetID());
+ }
+ }
+
+ // --- create volumes on multiple domain intersection if requested
+ // iterate on mutipleNodesToFace
+ // iterate on edgesMultiDomains
+
+ if (createJointElems)
+ {
+ // --- iterate on mutipleNodesToFace
- localClonedNodeIds.clear();
- for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
+ std::map<int, std::vector<int> >::iterator itn = mutipleNodesToFace.begin();
+ for (; itn != mutipleNodesToFace.end(); ++itn)
+ {
+ int node = itn->first;
+ vector<int> orderDom = itn->second;
+ vector<vtkIdType> orderedNodes;
+ for (int idom = 0; idom <orderDom.size(); idom++)
+ orderedNodes.push_back( nodeDomains[node][orderDom[idom]] );
+ SMDS_MeshFace* face = this->GetMeshDS()->AddFaceFromVtkIds(orderedNodes);
+
+ stringstream grpname;
+ grpname << "m2j_";
+ grpname << 0 << "_" << 0;
+ int idg;
+ string namegrp = grpname.str();
+ if (!mapOfJunctionGroups.count(namegrp))
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+ if (sgrp)
+ sgrp->Add(face->GetID());
+ }
+
+ // --- iterate on edgesMultiDomains
+
+ std::map<std::vector<int>, std::vector<int> >::iterator ite = edgesMultiDomains.begin();
+ for (; ite != edgesMultiDomains.end(); ++ite)
+ {
+ vector<int> nodes = ite->first;
+ vector<int> orderDom = ite->second;
+ vector<vtkIdType> orderedNodes;
+ if (nodes.size() == 2)
{
- int oldId = *itn;
- int refid = oldId;
- if (nodeDomains[oldId].count(dom1))
- refid = nodeDomains[oldId][dom1];
- else
- MESSAGE("--- problem domain node " << dom1 << " " << oldId);
- int newid = oldId;
- if (nodeDomains[oldId].count(dom2))
- newid = nodeDomains[oldId][dom2];
- else
- MESSAGE("--- problem domain node " << dom2 << " " << oldId);
- localClonedNodeIds[oldId] = newid;
+ //MESSAGE(" use edgesMultiDomains " << nodes[0] << " " << nodes[1]);
+ for (int ino=0; ino < nodes.size(); ino++)
+ if (orderDom.size() == 3)
+ for (int idom = 0; idom <orderDom.size(); idom++)
+ orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
+ else
+ for (int idom = orderDom.size()-1; idom >=0; idom--)
+ orderedNodes.push_back( nodeDomains[nodes[ino]][orderDom[idom]] );
+ SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
+
+ int idg;
+ string namegrp = "jointsMultiples";
+ if (!mapOfJunctionGroups.count(namegrp))
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+ if (sgrp)
+ sgrp->Add(vol->GetID());
+ }
+ else
+ {
+ INFOS("Quadratic multiple joints not implemented");
+ // TODO quadratic nodes
+ }
+ }
+ }
+
+ // --- list the explicit faces and edges of the mesh that need to be modified,
+ // i.e. faces and edges built with one or more duplicated nodes.
+ // associate these faces or edges to their corresponding domain.
+ // only the first domain found is kept when a face or edge is shared
+
+ std::map<DownIdType, std::map<int,int>, DownIdCompare> faceOrEdgeDom; // cellToModify --> (id domain --> id cell)
+ std::map<int,int> feDom; // vtk id of cell to modify --> id domain
+ faceOrEdgeDom.clear();
+ feDom.clear();
+
+ for (int idomain = 0; idomain < theElems.size(); idomain++)
+ {
+ std::map<int, std::map<int, int> >::const_iterator itnod = nodeDomains.begin();
+ for (; itnod != nodeDomains.end(); ++itnod)
+ {
+ int oldId = itnod->first;
+ //MESSAGE(" node " << oldId);
+ vtkCellLinks::Link l = grid->GetCellLinks()->GetLink(oldId);
+ for (int i = 0; i < l.ncells; i++)
+ {
+ int vtkId = l.cells[i];
+ int vtkType = grid->GetCellType(vtkId);
+ int downId = grid->CellIdToDownId(vtkId);
+ if (downId < 0)
+ continue; // new cells: not to be modified
+ DownIdType aCell(downId, vtkType);
+ int volParents[1000];
+ int nbvol = grid->GetParentVolumes(volParents, vtkId);
+ for (int j = 0; j < nbvol; j++)
+ if (celldom.count(volParents[j]) && (celldom[volParents[j]] == idomain))
+ if (!feDom.count(vtkId))
+ {
+ feDom[vtkId] = idomain;
+ faceOrEdgeDom[aCell] = emptyMap;
+ faceOrEdgeDom[aCell][idomain] = vtkId; // affect face or edge to the first domain only
+ //MESSAGE("affect cell " << this->GetMeshDS()->fromVtkToSmds(vtkId) << " domain " << idomain
+ // << " type " << vtkType << " downId " << downId);
+ }
}
- meshDS->extrudeVolumeFromFace(vtkVolId, localClonedNodeIds);
}
}
// get node id's of the face
// replace old nodes by new nodes in volumes, and update inverse connectivity
- itface = faceDomains.begin();
- for( ; itface != faceDomains.end();++itface )
+ std::map<DownIdType, std::map<int,int>, DownIdCompare>* maps[3] = {&faceDomains, &cellDomains, &faceOrEdgeDom};
+ for (int m=0; m<3; m++)
{
- DownIdType face = itface->first;
- std::set<int> oldNodes;
- std::set<int>::iterator itn;
- oldNodes.clear();
- grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
- std::map<int,int> localClonedNodeIds;
-
- std::map<int,int> domvol = itface->second;
- std::map<int,int>::iterator itdom = domvol.begin();
- for(; itdom != domvol.end(); ++itdom)
+ std::map<DownIdType, std::map<int,int>, DownIdCompare>* amap = maps[m];
+ itface = (*amap).begin();
+ for (; itface != (*amap).end(); ++itface)
{
- int idom = itdom->first;
- int vtkVolId = itdom->second;
- localClonedNodeIds.clear();
- for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
+ DownIdType face = itface->first;
+ std::set<int> oldNodes;
+ std::set<int>::iterator itn;
+ oldNodes.clear();
+ grid->GetNodeIds(oldNodes, face.cellId, face.cellType);
+ //MESSAGE("examine cell, downId " << face.cellId << " type " << int(face.cellType));
+ std::map<int, int> localClonedNodeIds;
+
+ std::map<int, int> domvol = itface->second;
+ std::map<int, int>::iterator itdom = domvol.begin();
+ for (; itdom != domvol.end(); ++itdom)
{
- int oldId = *itn;
- if (nodeDomains[oldId].count(idom))
- localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
+ int idom = itdom->first;
+ int vtkVolId = itdom->second;
+ //MESSAGE("modify nodes of cell " << this->GetMeshDS()->fromVtkToSmds(vtkVolId) << " domain " << idom);
+ localClonedNodeIds.clear();
+ for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
+ {
+ int oldId = *itn;
+ if (nodeDomains[oldId].count(idom))
+ {
+ localClonedNodeIds[oldId] = nodeDomains[oldId][idom];
+ //MESSAGE(" node " << oldId << " --> " << localClonedNodeIds[oldId]);
+ }
+ }
+ meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
}
- meshDS->ModifyCellNodes(vtkVolId, localClonedNodeIds);
}
}
+
+ meshDS->CleanDownWardConnectivity(); // Mesh has been modified, downward connectivity is no more usable, free memory
grid->BuildLinks();
- // TODO replace also old nodes by new nodes in faces and edges
CHRONOSTOP(50);
counters::stats();
return true;
}
+/*!
+ * \brief Double nodes on some external faces and create flat elements.
+ * Flat elements are mainly used by some types of mechanic calculations.
+ *
+ * Each group of the list must be constituted of faces.
+ * Triangles are transformed in prisms, and quadrangles in hexahedrons.
+ * @param theElems - list of groups of faces, where a group of faces is a set of
+ * SMDS_MeshElements sorted by Id.
+ * @return TRUE if operation has been completed successfully, FALSE otherwise
+ */
+bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSortedElemSet>& theElems)
+{
+ MESSAGE("-------------------------------------------------");
+ MESSAGE("SMESH_MeshEditor::CreateFlatElementsOnFacesGroups");
+ MESSAGE("-------------------------------------------------");
+
+ SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
+
+ // --- For each group of faces
+ // duplicate the nodes, create a flat element based on the face
+ // replace the nodes of the faces by their clones
+
+ std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> clonedNodes;
+ std::map<const SMDS_MeshNode*, const SMDS_MeshNode*> intermediateNodes;
+ clonedNodes.clear();
+ intermediateNodes.clear();
+ std::map<std::string, SMESH_Group*> mapOfJunctionGroups;
+ mapOfJunctionGroups.clear();
+
+ for (int idom = 0; idom < theElems.size(); idom++)
+ {
+ const TIDSortedElemSet& domain = theElems[idom];
+ TIDSortedElemSet::const_iterator elemItr = domain.begin();
+ for (; elemItr != domain.end(); ++elemItr)
+ {
+ SMDS_MeshElement* anElem = (SMDS_MeshElement*) *elemItr;
+ SMDS_MeshFace* aFace = dynamic_cast<SMDS_MeshFace*> (anElem);
+ if (!aFace)
+ continue;
+ // MESSAGE("aFace=" << aFace->GetID());
+ bool isQuad = aFace->IsQuadratic();
+ vector<const SMDS_MeshNode*> ln0, ln1, ln2, ln3, ln4;
+
+ // --- clone the nodes, create intermediate nodes for non medium nodes of a quad face
+
+ SMDS_ElemIteratorPtr nodeIt = aFace->nodesIterator();
+ while (nodeIt->more())
+ {
+ const SMDS_MeshNode* node = static_cast<const SMDS_MeshNode*> (nodeIt->next());
+ bool isMedium = isQuad && (aFace->IsMediumNode(node));
+ if (isMedium)
+ ln2.push_back(node);
+ else
+ ln0.push_back(node);
+
+ const SMDS_MeshNode* clone = 0;
+ if (!clonedNodes.count(node))
+ {
+ clone = meshDS->AddNode(node->X(), node->Y(), node->Z());
+ clonedNodes[node] = clone;
+ }
+ else
+ clone = clonedNodes[node];
+
+ if (isMedium)
+ ln3.push_back(clone);
+ else
+ ln1.push_back(clone);
+
+ const SMDS_MeshNode* inter = 0;
+ if (isQuad && (!isMedium))
+ {
+ if (!intermediateNodes.count(node))
+ {
+ inter = meshDS->AddNode(node->X(), node->Y(), node->Z());
+ intermediateNodes[node] = inter;
+ }
+ else
+ inter = intermediateNodes[node];
+ ln4.push_back(inter);
+ }
+ }
+
+ // --- extrude the face
+
+ vector<const SMDS_MeshNode*> ln;
+ SMDS_MeshVolume* vol = 0;
+ vtkIdType aType = aFace->GetVtkType();
+ switch (aType)
+ {
+ case VTK_TRIANGLE:
+ vol = meshDS->AddVolume(ln0[2], ln0[1], ln0[0], ln1[2], ln1[1], ln1[0]);
+ // MESSAGE("vol prism " << vol->GetID());
+ ln.push_back(ln1[0]);
+ ln.push_back(ln1[1]);
+ ln.push_back(ln1[2]);
+ break;
+ case VTK_QUAD:
+ vol = meshDS->AddVolume(ln0[3], ln0[2], ln0[1], ln0[0], ln1[3], ln1[2], ln1[1], ln1[0]);
+ // MESSAGE("vol hexa " << vol->GetID());
+ ln.push_back(ln1[0]);
+ ln.push_back(ln1[1]);
+ ln.push_back(ln1[2]);
+ ln.push_back(ln1[3]);
+ break;
+ case VTK_QUADRATIC_TRIANGLE:
+ vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln0[0], ln0[1], ln0[2], ln3[0], ln3[1], ln3[2],
+ ln2[0], ln2[1], ln2[2], ln4[0], ln4[1], ln4[2]);
+ // MESSAGE("vol quad prism " << vol->GetID());
+ ln.push_back(ln1[0]);
+ ln.push_back(ln1[1]);
+ ln.push_back(ln1[2]);
+ ln.push_back(ln3[0]);
+ ln.push_back(ln3[1]);
+ ln.push_back(ln3[2]);
+ break;
+ case VTK_QUADRATIC_QUAD:
+// vol = meshDS->AddVolume(ln0[0], ln0[1], ln0[2], ln0[3], ln1[0], ln1[1], ln1[2], ln1[3],
+// ln2[0], ln2[1], ln2[2], ln2[3], ln3[0], ln3[1], ln3[2], ln3[3],
+// ln4[0], ln4[1], ln4[2], ln4[3]);
+ vol = meshDS->AddVolume(ln1[0], ln1[1], ln1[2], ln1[3], ln0[0], ln0[1], ln0[2], ln0[3],
+ ln3[0], ln3[1], ln3[2], ln3[3], ln2[0], ln2[1], ln2[2], ln2[3],
+ ln4[0], ln4[1], ln4[2], ln4[3]);
+ // MESSAGE("vol quad hexa " << vol->GetID());
+ ln.push_back(ln1[0]);
+ ln.push_back(ln1[1]);
+ ln.push_back(ln1[2]);
+ ln.push_back(ln1[3]);
+ ln.push_back(ln3[0]);
+ ln.push_back(ln3[1]);
+ ln.push_back(ln3[2]);
+ ln.push_back(ln3[3]);
+ break;
+ case VTK_POLYGON:
+ break;
+ default:
+ break;
+ }
+
+ if (vol)
+ {
+ stringstream grpname;
+ grpname << "jf_";
+ grpname << idom;
+ int idg;
+ string namegrp = grpname.str();
+ if (!mapOfJunctionGroups.count(namegrp))
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
+ if (sgrp)
+ sgrp->Add(vol->GetID());
+ }
+
+ // --- modify the face
+
+ aFace->ChangeNodes(&ln[0], ln.size());
+ }
+ }
+ return true;
+}
+
+/*!
+ * \brief identify all the elements around a geom shape, get the faces delimiting the hole
+ * Build groups of volume to remove, groups of faces to replace on the skin of the object,
+ * groups of faces to remove inside the object, (idem edges).
+ * Build ordered list of nodes at the border of each group of faces to replace (to be used to build a geom subshape)
+ */
+void SMESH_MeshEditor::CreateHoleSkin(double radius,
+ const TopoDS_Shape& theShape,
+ SMESH_NodeSearcher* theNodeSearcher,
+ const char* groupName,
+ std::vector<double>& nodesCoords,
+ std::vector<std::vector<int> >& listOfListOfNodes)
+{
+ MESSAGE("--------------------------------");
+ MESSAGE("SMESH_MeshEditor::CreateHoleSkin");
+ MESSAGE("--------------------------------");
+
+ // --- zone of volumes to remove is given :
+ // 1 either by a geom shape (one or more vertices) and a radius,
+ // 2 either by a group of nodes (representative of the shape)to use with the radius,
+ // 3 either by a group of nodes where all the elements build on one of this nodes are to remove,
+ // In the case 2, the group of nodes is an external group of nodes from another mesh,
+ // In the case 3, the group of nodes is an internal group of the mesh (obtained for instance by a filter),
+ // defined by it's name.
+
+ SMESHDS_GroupBase* groupDS = 0;
+ SMESH_Mesh::GroupIteratorPtr groupIt = this->myMesh->GetGroups();
+ while ( groupIt->more() )
+ {
+ groupDS = 0;
+ SMESH_Group * group = groupIt->next();
+ if ( !group ) continue;
+ groupDS = group->GetGroupDS();
+ if ( !groupDS || groupDS->IsEmpty() ) continue;
+ std::string grpName = group->GetName();
+ //MESSAGE("grpName=" << grpName);
+ if (grpName == groupName)
+ break;
+ else
+ groupDS = 0;
+ }
+
+ bool isNodeGroup = false;
+ bool isNodeCoords = false;
+ if (groupDS)
+ {
+ if (groupDS->GetType() != SMDSAbs_Node)
+ return;
+ isNodeGroup = true; // a group of nodes exists and it is in this mesh
+ }
+
+ if (nodesCoords.size() > 0)
+ isNodeCoords = true; // a list o nodes given by their coordinates
+ //MESSAGE("---" << isNodeGroup << " " << isNodeCoords);
+
+ // --- define groups to build
+
+ int idg; // --- group of SMDS volumes
+ string grpvName = groupName;
+ grpvName += "_vol";
+ SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
+ if (!grp)
+ {
+ MESSAGE("group not created " << grpvName);
+ return;
+ }
+ SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
+
+ int idgs; // --- group of SMDS faces on the skin
+ string grpsName = groupName;
+ grpsName += "_skin";
+ SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
+ if (!grps)
+ {
+ MESSAGE("group not created " << grpsName);
+ return;
+ }
+ SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
+
+ int idgi; // --- group of SMDS faces internal (several shapes)
+ string grpiName = groupName;
+ grpiName += "_internalFaces";
+ SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
+ if (!grpi)
+ {
+ MESSAGE("group not created " << grpiName);
+ return;
+ }
+ SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
+
+ int idgei; // --- group of SMDS faces internal (several shapes)
+ string grpeiName = groupName;
+ grpeiName += "_internalEdges";
+ SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
+ if (!grpei)
+ {
+ MESSAGE("group not created " << grpeiName);
+ return;
+ }
+ SMESHDS_Group *sgrpei = dynamic_cast<SMESHDS_Group*>(grpei->GetGroupDS());
+
+ // --- build downward connectivity
+
+ SMESHDS_Mesh *meshDS = this->myMesh->GetMeshDS();
+ meshDS->BuildDownWardConnectivity(true);
+ SMDS_UnstructuredGrid* grid = meshDS->getGrid();
+
+ // --- set of volumes detected inside
+
+ std::set<int> setOfInsideVol;
+ std::set<int> setOfVolToCheck;
+
+ std::vector<gp_Pnt> gpnts;
+ gpnts.clear();
+
+ if (isNodeGroup) // --- a group of nodes is provided : find all the volumes using one or more of this nodes
+ {
+ MESSAGE("group of nodes provided");
+ SMDS_ElemIteratorPtr elemIt = groupDS->GetElements();
+ while ( elemIt->more() )
+ {
+ const SMDS_MeshElement* elem = elemIt->next();
+ if (!elem)
+ continue;
+ const SMDS_MeshNode* node = dynamic_cast<const SMDS_MeshNode*>(elem);
+ if (!node)
+ continue;
+ SMDS_MeshElement* vol = 0;
+ SMDS_ElemIteratorPtr volItr = node->GetInverseElementIterator(SMDSAbs_Volume);
+ while (volItr->more())
+ {
+ vol = (SMDS_MeshElement*)volItr->next();
+ setOfInsideVol.insert(vol->getVtkId());
+ sgrp->Add(vol->GetID());
+ }
+ }
+ }
+ else if (isNodeCoords)
+ {
+ MESSAGE("list of nodes coordinates provided");
+ int i = 0;
+ int k = 0;
+ while (i < nodesCoords.size()-2)
+ {
+ double x = nodesCoords[i++];
+ double y = nodesCoords[i++];
+ double z = nodesCoords[i++];
+ gp_Pnt p = gp_Pnt(x, y ,z);
+ gpnts.push_back(p);
+ MESSAGE("TopoDS_Vertex " << k++ << " " << p.X() << " " << p.Y() << " " << p.Z());
+ }
+ }
+ else // --- no group, no coordinates : use the vertices of the geom shape provided, and radius
+ {
+ MESSAGE("no group of nodes provided, using vertices from geom shape, and radius");
+ TopTools_IndexedMapOfShape vertexMap;
+ TopExp::MapShapes( theShape, TopAbs_VERTEX, vertexMap );
+ gp_Pnt p = gp_Pnt(0,0,0);
+ if (vertexMap.Extent() < 1)
+ return;
+
+ for ( int i = 1; i <= vertexMap.Extent(); ++i )
+ {
+ const TopoDS_Vertex& vertex = TopoDS::Vertex( vertexMap( i ));
+ p = BRep_Tool::Pnt(vertex);
+ gpnts.push_back(p);
+ MESSAGE("TopoDS_Vertex " << i << " " << p.X() << " " << p.Y() << " " << p.Z());
+ }
+ }
+
+ if (gpnts.size() > 0)
+ {
+ int nodeId = 0;
+ const SMDS_MeshNode* startNode = theNodeSearcher->FindClosestTo(gpnts[0]);
+ if (startNode)
+ nodeId = startNode->GetID();
+ MESSAGE("nodeId " << nodeId);
+
+ double radius2 = radius*radius;
+ MESSAGE("radius2 " << radius2);
+
+ // --- volumes on start node
+
+ setOfVolToCheck.clear();
+ SMDS_MeshElement* startVol = 0;
+ SMDS_ElemIteratorPtr volItr = startNode->GetInverseElementIterator(SMDSAbs_Volume);
+ while (volItr->more())
+ {
+ startVol = (SMDS_MeshElement*)volItr->next();
+ setOfVolToCheck.insert(startVol->getVtkId());
+ }
+ if (setOfVolToCheck.empty())
+ {
+ MESSAGE("No volumes found");
+ return;
+ }
+
+ // --- starting with central volumes then their neighbors, check if they are inside
+ // or outside the domain, until no more new neighbor volume is inside.
+ // Fill the group of inside volumes
+
+ std::map<int, double> mapOfNodeDistance2;
+ mapOfNodeDistance2.clear();
+ std::set<int> setOfOutsideVol;
+ while (!setOfVolToCheck.empty())
+ {
+ std::set<int>::iterator it = setOfVolToCheck.begin();
+ int vtkId = *it;
+ MESSAGE("volume to check, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+ bool volInside = false;
+ vtkIdType npts = 0;
+ vtkIdType* pts = 0;
+ grid->GetCellPoints(vtkId, npts, pts);
+ for (int i=0; i<npts; i++)
+ {
+ double distance2 = 0;
+ if (mapOfNodeDistance2.count(pts[i]))
+ {
+ distance2 = mapOfNodeDistance2[pts[i]];
+ MESSAGE("point " << pts[i] << " distance2 " << distance2);
+ }
+ else
+ {
+ double *coords = grid->GetPoint(pts[i]);
+ gp_Pnt aPoint = gp_Pnt(coords[0], coords[1], coords[2]);
+ distance2 = 1.E40;
+ for (int j=0; j<gpnts.size(); j++)
+ {
+ double d2 = aPoint.SquareDistance(gpnts[j]);
+ if (d2 < distance2)
+ {
+ distance2 = d2;
+ if (distance2 < radius2)
+ break;
+ }
+ }
+ mapOfNodeDistance2[pts[i]] = distance2;
+ MESSAGE(" point " << pts[i] << " distance2 " << distance2 << " coords " << coords[0] << " " << coords[1] << " " << coords[2]);
+ }
+ if (distance2 < radius2)
+ {
+ volInside = true; // one or more nodes inside the domain
+ sgrp->Add(meshDS->fromVtkToSmds(vtkId));
+ break;
+ }
+ }
+ if (volInside)
+ {
+ setOfInsideVol.insert(vtkId);
+ MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+ int neighborsVtkIds[NBMAXNEIGHBORS];
+ int downIds[NBMAXNEIGHBORS];
+ unsigned char downTypes[NBMAXNEIGHBORS];
+ int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+ for (int n = 0; n < nbNeighbors; n++)
+ if (!setOfInsideVol.count(neighborsVtkIds[n]) ||setOfOutsideVol.count(neighborsVtkIds[n]))
+ setOfVolToCheck.insert(neighborsVtkIds[n]);
+ }
+ else
+ {
+ setOfOutsideVol.insert(vtkId);
+ MESSAGE(" volume outside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+ }
+ setOfVolToCheck.erase(vtkId);
+ }
+ }
+
+ // --- for outside hexahedrons, check if they have more than one neighbor volume inside
+ // If yes, add the volume to the inside set
+
+ bool addedInside = true;
+ std::set<int> setOfVolToReCheck;
+ while (addedInside)
+ {
+ MESSAGE(" --------------------------- re check");
+ addedInside = false;
+ std::set<int>::iterator itv = setOfInsideVol.begin();
+ for (; itv != setOfInsideVol.end(); ++itv)
+ {
+ int vtkId = *itv;
+ int neighborsVtkIds[NBMAXNEIGHBORS];
+ int downIds[NBMAXNEIGHBORS];
+ unsigned char downTypes[NBMAXNEIGHBORS];
+ int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+ for (int n = 0; n < nbNeighbors; n++)
+ if (!setOfInsideVol.count(neighborsVtkIds[n]))
+ setOfVolToReCheck.insert(neighborsVtkIds[n]);
+ }
+ setOfVolToCheck = setOfVolToReCheck;
+ setOfVolToReCheck.clear();
+ while (!setOfVolToCheck.empty())
+ {
+ std::set<int>::iterator it = setOfVolToCheck.begin();
+ int vtkId = *it;
+ if (grid->GetCellType(vtkId) == VTK_HEXAHEDRON)
+ {
+ MESSAGE("volume to recheck, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+ int countInside = 0;
+ int neighborsVtkIds[NBMAXNEIGHBORS];
+ int downIds[NBMAXNEIGHBORS];
+ unsigned char downTypes[NBMAXNEIGHBORS];
+ int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+ for (int n = 0; n < nbNeighbors; n++)
+ if (setOfInsideVol.count(neighborsVtkIds[n]))
+ countInside++;
+ MESSAGE("countInside " << countInside);
+ if (countInside > 1)
+ {
+ MESSAGE(" volume inside, vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+ setOfInsideVol.insert(vtkId);
+ sgrp->Add(meshDS->fromVtkToSmds(vtkId));
+ addedInside = true;
+ }
+ else
+ setOfVolToReCheck.insert(vtkId);
+ }
+ setOfVolToCheck.erase(vtkId);
+ }
+ }
+
+ // --- map of Downward faces at the boundary, inside the global volume
+ // map of Downward faces on the skin of the global volume (equivalent to SMDS faces on the skin)
+ // fill group of SMDS faces inside the volume (when several volume shapes)
+ // fill group of SMDS faces on the skin of the global volume (if skin)
+
+ std::map<DownIdType, int, DownIdCompare> boundaryFaces; // boundary faces inside the volume --> corresponding cell
+ std::map<DownIdType, int, DownIdCompare> skinFaces; // faces on the skin of the global volume --> corresponding cell
+ std::set<int>::iterator it = setOfInsideVol.begin();
+ for (; it != setOfInsideVol.end(); ++it)
+ {
+ int vtkId = *it;
+ //MESSAGE(" vtkId " << vtkId << " smdsId " << meshDS->fromVtkToSmds(vtkId));
+ int neighborsVtkIds[NBMAXNEIGHBORS];
+ int downIds[NBMAXNEIGHBORS];
+ unsigned char downTypes[NBMAXNEIGHBORS];
+ int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId, true);
+ for (int n = 0; n < nbNeighbors; n++)
+ {
+ int neighborDim = SMDS_Downward::getCellDimension(grid->GetCellType(neighborsVtkIds[n]));
+ if (neighborDim == 3)
+ {
+ if (! setOfInsideVol.count(neighborsVtkIds[n])) // neighbor volume is not inside : face is boundary
+ {
+ DownIdType face(downIds[n], downTypes[n]);
+ boundaryFaces[face] = vtkId;
+ }
+ // if the face between to volumes is in the mesh, get it (internal face between shapes)
+ int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
+ if (vtkFaceId >= 0)
+ {
+ sgrpi->Add(meshDS->fromVtkToSmds(vtkFaceId));
+ // find also the smds edges on this face
+ int nbEdges = grid->getDownArray(downTypes[n])->getNumberOfDownCells(downIds[n]);
+ const int* dEdges = grid->getDownArray(downTypes[n])->getDownCells(downIds[n]);
+ const unsigned char* dTypes = grid->getDownArray(downTypes[n])->getDownTypes(downIds[n]);
+ for (int i = 0; i < nbEdges; i++)
+ {
+ int vtkEdgeId = grid->getDownArray(dTypes[i])->getVtkCellId(dEdges[i]);
+ if (vtkEdgeId >= 0)
+ sgrpei->Add(meshDS->fromVtkToSmds(vtkEdgeId));
+ }
+ }
+ }
+ else if (neighborDim == 2) // skin of the volume
+ {
+ DownIdType face(downIds[n], downTypes[n]);
+ skinFaces[face] = vtkId;
+ int vtkFaceId = grid->getDownArray(downTypes[n])->getVtkCellId(downIds[n]);
+ if (vtkFaceId >= 0)
+ sgrps->Add(meshDS->fromVtkToSmds(vtkFaceId));
+ }
+ }
+ }
+
+ // --- identify the edges constituting the wire of each subshape on the skin
+ // define polylines with the nodes of edges, equivalent to wires
+ // project polylines on subshapes, and partition, to get geom faces
+
+ std::map<int, std::set<int> > shapeIdToVtkIdSet; // shapeId --> set of vtkId on skin
+ std::set<int> emptySet;
+ emptySet.clear();
+ std::set<int> shapeIds;
+
+ SMDS_ElemIteratorPtr itelem = sgrps->GetElements();
+ while (itelem->more())
+ {
+ const SMDS_MeshElement *elem = itelem->next();
+ int shapeId = elem->getshapeId();
+ int vtkId = elem->getVtkId();
+ if (!shapeIdToVtkIdSet.count(shapeId))
+ {
+ shapeIdToVtkIdSet[shapeId] = emptySet;
+ shapeIds.insert(shapeId);
+ }
+ shapeIdToVtkIdSet[shapeId].insert(vtkId);
+ }
+
+ std::map<int, std::set<DownIdType, DownIdCompare> > shapeIdToEdges; // shapeId --> set of downward edges
+ std::set<DownIdType, DownIdCompare> emptyEdges;
+ emptyEdges.clear();
+
+ std::map<int, std::set<int> >::iterator itShape = shapeIdToVtkIdSet.begin();
+ for (; itShape != shapeIdToVtkIdSet.end(); ++itShape)
+ {
+ int shapeId = itShape->first;
+ MESSAGE(" --- Shape ID --- "<< shapeId);
+ shapeIdToEdges[shapeId] = emptyEdges;
+
+ std::vector<int> nodesEdges;
+
+ std::set<int>::iterator its = itShape->second.begin();
+ for (; its != itShape->second.end(); ++its)
+ {
+ int vtkId = *its;
+ MESSAGE(" " << vtkId);
+ int neighborsVtkIds[NBMAXNEIGHBORS];
+ int downIds[NBMAXNEIGHBORS];
+ unsigned char downTypes[NBMAXNEIGHBORS];
+ int nbNeighbors = grid->GetNeighbors(neighborsVtkIds, downIds, downTypes, vtkId);
+ for (int n = 0; n < nbNeighbors; n++)
+ {
+ if (neighborsVtkIds[n]<0) // only smds faces are considered as neighbors here
+ continue;
+ int smdsId = meshDS->fromVtkToSmds(neighborsVtkIds[n]);
+ const SMDS_MeshElement* elem = meshDS->FindElement(smdsId);
+ if ( shapeIds.count(elem->getshapeId()) && !sgrps->Contains(elem)) // edge : neighbor in the set of shape, not in the group
+ {
+ DownIdType edge(downIds[n], downTypes[n]);
+ if (!shapeIdToEdges[shapeId].count(edge))
+ {
+ shapeIdToEdges[shapeId].insert(edge);
+ int vtkNodeId[3];
+ int nbNodes = grid->getDownArray(downTypes[n])->getNodes(downIds[n],vtkNodeId);
+ nodesEdges.push_back(vtkNodeId[0]);
+ nodesEdges.push_back(vtkNodeId[nbNodes-1]);
+ MESSAGE(" --- nodes " << vtkNodeId[0]+1 << " " << vtkNodeId[nbNodes-1]+1);
+ }
+ }
+ }
+ }
+
+ std::list<int> order;
+ order.clear();
+ if (nodesEdges.size() > 0)
+ {
+ order.push_back(nodesEdges[0]); MESSAGE(" --- back " << order.back()+1); // SMDS id = VTK id + 1;
+ nodesEdges[0] = -1;
+ order.push_back(nodesEdges[1]); MESSAGE(" --- back " << order.back()+1);
+ nodesEdges[1] = -1; // do not reuse this edge
+ bool found = true;
+ while (found)
+ {
+ int nodeTofind = order.back(); // try first to push back
+ int i = 0;
+ for (i = 0; i<nodesEdges.size(); i++)
+ if (nodesEdges[i] == nodeTofind)
+ break;
+ if (i == nodesEdges.size())
+ found = false; // no follower found on back
+ else
+ {
+ if (i%2) // odd ==> use the previous one
+ if (nodesEdges[i-1] < 0)
+ found = false;
+ else
+ {
+ order.push_back(nodesEdges[i-1]); MESSAGE(" --- back " << order.back()+1);
+ nodesEdges[i-1] = -1;
+ }
+ else // even ==> use the next one
+ if (nodesEdges[i+1] < 0)
+ found = false;
+ else
+ {
+ order.push_back(nodesEdges[i+1]); MESSAGE(" --- back " << order.back()+1);
+ nodesEdges[i+1] = -1;
+ }
+ }
+ if (found)
+ continue;
+ // try to push front
+ found = true;
+ nodeTofind = order.front(); // try to push front
+ for (i = 0; i<nodesEdges.size(); i++)
+ if (nodesEdges[i] == nodeTofind)
+ break;
+ if (i == nodesEdges.size())
+ {
+ found = false; // no predecessor found on front
+ continue;
+ }
+ if (i%2) // odd ==> use the previous one
+ if (nodesEdges[i-1] < 0)
+ found = false;
+ else
+ {
+ order.push_front(nodesEdges[i-1]); MESSAGE(" --- front " << order.front()+1);
+ nodesEdges[i-1] = -1;
+ }
+ else // even ==> use the next one
+ if (nodesEdges[i+1] < 0)
+ found = false;
+ else
+ {
+ order.push_front(nodesEdges[i+1]); MESSAGE(" --- front " << order.front()+1);
+ nodesEdges[i+1] = -1;
+ }
+ }
+ }
+
+
+ std::vector<int> nodes;
+ nodes.push_back(shapeId);
+ std::list<int>::iterator itl = order.begin();
+ for (; itl != order.end(); itl++)
+ {
+ nodes.push_back((*itl) + 1); // SMDS id = VTK id + 1;
+ MESSAGE(" ordered node " << nodes[nodes.size()-1]);
+ }
+ listOfListOfNodes.push_back(nodes);
+ }
+
+ // partition geom faces with blocFissure
+ // mesh blocFissure and geom faces of the skin (external wires given, triangle algo to choose)
+ // mesh volume around blocFissure (skin triangles and quadrangle given, tetra algo to choose)
+
+ return;
+}
+
+
//================================================================================
/*!
* \brief Generates skin mesh (containing 2D cells) from 3D mesh
while(vIt->more())
{
const SMDS_MeshVolume* volume = vIt->next();
- SMDS_VolumeTool vTool( volume );
+ SMDS_VolumeTool vTool( volume, /*ignoreCentralNodes=*/false );
vTool.SetExternalNormal();
- const bool isPoly = volume->IsPoly();
- const bool isQuad = volume->IsQuadratic();
+ //const bool isPoly = volume->IsPoly();
+ const int iQuad = volume->IsQuadratic();
for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
{
if (!vTool.IsFreeFace(iface))
int nbFaceNodes = vTool.NbFaceNodes(iface);
const SMDS_MeshNode** faceNodes = vTool.GetFaceNodes(iface);
int inode = 0;
- for ( ; inode < nbFaceNodes; inode += isQuad ? 2 : 1)
+ for ( ; inode < nbFaceNodes; inode += iQuad+1)
nodes.push_back(faceNodes[inode]);
- if (isQuad)
+ if (iQuad) { // add medium nodes
for ( inode = 1; inode < nbFaceNodes; inode += 2)
nodes.push_back(faceNodes[inode]);
-
+ if ( nbFaceNodes == 9 ) // bi-quadratic quad
+ nodes.push_back(faceNodes[8]);
+ }
// add new face based on volume nodes
- if (aMesh->FindFace( nodes ) ) {
+ if (aMesh->FindElement( nodes, SMDSAbs_Face, /*noMedium=*/false) ) {
nbExisted++;
continue; // face already exsist
}
- AddElement(nodes, SMDSAbs_Face, isPoly && iface == 1);
+ AddElement(nodes, SMDSAbs_Face, ( !iQuad && nbFaceNodes/(iQuad+1) > 4 ));
nbCreated++;
}
}
* \param group - a group to store created boundary elements in
* \param targetMesh - a mesh to store created boundary elements in
* \param toCopyElements - if true, the checked elements will be copied into the targetMesh
- * \param toCopyExistingBondary - if true, not only new but also pre-existing
+ * \param toCopyExistingBoundary - if true, not only new but also pre-existing
* boundary elements will be copied into the targetMesh
+ * \param toAddExistingBondary - if true, not only new but also pre-existing
+ * boundary elements will be added into the new group
+ * \param aroundElements - if true, elements will be created on boundary of given
+ * elements else, on boundary of the whole mesh.
+ * \return nb of added boundary elements
*/
//================================================================================
-void SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
- Bnd_Dimension dimension,
- SMESH_Group* group/*=0*/,
- SMESH_Mesh* targetMesh/*=0*/,
- bool toCopyElements/*=false*/,
- bool toCopyExistingBondary/*=false*/)
+int SMESH_MeshEditor::MakeBoundaryMesh(const TIDSortedElemSet& elements,
+ Bnd_Dimension dimension,
+ SMESH_Group* group/*=0*/,
+ SMESH_Mesh* targetMesh/*=0*/,
+ bool toCopyElements/*=false*/,
+ bool toCopyExistingBoundary/*=false*/,
+ bool toAddExistingBondary/*= false*/,
+ bool aroundElements/*= false*/)
{
SMDSAbs_ElementType missType = (dimension == BND_2DFROM3D) ? SMDSAbs_Face : SMDSAbs_Edge;
SMDSAbs_ElementType elemType = (dimension == BND_1DFROM2D) ? SMDSAbs_Face : SMDSAbs_Volume;
throw SALOME_Exception(LOCALIZED("wrong element type"));
if ( !targetMesh )
- toCopyElements = toCopyExistingBondary = false;
+ toCopyElements = toCopyExistingBoundary = false;
SMESH_MeshEditor tgtEditor( targetMesh ? targetMesh : myMesh );
SMESHDS_Mesh* aMesh = GetMeshDS(), *tgtMeshDS = tgtEditor.GetMeshDS();
+ int nbAddedBnd = 0;
+
+ // editor adding present bnd elements and optionally holding elements to add to the group
+ SMESH_MeshEditor* presentEditor;
+ SMESH_MeshEditor tgtEditor2( tgtEditor.GetMesh() );
+ presentEditor = toAddExistingBondary ? &tgtEditor : &tgtEditor2;
+ SMESH_MesherHelper helper( *myMesh );
+ const TopAbs_ShapeEnum missShapeType = ( missType==SMDSAbs_Face ? TopAbs_FACE : TopAbs_EDGE );
SMDS_VolumeTool vTool;
- TIDSortedElemSet emptySet, avoidSet;
+ TIDSortedElemSet avoidSet;
+ const TIDSortedElemSet emptySet, *elemSet = aroundElements ? &elements : &emptySet;
int inode;
typedef vector<const SMDS_MeshNode*> TConnectivity;
const SMDS_MeshElement* elem = eIt->next();
const int iQuad = elem->IsQuadratic();
+ // ------------------------------------------------------------------------------------
// 1. For an elem, get present bnd elements and connectivities of missing bnd elements
+ // ------------------------------------------------------------------------------------
vector<const SMDS_MeshElement*> presentBndElems;
vector<TConnectivity> missingBndElems;
TConnectivity nodes;
- if ( vTool.Set(elem) ) // elem is a volume ------------------------------------------
+ if ( vTool.Set(elem, /*ignoreCentralNodes=*/true) ) // elem is a volume --------------
{
vTool.SetExternalNormal();
+ const SMDS_MeshElement* otherVol = 0;
for ( int iface = 0, n = vTool.NbFaces(); iface < n; iface++ )
{
- if (!vTool.IsFreeFace(iface))
+ if ( !vTool.IsFreeFace(iface, &otherVol) &&
+ ( !aroundElements || elements.count( otherVol )))
continue;
- int nbFaceNodes = vTool.NbFaceNodes(iface);
+ const int nbFaceNodes = vTool.NbFaceNodes(iface);
const SMDS_MeshNode** nn = vTool.GetFaceNodes(iface);
if ( missType == SMDSAbs_Edge ) // boundary edges
{
for ( int j = 0; j < nodes.size(); ++j )
nodes[j] =nn[i+j];
if ( const SMDS_MeshElement* edge =
- aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/0))
+ aMesh->FindElement(nodes,SMDSAbs_Edge,/*noMedium=*/false))
presentBndElems.push_back( edge );
else
missingBndElems.push_back( nodes );
nodes.clear();
for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
nodes.push_back( nn[inode] );
- if (iQuad)
+ if (iQuad) // add medium nodes
for ( inode = 1; inode < nbFaceNodes; inode += 2)
nodes.push_back( nn[inode] );
+ int iCenter = vTool.GetCenterNodeIndex(iface); // for HEX27
+ if ( iCenter > 0 )
+ nodes.push_back( vTool.GetNodes()[ iCenter ] );
- if (const SMDS_MeshFace * f = aMesh->FindFace( nodes ) )
+ if (const SMDS_MeshElement * f = aMesh->FindElement( nodes,
+ SMDSAbs_Face, /*noMedium=*/false ))
presentBndElems.push_back( f );
else
missingBndElems.push_back( nodes );
+
+ if ( targetMesh != myMesh )
+ {
+ // add 1D elements on face boundary to be added to a new mesh
+ const SMDS_MeshElement* edge;
+ for ( inode = 0; inode < nbFaceNodes; inode += 1+iQuad)
+ {
+ if ( iQuad )
+ edge = aMesh->FindEdge( nn[inode], nn[inode+1], nn[inode+2]);
+ else
+ edge = aMesh->FindEdge( nn[inode], nn[inode+1]);
+ if ( edge && avoidSet.insert( edge ).second )
+ presentBndElems.push_back( edge );
+ }
+ }
}
}
}
{
nodes[0] = elem->GetNode(i);
nodes[1] = elem->GetNode((i+1)%nbNodes);
- if ( FindFaceInSet( nodes[0], nodes[1], emptySet, avoidSet))
+ if ( FindFaceInSet( nodes[0], nodes[1], *elemSet, avoidSet))
continue; // not free link
//if ( iQuad )
}
}
+ // ---------------------------------
// 2. Add missing boundary elements
+ // ---------------------------------
if ( targetMesh != myMesh )
// instead of making a map of nodes in this mesh and targetMesh,
- // we create nodes with same IDs. We can renumber them later, if needed
+ // we create nodes with same IDs.
for ( int i = 0; i < missingBndElems.size(); ++i )
{
TConnectivity& srcNodes = missingBndElems[i];
TConnectivity nodes( srcNodes.size() );
for ( inode = 0; inode < nodes.size(); ++inode )
nodes[inode] = getNodeWithSameID( tgtMeshDS, srcNodes[inode] );
- tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+ if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
+ missType,
+ /*noMedium=*/false))
+ continue;
+ tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
+ ++nbAddedBnd;
}
else
for ( int i = 0; i < missingBndElems.size(); ++i )
{
- TConnectivity& nodes = missingBndElems[i];
- tgtEditor.AddElement(nodes, missType, elem->IsPoly() && nodes.size()/(iQuad+1)>4);
+ TConnectivity& nodes = missingBndElems[i];
+ if ( aroundElements && tgtEditor.GetMeshDS()->FindElement( nodes,
+ missType,
+ /*noMedium=*/false))
+ continue;
+ SMDS_MeshElement* elem =
+ tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
+ ++nbAddedBnd;
+
+ // try to set a new element to a shape
+ if ( myMesh->HasShapeToMesh() )
+ {
+ bool ok = true;
+ set< pair<TopAbs_ShapeEnum, int > > mediumShapes;
+ const int nbN = nodes.size() / (iQuad+1 );
+ for ( inode = 0; inode < nbN && ok; ++inode )
+ {
+ pair<int, TopAbs_ShapeEnum> i_stype =
+ helper.GetMediumPos( nodes[inode], nodes[(inode+1)%nbN]);
+ if (( ok = ( i_stype.first > 0 && i_stype.second >= TopAbs_FACE )))
+ mediumShapes.insert( make_pair ( i_stype.second, i_stype.first ));
+ }
+ if ( ok && mediumShapes.size() > 1 )
+ {
+ set< pair<TopAbs_ShapeEnum, int > >::iterator stype_i = mediumShapes.begin();
+ pair<TopAbs_ShapeEnum, int> stype_i_0 = *stype_i;
+ for ( ++stype_i; stype_i != mediumShapes.end() && ok; ++stype_i )
+ {
+ if (( ok = ( stype_i->first != stype_i_0.first )))
+ ok = helper.IsSubShape( aMesh->IndexToShape( stype_i->second ),
+ aMesh->IndexToShape( stype_i_0.second ));
+ }
+ }
+ if ( ok && mediumShapes.begin()->first == missShapeType )
+ aMesh->SetMeshElementOnShape( elem, mediumShapes.begin()->second );
+ }
}
+ // ----------------------------------
// 3. Copy present boundary elements
- if ( toCopyExistingBondary )
+ // ----------------------------------
+ if ( toCopyExistingBoundary )
for ( int i = 0 ; i < presentBndElems.size(); ++i )
{
const SMDS_MeshElement* e = presentBndElems[i];
TConnectivity nodes( e->NbNodes() );
for ( inode = 0; inode < nodes.size(); ++inode )
nodes[inode] = getNodeWithSameID( tgtMeshDS, e->GetNode(inode) );
- tgtEditor.AddElement(nodes, missType, e->IsPoly());
- // leave only missing elements in tgtEditor.myLastCreatedElems
- tgtEditor.myLastCreatedElems.Remove( tgtEditor.myLastCreatedElems.Size() );
+ presentEditor->AddElement(nodes, e->GetType(), e->IsPoly());
}
+ else // store present elements to add them to a group
+ for ( int i = 0 ; i < presentBndElems.size(); ++i )
+ {
+ presentEditor->myLastCreatedElems.Append(presentBndElems[i]);
+ }
+
} // loop on given elements
- // 4. Fill group with missing boundary elements
+ // ---------------------------------------------
+ // 4. Fill group with boundary elements
+ // ---------------------------------------------
if ( group )
{
if ( SMESHDS_Group* g = dynamic_cast<SMESHDS_Group*>( group->GetGroupDS() ))
g->SMDSGroup().Add( tgtEditor.myLastCreatedElems( i+1 ));
}
tgtEditor.myLastCreatedElems.Clear();
+ tgtEditor2.myLastCreatedElems.Clear();
+ // -----------------------
// 5. Copy given elements
- if ( toCopyElements )
+ // -----------------------
+ if ( toCopyElements && targetMesh != myMesh )
{
if (elements.empty())
eIt = aMesh->elementsIterator(elemType);
tgtEditor.myLastCreatedElems.Clear();
}
}
- return;
+ return nbAddedBnd;
}