-// Copyright (C) 2007-2010 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2011 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
-//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// 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
-// SMESH SMESH : idl implementation based on 'SMESH' unit's classes
+// 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 <gp_XY.hxx>
#include <gp_XYZ.hxx>
-#include <math.h>
+#include <cmath>
#include <map>
#include <set>
#include <numeric>
#include <limits>
+#include <algorithm>
+#include <sstream>
#define cast2Node(elem) static_cast<const SMDS_MeshNode*>( elem )
int nbnode = node.size();
SMESHDS_Mesh* mesh = GetMeshDS();
switch ( type ) {
- case SMDSAbs_0DElement:
- if ( nbnode == 1 ) {
- if ( ID >= 0 ) e = mesh->Add0DElementWithID(node[0], ID);
- else e = mesh->Add0DElement (node[0] );
- }
- break;
- case SMDSAbs_Edge:
- if ( nbnode == 2 ) {
- if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
- else e = mesh->AddEdge (node[0], node[1] );
- }
- else if ( nbnode == 3 ) {
- if ( ID >= 0 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
- else e = mesh->AddEdge (node[0], node[1], node[2] );
- }
- break;
case SMDSAbs_Face:
if ( !isPoly ) {
if (nbnode == 3) {
- if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
- else e = mesh->AddFace (node[0], node[1], node[2] );
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2] );
}
else if (nbnode == 4) {
- if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
- else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2], node[3] );
}
else if (nbnode == 6) {
- if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
- node[4], node[5], ID);
- else e = mesh->AddFace (node[0], node[1], node[2], node[3],
- node[4], node[5] );
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], ID);
+ else e = mesh->AddFace (node[0], node[1], node[2], node[3],
+ node[4], node[5] );
}
else if (nbnode == 8) {
- if ( ID >= 0 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
- node[4], node[5], node[6], node[7], ID);
- else e = mesh->AddFace (node[0], node[1], node[2], node[3],
- node[4], node[5], node[6], node[7] );
+ if ( ID >= 1 ) e = mesh->AddFaceWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7], ID);
+ 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 >= 0 ) e = mesh->AddPolygonalFaceWithID(node, ID);
- else e = mesh->AddPolygonalFace (node );
+ if ( ID >= 1 ) e = mesh->AddPolygonalFaceWithID(node, ID);
+ else e = mesh->AddPolygonalFace (node );
}
break;
+
case SMDSAbs_Volume:
if ( !isPoly ) {
if (nbnode == 4) {
- if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
- else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3] );
}
else if (nbnode == 5) {
- if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
- node[4], ID);
- else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
- node[4] );
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4] );
}
else if (nbnode == 6) {
- if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
- node[4], node[5], ID);
- else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
- node[4], node[5] );
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5] );
}
else if (nbnode == 8) {
- if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
- node[4], node[5], node[6], node[7], ID);
- else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
- node[4], node[5], node[6], node[7] );
+ if ( ID >= 1 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7], ID);
+ else e = mesh->AddVolume (node[0], node[1], node[2], node[3],
+ node[4], node[5], node[6], node[7] );
}
else if (nbnode == 10) {
- if ( ID >= 0 ) e = mesh->AddVolumeWithID(node[0], node[1], node[2], node[3],
- node[4], node[5], node[6], node[7],
- node[8], node[9], 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] );
+ 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], 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] );
+ }
+ 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 >= 0 ) 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],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] );
+ 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],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] );
}
else if (nbnode == 15) {
- if ( ID >= 0 ) 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],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] );
+ 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],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] );
}
else if (nbnode == 20) {
- if ( ID >= 0 ) 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],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] );
+ 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],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] );
+ }
+ 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;
+
+ case SMDSAbs_Edge:
+ if ( nbnode == 2 ) {
+ if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], ID);
+ else e = mesh->AddEdge (node[0], node[1] );
+ }
+ else if ( nbnode == 3 ) {
+ if ( ID >= 1 ) e = mesh->AddEdgeWithID(node[0], node[1], node[2], ID);
+ else e = mesh->AddEdge (node[0], node[1], node[2] );
+ }
+ break;
+
+ case SMDSAbs_0DElement:
+ if ( nbnode == 1 ) {
+ if ( ID >= 1 ) e = mesh->Add0DElementWithID(node[0], ID);
+ else e = mesh->Add0DElement (node[0] );
+ }
+ break;
+
+ case SMDSAbs_Node:
+ if ( ID >= 1 ) e = mesh->AddNodeWithID(node[0]->X(), node[0]->Y(), node[0]->Z(), ID);
+ else e = mesh->AddNode (node[0]->X(), node[0]->Y(), node[0]->Z());
+ break;
+
+ default:;
}
if ( e ) myLastCreatedElems.Append( e );
return e;
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
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
+
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],
{
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,
const int theMethodFlags)
{
// std-like iterator on coordinates of nodes of mesh element
- typedef SMDS_StdIterator< TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
+ typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > NXyzIterator;
NXyzIterator xyzEnd;
SMDS_VolumeTool volTool;
SMESH_MesherHelper helper( *GetMesh());
- SMESHDS_SubMesh* subMesh = GetMeshDS()->MeshElements(1);
- SMESHDS_SubMesh* fSubMesh = subMesh;
+ SMESHDS_SubMesh* subMesh = 0;//GetMeshDS()->MeshElements(1);
+ SMESHDS_SubMesh* fSubMesh = 0;//subMesh;
SMESH_SequenceOfElemPtr newNodes, newElems;
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 );
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() );
- gp_Vec vB ( pP, pB ), vA ( pP, pA ), vN ( pP, pN );
+ SMESH_TNodeXYZ pP = prevNodes[ iNotSame ];
+ SMESH_TNodeXYZ pN = nextNodes[ iNotSame ];
+ gp_XYZ extrDir( pN - pP ), faceNorm;
+ SMESH_Algo::FaceNormal( face, faceNorm, /*normalized=*/false );
- 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 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 ],
+ 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 ]);
- 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 ( nbDouble != 4 ) break;
+ if( nbSame == 0 ) {
+ // ---> 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 ) {
+ // ---> 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;
+ }
+ case SMDSEntity_Polygon: { // sweep POLYGON
+
+ 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;
}
+ default:
+ break;
}
}
- if(!aNewElem) {
- // realized for extrusion only
+ 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);
-
- 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];
+ 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 );
SMDS_ElemIteratorPtr eIt = node->GetInverseElementIterator();
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(),
if ( elem->GetType() != SMDSAbs_Face )
continue;
- if(itElem->second.size()==0) continue;
-
bool hasFreeLinks = false;
TIDSortedElemSet avoidSet;
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 ) {
+
+ 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;
+ bool isClosed = false;
+
+ //check start node
+ if( !theTrack->GetMeshDS()->Contains(theN1) ) {
+ return EXTR_BAD_STARTING_NODE;
+ }
+
+ 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++;
+ isClosed = true;
+ 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();
+ 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 ) )
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,
* \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;
int elemType = elem->GetType();
if (elem->IsPoly()) {
- // Polygon or Polyhedral Volume
+
+ // polygon or polyhedral volume
switch ( elemType ) {
case SMDSAbs_Face:
{
break;
case SMDSAbs_Volume:
{
- // ATTENTION: Reversing is not yet done!!!
const SMDS_VtkVolume* aPolyedre =
dynamic_cast<const SMDS_VtkVolume*>( elem );
if (!aPolyedre) {
continue;
}
- vector<const SMDS_MeshNode*> poly_nodes;
+ vector<const SMDS_MeshNode*> poly_nodes; poly_nodes.reserve( nbNodes );
vector<int> quantities;
bool allTransformed = true;
} else {
poly_nodes.push_back((*nodeMapIt).second);
}
+ if ( needReverse && allTransformed )
+ std::reverse( poly_nodes.end() - nbFaceNodes, poly_nodes.end() );
}
quantities.push_back(nbFaceNodes);
}
default:;
}
continue;
- }
+
+ } // elem->isPoly()
// 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;
- }
- }
- }
+
+ 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);
if ( nbNodes > 2 )
aMesh->ChangeElementNodes( elem, &nodes[0], nbNodes );
}
- }
+
+ } // 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
const SMDS_MeshNode* closestNode = 0;
list<const SMDS_MeshNode*>::iterator nIt = nodes.begin();
for ( ; nIt != nodes.end(); ++nIt ) {
- double sqDist = thePnt.SquareDistance( SMESH_MeshEditor::TNodeXYZ( *nIt ) );
+ double sqDist = thePnt.SquareDistance( SMESH_TNodeXYZ( *nIt ) );
if ( minSqDist > sqDist ) {
closestNode = *nIt;
minSqDist = sqDist;
{
public:
- ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance = NodeRadius );
+ 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);
~ElementBndBoxTree();
*/
//================================================================================
- ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, double tolerance)
+ ElementBndBoxTree::ElementBndBoxTree(const SMDS_Mesh& mesh, SMDSAbs_ElementType elemType, SMDS_ElemIteratorPtr theElemIt, double tolerance)
:SMESH_Octree( new SMESH_Octree::Limit( MaxLevel, /*minSize=*/0. ))
{
int nbElems = mesh.GetMeshInfo().NbElements( elemType );
_elements.reserve( nbElems );
- SMDS_ElemIteratorPtr elemIt = mesh.elementsIterator( elemType );
+ SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
while ( elemIt->more() )
_elements.push_back( new ElementBox( elemIt->next(),tolerance ));
_refCount = 1;
SMDS_ElemIteratorPtr nIt = elem->nodesIterator();
while ( nIt->more() )
- Add( SMESH_MeshEditor::TNodeXYZ( cast2Node( nIt->next() )));
+ Add( SMESH_TNodeXYZ( cast2Node( nIt->next() )));
Enlarge( tolerance );
}
struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher
{
SMESHDS_Mesh* _mesh;
+ SMDS_ElemIteratorPtr _meshPartIt;
ElementBndBoxTree* _ebbTree;
SMESH_NodeSearcherImpl* _nodeSearcher;
SMDSAbs_ElementType _elementType;
bool _outerFacesFound;
set<const SMDS_MeshElement*> _outerFaces; // empty means "no internal faces at all"
- SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh )
- : _mesh(&mesh),_ebbTree(0),_nodeSearcher(0), _tolerance(-1), _outerFacesFound(false) {}
+ SMESH_ElementSearcherImpl( SMESHDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr())
+ : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {}
~SMESH_ElementSearcherImpl()
{
if ( _ebbTree ) delete _ebbTree; _ebbTree = 0;
SMDS_NodeIteratorPtr nodeIt = _mesh->nodesIterator();
elemSize = 1;
if ( meshInfo.NbNodes() > 2 )
- elemSize = SMESH_MeshEditor::TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
+ elemSize = SMESH_TNodeXYZ( nodeIt->next() ).Distance( nodeIt->next() );
}
else
{
_mesh->elementsIterator( SMDSAbs_ElementType( complexType ));
const SMDS_MeshElement* elem = elemIt->next();
SMDS_ElemIteratorPtr nodeIt = elem->nodesIterator();
- SMESH_MeshEditor::TNodeXYZ n1( cast2Node( nodeIt->next() ));
+ SMESH_TNodeXYZ n1( cast2Node( nodeIt->next() ));
+ elemSize = 0;
while ( nodeIt->more() )
{
double dist = n1.Distance( cast2Node( nodeIt->next() ));
int nbNodes = face->IsQuadratic() ? face->NbNodes()/2 : face->NbNodes();
for ( int i = 0; i < nbNodes && nbInts < 2; ++i )
{
- GC_MakeSegment edge( SMESH_MeshEditor::TNodeXYZ( face->GetNode( i )),
- SMESH_MeshEditor::TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
+ GC_MakeSegment edge( SMESH_TNodeXYZ( face->GetNode( i )),
+ SMESH_TNodeXYZ( face->GetNode( (i+1)%nbNodes) ));
anExtCC.Init( lineCurve, edge);
if ( anExtCC.NbExtrema() > 0 && anExtCC.LowerDistance() <= tol)
{
seamLinks.insert( link );
// link direction within the outerFace
- gp_Vec n1n2( SMESH_MeshEditor::TNodeXYZ( link.node1()),
- SMESH_MeshEditor::TNodeXYZ( link.node2()));
+ gp_Vec n1n2( SMESH_TNodeXYZ( link.node1()),
+ SMESH_TNodeXYZ( link.node2()));
int i1 = outerFace->GetNodeIndex( link.node1() );
int i2 = outerFace->GetNodeIndex( link.node2() );
bool rev = ( abs(i2-i1) == 1 ? i1 > i2 : i2 > i1 );
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() )
const SMDS_MeshNode* closeNode = _nodeSearcher->FindClosestTo( point );
if ( !closeNode ) return foundElements.size();
- if ( point.Distance( SMESH_MeshEditor::TNodeXYZ( closeNode )) > tolerance )
+ if ( point.Distance( SMESH_TNodeXYZ( closeNode )) > tolerance )
return foundElements.size(); // to far from any node
if ( type == SMDSAbs_Node )
if ( !_ebbTree || _elementType != type )
{
if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, tolerance );
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt, tolerance );
}
TIDSortedElemSet suspectElems;
_ebbTree->getElementsNearPoint( point, suspectElems );
if ( !_ebbTree || _elementType != SMDSAbs_Face )
{
if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face );
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = SMDSAbs_Face, _meshPartIt );
}
// Algo: analyse transition of a line starting at the point through mesh boundary;
// try three lines parallel to axis of the coordinate system and perform rough
// get face plane
gp_XYZ fNorm;
if ( !SMESH_Algo::FaceNormal( *face, fNorm, /*normalized=*/false)) continue;
- gp_Pln facePlane( SMESH_MeshEditor::TNodeXYZ( (*face)->GetNode(0)), fNorm );
+ gp_Pln facePlane( SMESH_TNodeXYZ( (*face)->GetNode(0)), fNorm );
// perform intersection
IntAna_IntConicQuad intersection( line, IntAna_Quadric( facePlane ));
if ( !_ebbTree || _elementType != type )
{
if ( _ebbTree ) delete _ebbTree;
- _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type );
+ _ebbTree = new ElementBndBoxTree( *_mesh, _elementType = type, _meshPartIt );
}
TIDSortedElemSet suspectFaces; // elements possibly intersecting the line
_ebbTree->getElementsNearLine( line, suspectFaces );
return new SMESH_ElementSearcherImpl( *GetMeshDS() );
}
+//=======================================================================
+/*!
+ * \brief Return SMESH_ElementSearcher acting on a sub-set of elements
+ */
+//=======================================================================
+
+SMESH_ElementSearcher* SMESH_MeshEditor::GetElementSearcher(SMDS_ElemIteratorPtr elemIt)
+{
+ return new SMESH_ElementSearcherImpl( *GetMeshDS(), elemIt );
+}
+
//=======================================================================
/*!
* \brief Return true if the point is IN or ON of the element
while ( nodeIt->more() )
{
const SMDS_MeshNode* node = cast2Node( nodeIt->next() );
- xyz.push_back( TNodeXYZ(node) );
+ xyz.push_back( SMESH_TNodeXYZ(node) );
nodeList.push_back(node);
}
}
}
// 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() );
}
}
}
+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();
}
- if (!GetMeshDS()->isCompacted())
- GetMeshDS()->compactMesh();
+}
+
+//================================================================================
+/*!
+ * \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();
+ }
}
//=======================================================================
/*!
* \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 :
}
// 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 );
* \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
*/
//================================================================================
gp_XYZ centerXYZ (0, 0, 0);
SMDS_ElemIteratorPtr aNodeItr = theElem->nodesIterator();
while (aNodeItr->more())
- centerXYZ += SMESH_MeshEditor::TNodeXYZ(cast2Node( aNodeItr->next()));
+ centerXYZ += SMESH_TNodeXYZ(cast2Node( aNodeItr->next()));
gp_Pnt aPnt = centerXYZ / theElem->NbNodes();
theClassifier.Perform(aPnt, theTol);
_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
{
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++)
if (!faceDomains[face].count(idom))
{
faceDomains[face][idom] = vtkId; // volume associated to face in this domain
+ celldom[vtkId] = 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;
+
+ // --- 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++)
+ {
+ 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);
+ std::set<int> cells;
+ cells.clear();
+ 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 (celldom.count(vtkId))
+ continue;
+ cellDomains[aCell][idomain] = vtkId;
+ celldom[vtkId] = idomain;
+ }
+ }
+ }
+ }
- // --- for each shared face, get the nodes
+ // --- 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 muti domains with domain order
+
+ 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);
+ bool isMultipleDetected = false;
+ 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(" 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
+ 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);
+ isMultipleDetected =true;
+ 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(" newNode " << newId << " oldNode " << oldId << " size=" <<nodeDomains[oldId].size());
+ }
+ if (nodeDomains[oldId].size() >= 3)
+ {
+ //MESSAGE("confirm multiple node " << oldId);
+ isMultipleDetected =true;
+ }
+ }
+ }
+ if (isMultipleDetected) // 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;
+ 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]];
+ sort( vn0.begin(), vn0.end() );
+ sort( vn1.begin(), vn1.end() );
+ if (vn0 == vn1)
+ {
+ //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 < vn0.size(); id++)
+ {
+ int idom = vn0[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)
{
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_MeshVolume *vol = grid->extrudeVolumeFromFace(vtkVolId, dom1, dom2, oldNodes, nodeDomains,
+ nodeQuadDomains);
+ stringstream grpname;
+ grpname << "j_";
+ if (dom1 < dom2)
+ grpname << dom1 << "_" << dom2;
+ else
+ grpname << dom2 << "_" << dom1;
+ 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());
+ }
+ }
+
+ // --- create volumes on multiple domain intersection if requested
+ // iterate on edgesMultiDomains
- localClonedNodeIds.clear();
- for (itn = oldNodes.begin(); itn != oldNodes.end(); ++itn)
+ if (createJointElems)
+ {
+ 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);
+
+ stringstream grpname;
+ grpname << "mj_";
+ grpname << 0 << "_" << 0;
+ 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());
+ }
+ else
+ {
+ //MESSAGE("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 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;
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;
+ tgtEditor.AddElement(nodes, missType, !iQuad && nodes.size()/(iQuad+1)>4);
+ ++nbAddedBnd;
}
+ // ----------------------------------
// 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;
}