-// Copyright (C) 2007-2008 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
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
+
// File : SMDS_VolumeTool.cxx
// Created : Tue Jul 13 12:22:13 2004
// Author : Edward AGAPOV (eap)
#include "SMDS_MeshElement.hxx"
#include "SMDS_MeshNode.hxx"
-#include "SMDS_PolyhedralVolumeOfNodes.hxx"
+#include "SMDS_VtkVolume.hxx"
#include "SMDS_Mesh.hxx"
#include "utilities.h"
myFaceNodeIndices( NULL ),
myFaceNodes( NULL )
{
+ //MESSAGE("******************************************************** SMDS_VolumeToo");
}
//=======================================================================
myFaceNodeIndices( NULL ),
myFaceNodes( NULL )
{
+ //MESSAGE("******************************************************** SMDS_VolumeToo");
Set( theVolume );
}
SMDS_VolumeTool::~SMDS_VolumeTool()
{
- if (myVolumeNodes != NULL) {
- delete [] myVolumeNodes;
- myVolumeNodes = NULL;
- }
- if (myFaceNodes != NULL) {
- delete [] myFaceNodes;
- myFaceNodes = NULL;
- }
+ if ( myVolumeNodes != NULL ) delete [] myVolumeNodes;
+ if ( myFaceNodes != NULL ) delete [] myFaceNodes;
+
+ myFaceNodeIndices = NULL;
+ myVolumeNodes = myFaceNodes = NULL;
}
//=======================================================================
}
if (myVolume->IsPoly()) {
- myPolyedre = static_cast<const SMDS_PolyhedralVolumeOfNodes*>( myVolume );
+ myPolyedre = dynamic_cast<const SMDS_VtkVolume*>( myVolume );
if (!myPolyedre) {
MESSAGE("Warning: bad volumic element");
return false;
// define volume orientation
XYZ botNormal;
GetFaceNormal( 0, botNormal.x, botNormal.y, botNormal.z );
- const SMDS_MeshNode* topNode = myVolumeNodes[ myVolumeNbNodes - 1 ];
const SMDS_MeshNode* botNode = myVolumeNodes[ 0 ];
+ int topNodeIndex = myVolume->NbCornerNodes() - 1;
+ while ( !IsLinked( 0, topNodeIndex, /*ignoreMediumNodes=*/true )) --topNodeIndex;
+ const SMDS_MeshNode* topNode = myVolumeNodes[ topNodeIndex ];
XYZ upDir (topNode->X() - botNode->X(),
topNode->Y() - botNode->Y(),
topNode->Z() - botNode->Z() );
if ( !myPolyedre )
return 0.;
+ SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myPolyedre->getMeshId()];
// split a polyhedron into tetrahedrons
SMDS_VolumeTool* me = const_cast< SMDS_VolumeTool* > ( this );
XYZ baryCenter;
me->GetBaryCenter(baryCenter.x, baryCenter.y, baryCenter.z);
- SMDS_MeshNode bcNode ( baryCenter.x, baryCenter.y, baryCenter.z );
+ SMDS_MeshNode *bcNode = mesh->AddNode( baryCenter.x, baryCenter.y, baryCenter.z );
for ( int f = 0; f < NbFaces(); ++f )
{
double Vn = getTetraVolume( myFaceNodes[ 0 ],
myFaceNodes[ n-1 ],
myFaceNodes[ n ],
- & bcNode );
+ bcNode );
/// cout <<"++++ " << Vn << " nodes " <<myFaceNodes[ 0 ]->GetID() << " " <<myFaceNodes[ n-1 ]->GetID() << " " <<myFaceNodes[ n ]->GetID() << " < " << V << endl;
V += externalFace ? -Vn : Vn;
}
}
+ mesh->RemoveNode(bcNode);
}
else
{
const int* SMDS_VolumeTool::GetFaceNodesIndices( int faceIndex )
{
- if (myVolume->IsPoly()) {
- MESSAGE("Warning: attempt to obtain FaceNodesIndices of polyhedral volume");
- return NULL;
- }
if ( !setFace( faceIndex ))
return 0;
+
+ if (myVolume->IsPoly())
+ {
+ myPolyIndices.resize( myFaceNbNodes + 1 );
+ myFaceNodeIndices = & myPolyIndices[0];
+ for ( int i = 0; i <= myFaceNbNodes; ++i )
+ myFaceNodeIndices[i] = myVolume->GetNodeIndex( myFaceNodes[i] );
+ }
return myFaceNodeIndices;
}
//=======================================================================
//function : IsFaceExternal
-//purpose : Check normal orientation of a returned face
+//purpose : Check normal orientation of a given face
//=======================================================================
bool SMDS_VolumeTool::IsFaceExternal( int faceIndex )
return true;
}
+//================================================================================
+/*!
+ * \brief Return barycenter of a face
+ */
+//================================================================================
+
+bool SMDS_VolumeTool::GetFaceBaryCenter (int faceIndex, double & X, double & Y, double & Z)
+{
+ if ( !setFace( faceIndex ))
+ return false;
+
+ X = Y = Z = 0.0;
+ for ( int i = 0; i < myFaceNbNodes; ++i )
+ {
+ X += myFaceNodes[i]->X() / myFaceNbNodes;
+ Y += myFaceNodes[i]->Y() / myFaceNbNodes;
+ Z += myFaceNodes[i]->Z() / myFaceNbNodes;
+ }
+ return true;
+}
+
//=======================================================================
//function : GetFaceArea
//purpose : Return face area
//=======================================================================
//function : IsLinked
//purpose : return true if theNode1 is linked with theNode2
+// If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well
//=======================================================================
bool SMDS_VolumeTool::IsLinked (const SMDS_MeshNode* theNode1,
- const SMDS_MeshNode* theNode2) const
+ const SMDS_MeshNode* theNode2,
+ const bool theIgnoreMediumNodes) const
{
if ( !myVolume )
return false;
//function : IsLinked
//purpose : return true if the node with theNode1Index is linked
// with the node with theNode2Index
+// If theIgnoreMediumNodes then corner nodes of quadratic cell are considered linked as well
//=======================================================================
bool SMDS_VolumeTool::IsLinked (const int theNode1Index,
- const int theNode2Index) const
+ const int theNode2Index,
+ bool theIgnoreMediumNodes) const
{
if ( myVolume->IsPoly() ) {
return IsLinked(myVolumeNodes[theNode1Index], myVolumeNodes[theNode2Index]);
if ( minInd < 0 || maxInd > myVolumeNbNodes - 1 || maxInd == minInd )
return false;
- switch ( myVolumeNbNodes ) {
- case 4:
+ SMDSAbs_EntityType type = myVolume->GetEntityType();
+ if ( myVolume->IsQuadratic() )
+ {
+ int firstMediumInd = myVolume->NbCornerNodes();
+ if ( minInd >= firstMediumInd )
+ return false; // medium nodes are not linked
+ if ( maxInd < firstMediumInd ) // both nodes are corners
+ {
+ if ( theIgnoreMediumNodes )
+ type = SMDSAbs_EntityType( int(type)-1 ); // check linkage of corner nodes
+ else
+ return false; // corner nodes are not linked directly in a quadratic cell
+ }
+ }
+
+ switch ( type ) {
+ case SMDSEntity_Tetra:
return true;
- case 5:
+ case SMDSEntity_Hexa:
+ switch ( maxInd - minInd ) {
+ case 1: return minInd != 3;
+ case 3: return minInd == 0 || minInd == 4;
+ case 4: return true;
+ default:;
+ }
+ break;
+ case SMDSEntity_Pyramid:
if ( maxInd == 4 )
return true;
switch ( maxInd - minInd ) {
default:;
}
break;
- case 6:
+ case SMDSEntity_Penta:
switch ( maxInd - minInd ) {
case 1: return minInd != 2;
case 2: return minInd == 0 || minInd == 3;
default:;
}
break;
- case 8:
- switch ( maxInd - minInd ) {
- case 1: return minInd != 3;
- case 3: return minInd == 0 || minInd == 4;
- case 4: return true;
- default:;
- }
- break;
- case 10:
+ case SMDSEntity_Quad_Tetra:
{
switch ( minInd ) {
case 0: if( maxInd==4 || maxInd==6 || maxInd==7 ) return true;
}
break;
}
- case 13:
+ case SMDSEntity_Quad_Hexa:
+ {
+ switch ( minInd ) {
+ case 0: if( maxInd==8 || maxInd==11 || maxInd==16 ) return true;
+ case 1: if( maxInd==8 || maxInd==9 || maxInd==17 ) return true;
+ case 2: if( maxInd==9 || maxInd==10 || maxInd==18 ) return true;
+ case 3: if( maxInd==10 || maxInd==11 || maxInd==19 ) return true;
+ case 4: if( maxInd==12 || maxInd==15 || maxInd==16 ) return true;
+ case 5: if( maxInd==12 || maxInd==13 || maxInd==17 ) return true;
+ case 6: if( maxInd==13 || maxInd==14 || maxInd==18 ) return true;
+ case 7: if( maxInd==14 || maxInd==15 || maxInd==19 ) return true;
+ default:;
+ }
+ break;
+ }
+ case SMDSEntity_Quad_Pyramid:
{
switch ( minInd ) {
case 0: if( maxInd==5 || maxInd==8 || maxInd==9 ) return true;
}
break;
}
- case 15:
+ case SMDSEntity_Quad_Penta:
{
switch ( minInd ) {
case 0: if( maxInd==6 || maxInd==8 || maxInd==12 ) return true;
}
break;
}
- case 20:
- {
- switch ( minInd ) {
- case 0: if( maxInd==8 || maxInd==11 || maxInd==16 ) return true;
- case 1: if( maxInd==8 || maxInd==9 || maxInd==17 ) return true;
- case 2: if( maxInd==9 || maxInd==10 || maxInd==18 ) return true;
- case 3: if( maxInd==10 || maxInd==11 || maxInd==19 ) return true;
- case 4: if( maxInd==12 || maxInd==15 || maxInd==16 ) return true;
- case 5: if( maxInd==12 || maxInd==13 || maxInd==17 ) return true;
- case 6: if( maxInd==13 || maxInd==14 || maxInd==18 ) return true;
- case 7: if( maxInd==14 || maxInd==15 || maxInd==19 ) return true;
- default:;
- }
- break;
- }
default:;
}
return false;
return edges.size();
}
-//=======================================================================
-//function : IsFreeFace
-//purpose : check that only one volume is build on the face nodes
-//=======================================================================
+//================================================================================
+/*!
+ * \brief check that only one volume is build on the face nodes
+ *
+ * If a face is shared by one of <ignoreVolumes>, it is considered free
+ */
+//================================================================================
-bool SMDS_VolumeTool::IsFreeFace( int faceIndex )
+bool SMDS_VolumeTool::IsFreeFace( int faceIndex, const SMDS_MeshElement** otherVol/*=0*/ )
{
- const int free = true;
+ const bool isFree = true;
if (!setFace( faceIndex ))
- return !free;
+ return !isFree;
const SMDS_MeshNode** nodes = GetFaceNodes( faceIndex );
- int nbFaceNodes = myFaceNbNodes;
+ const int nbFaceNodes = myFaceNbNodes;
// evaluate nb of face nodes shared by other volume
int maxNbShared = -1;
TElemIntMap::iterator vNbIt;
for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) {
const SMDS_MeshNode* n = nodes[ iNode ];
- SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator();
+ SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( SMDSAbs_Volume );
while ( eIt->more() ) {
const SMDS_MeshElement* elem = eIt->next();
- if ( elem != myVolume && elem->GetType() == SMDSAbs_Volume ) {
- int nbShared = 1;
- vNbIt = volNbShared.find( elem );
- if ( vNbIt == volNbShared.end() ) {
- volNbShared.insert ( TElemIntMap::value_type( elem, nbShared ));
- }
- else {
- nbShared = ++(*vNbIt).second;
- }
- if ( nbShared > maxNbShared )
- maxNbShared = nbShared;
+ if ( elem != myVolume ) {
+ vNbIt = volNbShared.insert( make_pair( elem, 0 )).first;
+ (*vNbIt).second++;
+ if ( vNbIt->second > maxNbShared )
+ maxNbShared = vNbIt->second;
}
}
}
if ( maxNbShared < 3 )
- return free; // is free
+ return isFree; // is free
// find volumes laying on the opposite side of the face
// and sharing all nodes
if ( IsFaceExternal( faceIndex ))
intNormal = XYZ( -intNormal.x, -intNormal.y, -intNormal.z );
XYZ p0 ( nodes[0] ), baryCenter;
- for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ ) {
- int nbShared = (*vNbIt).second;
+ for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); ) {
+ const int& nbShared = (*vNbIt).second;
if ( nbShared >= 3 ) {
SMDS_VolumeTool volume( (*vNbIt).first );
volume.GetBaryCenter( baryCenter.x, baryCenter.y, baryCenter.z );
XYZ intNormal2( baryCenter - p0 );
- if ( intNormal.Dot( intNormal2 ) < 0 )
- continue; // opposite side
+ if ( intNormal.Dot( intNormal2 ) < 0 ) {
+ // opposite side
+ if ( nbShared >= nbFaceNodes )
+ {
+ // a volume shares the whole facet
+ if ( otherVol ) *otherVol = vNbIt->first;
+ return !isFree;
+ }
+ ++vNbIt;
+ continue;
+ }
}
// remove a volume from volNbShared map
- volNbShared.erase( vNbIt-- );
+ volNbShared.erase( vNbIt++ );
}
- // here volNbShared contains only volumes laying on the
- // opposite side of the face
- if ( volNbShared.empty() ) {
- return free; // is free
+ // here volNbShared contains only volumes laying on the opposite side of
+ // the face and sharing 3 or more but not all face nodes with myVolume
+ if ( volNbShared.size() < 2 ) {
+ return isFree; // is free
}
// check if the whole area of a face is shared
- bool isShared[] = { false, false, false, false }; // 4 triangle parts of a quadrangle
- for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ ) {
- SMDS_VolumeTool volume( (*vNbIt).first );
- bool prevLinkShared = false;
- int nbSharedLinks = 0;
- for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) {
- bool linkShared = volume.IsLinked( nodes[ iNode ], nodes[ iNode + 1] );
- if ( linkShared )
- nbSharedLinks++;
- if ( linkShared && prevLinkShared &&
- volume.IsLinked( nodes[ iNode - 1 ], nodes[ iNode + 1] ))
- isShared[ iNode ] = true;
- prevLinkShared = linkShared;
- }
- if ( nbSharedLinks == nbFaceNodes )
- return !free; // is not free
- if ( nbFaceNodes == 4 ) {
- // check traingle parts 1 & 3
- if ( isShared[1] && isShared[3] )
- return !free; // is not free
- // check triangle parts 0 & 2;
- // 0 part could not be checked in the loop; check it here
- if ( isShared[2] && prevLinkShared &&
- volume.IsLinked( nodes[ 0 ], nodes[ 1 ] ) &&
- volume.IsLinked( nodes[ 1 ], nodes[ 3 ] ) )
- return !free; // is not free
- }
+ for ( int iNode = 0; iNode < nbFaceNodes; iNode++ )
+ {
+ const SMDS_MeshNode* n = nodes[ iNode ];
+ // check if n is shared by one of volumes of volNbShared
+ bool isShared = false;
+ SMDS_ElemIteratorPtr eIt = n->GetInverseElementIterator( SMDSAbs_Volume );
+ while ( eIt->more() && !isShared )
+ isShared = volNbShared.count( eIt->next() );
+ if ( !isShared )
+ return isFree;
}
- return free;
+ if ( otherVol ) *otherVol = volNbShared.begin()->first;
+ return !isFree;
+
+// if ( !myVolume->IsPoly() )
+// {
+// bool isShared[] = { false, false, false, false }; // 4 triangle parts of a quadrangle
+// for ( vNbIt = volNbShared.begin(); vNbIt != volNbShared.end(); vNbIt++ ) {
+// SMDS_VolumeTool volume( (*vNbIt).first );
+// bool prevLinkShared = false;
+// int nbSharedLinks = 0;
+// for ( int iNode = 0; iNode < nbFaceNodes; iNode++ ) {
+// bool linkShared = volume.IsLinked( nodes[ iNode ], nodes[ iNode + 1] );
+// if ( linkShared )
+// nbSharedLinks++;
+// if ( linkShared && prevLinkShared &&
+// volume.IsLinked( nodes[ iNode - 1 ], nodes[ iNode + 1] ))
+// isShared[ iNode ] = true;
+// prevLinkShared = linkShared;
+// }
+// if ( nbSharedLinks == nbFaceNodes )
+// return !free; // is not free
+// if ( nbFaceNodes == 4 ) {
+// // check traingle parts 1 & 3
+// if ( isShared[1] && isShared[3] )
+// return !free; // is not free
+// // check triangle parts 0 & 2;
+// // 0 part could not be checked in the loop; check it here
+// if ( isShared[2] && prevLinkShared &&
+// volume.IsLinked( nodes[ 0 ], nodes[ 1 ] ) &&
+// volume.IsLinked( nodes[ 1 ], nodes[ 3 ] ) )
+// return !free; // is not free
+// }
+// }
+// }
+// return free;
}
//=======================================================================
return false;
}
- // check orientation
- bool isGoodOri = true;
- if (myExternalFaces)
- isGoodOri = IsFaceExternal( faceIndex );
-
// set face nodes
int iNode;
myFaceNbNodes = myPolyedre->NbFaceNodes(faceIndex + 1);
myFaceNodes = new const SMDS_MeshNode* [myFaceNbNodes + 1];
- if (isGoodOri) {
- for ( iNode = 0; iNode < myFaceNbNodes; iNode++ )
- myFaceNodes[ iNode ] = myPolyedre->GetFaceNode(faceIndex + 1, iNode + 1);
- } else {
- for ( iNode = 0; iNode < myFaceNbNodes; iNode++ )
- myFaceNodes[ iNode ] = myPolyedre->GetFaceNode(faceIndex + 1, myFaceNbNodes - iNode);
- }
+ for ( iNode = 0; iNode < myFaceNbNodes; iNode++ )
+ myFaceNodes[ iNode ] = myPolyedre->GetFaceNode(faceIndex + 1, iNode + 1);
myFaceNodes[ myFaceNbNodes ] = myFaceNodes[ 0 ]; // last = first
+ // check orientation
+ if (myExternalFaces)
+ {
+ myCurFace = faceIndex; // avoid infinite recursion in IsFaceExternal()
+ myExternalFaces = false; // force normal computation by IsFaceExternal()
+ if ( !IsFaceExternal( faceIndex ))
+ for ( int i = 0, j = myFaceNbNodes; i < j; ++i, --j )
+ std::swap( myFaceNodes[i], myFaceNodes[j] );
+ myExternalFaces = true;
+ }
}
else {
// choose face node indices
//purpose : return element
//=======================================================================
-const SMDS_MeshVolume* SMDS_VolumeTool::Get() const
+const SMDS_MeshVolume* SMDS_VolumeTool::Element() const
{
return static_cast<const SMDS_MeshVolume*>( myVolume );
}