22359: Body Fitting algorithm: grid orientation

This commit is contained in:
eap 2014-02-14 16:09:40 +04:00
parent b65f7717ee
commit 86aa8ad014
3 changed files with 263 additions and 63 deletions

View File

@ -3092,9 +3092,11 @@ void _pyComplexParamHypo::Process( const Handle(_pyCommand)& theCommand)
{
// CartesianParameters3D hyp
if ( theCommand->GetMethod() == "SetSizeThreshold" )
if ( theCommand->GetMethod() == "SetSizeThreshold" ||
theCommand->GetMethod() == "SetToAddEdges" )
{
setCreationArg( 4, theCommand->GetArg( 1 ));
int iEdges = ( theCommand->GetMethod().Value( 4 ) == 'T' );
setCreationArg( 4+iEdges, theCommand->GetArg( 1 ));
myArgCommands.push_back( theCommand );
return;
}

View File

@ -1400,18 +1400,17 @@ class StdMeshersBuilder_Cartesian_3D(Mesh_Algorithm):
# Examples:
# - "10.5" - defines a grid with a constant spacing
# - [["1", "1+10*t", "11"] [0.1, 0.6]] - defines different spacing in 3 ranges.
# @param yGridDef defines the grid along the Y asix the same way as \a xGridDef does
# @param zGridDef defines the grid along the Z asix the same way as \a xGridDef does
# @param yGridDef defines the grid along the Y asix the same way as \a xGridDef does.
# @param zGridDef defines the grid along the Z asix the same way as \a xGridDef does.
# @param sizeThreshold (> 1.0) defines a minimal size of a polyhedron so that
# a polyhedron of size less than hexSize/sizeThreshold is not created
# @param UseExisting if ==true - searches for the existing hypothesis created with
# the same parameters, else (default) - creates a new one
def SetGrid(self, xGridDef, yGridDef, zGridDef, sizeThreshold=4.0, UseExisting=False):
# a polyhedron of size less than hexSize/sizeThreshold is not created.
# @param implEdges enables implementation of geometrical edges into the mesh.
def SetGrid(self, xGridDef, yGridDef, zGridDef, sizeThreshold=4.0, implEdges=False):
if not self.hyp:
compFun = lambda hyp, args: False
self.hyp = self.Hypothesis("CartesianParameters3D",
[xGridDef, yGridDef, zGridDef, sizeThreshold],
UseExisting=UseExisting, CompareMethod=compFun)
UseExisting=False, CompareMethod=compFun)
if not self.mesh.IsUsedHypothesis( self.hyp, self.geom ):
self.mesh.AddHypothesis( self.hyp, self.geom )
@ -1427,6 +1426,7 @@ class StdMeshersBuilder_Cartesian_3D(Mesh_Algorithm):
else:
self.hyp.SetGridSpacing( gridDef[0], gridDef[1], axis )
self.hyp.SetSizeThreshold( sizeThreshold )
self.hyp.SetToAddEdges( implEdges )
return self.hyp
## Defines custom directions of axes of the grid

View File

@ -83,7 +83,7 @@
#include <gp_Sphere.hxx>
#include <gp_Torus.hxx>
//#undef WITH_TBB
#undef WITH_TBB
#ifdef WITH_TBB
#include <tbb/parallel_for.h>
//#include <tbb/enumerable_thread_specific.h>
@ -179,7 +179,7 @@ namespace
B_IntersectPoint(): _node(NULL) {}
void Add( const vector< TGeomID >& fIDs, const SMDS_MeshNode* n=0 ) const;
bool HasCommonFace( const B_IntersectPoint * other ) const;
int HasCommonFace( const B_IntersectPoint * other, int avoidFace=-1 ) const;
bool IsOnFace( int faceID ) const;
virtual ~B_IntersectPoint() {}
};
@ -442,8 +442,10 @@ namespace
{
const SMDS_MeshNode* _node; // mesh node at hexahedron corner
const B_IntersectPoint* _intPoint;
bool _isUsedInFace;
_Node(const SMDS_MeshNode* n=0, const B_IntersectPoint* ip=0):_node(n), _intPoint(ip) {}
_Node(const SMDS_MeshNode* n=0, const B_IntersectPoint* ip=0)
:_node(n), _intPoint(ip), _isUsedInFace(0) {}
const SMDS_MeshNode* Node() const
{ return ( _intPoint && _intPoint->_node ) ? _intPoint->_node : _node; }
const F_IntersectPoint* FaceIntPnt() const
@ -463,9 +465,10 @@ namespace
_intPoint->Add( ip->_faceIDs );
}
}
bool IsLinked( const B_IntersectPoint* other ) const
int IsLinked( const B_IntersectPoint* other,
int avoidFace=-1 ) const // returns id of a common face
{
return _intPoint && _intPoint->HasCommonFace( other );
return _intPoint ? _intPoint->HasCommonFace( other, avoidFace ) : 0;
}
bool IsOnFace( int faceID ) const // returns true if faceID is found
{
@ -502,9 +505,9 @@ namespace
return _OrientedLink(&_link->_splits[_reverse ? NbResultLinks()-i-1 : i],_reverse);
}
_Node* FirstNode() const { return _link->_nodes[ _reverse ]; }
_Node* LastNode() const { return _link->_nodes[ !_reverse ]; }
_Node* LastNode() const { return _link->_nodes[ !_reverse ]; }
operator bool() const { return _link; }
vector< TGeomID > GetNotUsedFace(const set<TGeomID>& usedIDs ) const // returns a supporting FACEs
vector< TGeomID > GetNotUsedFace(const set<TGeomID>& usedIDs ) const // returns supporting FACEs
{
vector< TGeomID > faces;
const B_IntersectPoint *ip0, *ip1;
@ -518,6 +521,11 @@ namespace
}
return faces;
}
bool HasEdgeNodes() const
{
return ( dynamic_cast< const E_IntersectPoint* >( _link->_nodes[0]->_intPoint ) ||
dynamic_cast< const E_IntersectPoint* >( _link->_nodes[1]->_intPoint ));
}
};
// --------------------------------------------------------------------------------
struct _Face
@ -593,13 +601,16 @@ namespace
vector< Hexahedron* >& hexes,
int ijk[], int dIJK[] );
bool findChain( _Node* n1, _Node* n2, _Face& quad, vector<_Node*>& chainNodes );
bool closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const;
int addElements(SMESH_MesherHelper& helper);
bool is1stNodeOut( int iLink ) const;
bool isInHole() const;
bool checkPolyhedronSize() const;
bool addHexa ();
bool addTetra();
bool addPenta();
bool addPyra ();
bool debugDumpLink( _Link* link );
_Node* FindEqualNode( vector< _Node >& nodes,
const E_IntersectPoint* ip,
const double tol2 )
@ -725,7 +736,8 @@ namespace
return ( ipBef->_transition == Trans_OUT );
return ( ipBef->_transition != Trans_OUT );
}
return prevIsOut; // _transition == Trans_TANGENT
// _transition == Trans_TANGENT
return !prevIsOut;
}
//================================================================================
/*
@ -749,15 +761,16 @@ namespace
}
//================================================================================
/*
* Returns \c true if \a other B_IntersectPoint holds the same face ID
* Returns index of a common face if any, else zero
*/
bool B_IntersectPoint::HasCommonFace( const B_IntersectPoint * other ) const
int B_IntersectPoint::HasCommonFace( const B_IntersectPoint * other, int avoidFace ) const
{
if ( other )
for ( size_t i = 0; i < other->_faceIDs.size(); ++i )
if ( IsOnFace( other->_faceIDs[i] ) )
return true;
return false;
if ( avoidFace != other->_faceIDs[i] &&
IsOnFace ( other->_faceIDs[i] ))
return other->_faceIDs[i];
return 0;
}
//================================================================================
/*
@ -1582,11 +1595,11 @@ namespace
_Link& link = _hexLinks[ iLink ];
link._splits.clear();
split._nodes[ 0 ] = link._nodes[0];
bool isOut = ( ! link._nodes[0]->Node() );
//int iEnd = link._intNodes.size() - bool( link._nodes[1]->_intPoint );
bool isOut = ( ! link._nodes[0]->Node() ); // is1stNodeOut( iLink );
bool checkTransition;
for ( size_t i = 0; i < link._intNodes.size(); ++i )
{
if ( link._intNodes[i].Node() )
if ( link._intNodes[i].Node() ) // intersection non-coinsident with a grid node
{
if ( split._nodes[ 0 ]->Node() && !isOut )
{
@ -1594,11 +1607,19 @@ namespace
link._splits.push_back( split );
}
split._nodes[ 0 ] = &link._intNodes[i];
checkTransition = true;
}
switch ( link._intNodes[i].FaceIntPnt()->_transition ) {
case Trans_OUT: isOut = true; break;
case Trans_IN : isOut = false; break;
default:; // isOut remains the same
else // FACE intersection coinsident with a grid node
{
checkTransition = ( link._nodes[0]->Node() );
}
if ( checkTransition )
{
switch ( link._intNodes[i].FaceIntPnt()->_transition ) {
case Trans_OUT: isOut = true; break;
case Trans_IN : isOut = false; break;
default:; // isOut remains the same
}
}
}
if ( link._nodes[ 1 ]->Node() && split._nodes[ 0 ]->Node() && !isOut )
@ -1744,9 +1765,10 @@ namespace
return;
_polygons.clear();
_polygons.reserve( 10 );
_polygons.reserve( 20 );
// create polygons from quadrangles and get their nodes
// Create polygons from quadrangles
// --------------------------------
_Link polyLink;
vector< _OrientedLink > splits;
@ -1788,6 +1810,11 @@ namespace
_vertexNodes.push_back( quad._edgeNodes[ iP ]);
}
}
#ifdef _DEBUG_
for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
quad._edgeNodes[ iP ]._isUsedInFace = false;
#endif
int nbUsedEdgeNodes = 0;
while ( nbSplits > 0 )
{
@ -1815,8 +1842,8 @@ namespace
n1 = split.FirstNode();
if ( n1 != n2 )
{
// try to connect to intersections with EDGES
if ( quad._edgeNodes.size() > 0 &&
// try to connect to intersections with EDGEs
if ( quad._edgeNodes.size() > nbUsedEdgeNodes &&
findChain( n2, n1, quad, chainNodes ))
{
for ( size_t i = 1; i < chainNodes.size(); ++i )
@ -1825,6 +1852,13 @@ namespace
polyLink._nodes[1] = chainNodes[i];
polygon->_polyLinks.push_back( polyLink );
polygon->_links.push_back( _OrientedLink( &polygon->_polyLinks.back() ));
nbUsedEdgeNodes += polyLink._nodes[1]->_isUsedInFace;
}
if ( chainNodes.back() != n1 )
{
n2 = chainNodes.back();
--iS;
continue;
}
}
// try to connect to a split ending on the same FACE
@ -1870,7 +1904,11 @@ namespace
if ( nFirst != n2 ) // close a polygon
{
findChain( n2, nFirst, quad, chainNodes );
if ( !findChain( n2, nFirst, quad, chainNodes ))
{
if ( !closePolygon( polygon, chainNodes ))
;//chainNodes.push_back( nFirst );
}
for ( size_t i = 1; i < chainNodes.size(); ++i )
{
polyLink._nodes[0] = chainNodes[i-1];
@ -1892,7 +1930,8 @@ namespace
} // loop on 6 sides of a hexahedron
// create polygons closing holes in a polyhedron
// Create polygons closing holes in a polyhedron
// ----------------------------------------------
// add polygons to their links
for ( size_t iP = 0; iP < _polygons.size(); ++iP )
@ -1915,7 +1954,7 @@ namespace
freeLinks.push_back( & polygon._links[ iL ]);
}
int nbFreeLinks = freeLinks.size();
if ( 0 < nbFreeLinks && nbFreeLinks < 3 ) return;
if ( nbFreeLinks < 3 ) return;
set<TGeomID> usedFaceIDs;
@ -1958,22 +1997,42 @@ namespace
// get a remaining link to start from, one lying on minimal
// nb of FACEs
{
map< vector< TGeomID >, int > facesOfLink;
map< vector< TGeomID >, int >::iterator f2l;
vector< pair< TGeomID, int > > facesOfLink[3];
pair< TGeomID, int > faceOfLink( -1, -1 );
vector< TGeomID > faces;
for ( size_t iL = 0; iL < freeLinks.size(); ++iL )
if ( freeLinks[ iL ] )
{
f2l = facesOfLink.insert
( make_pair( freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs ), iL )).first;
if ( f2l->first.size() == 1 )
break;
faces = freeLinks[ iL ]->GetNotUsedFace( usedFaceIDs );
if ( faces.size() == 1 )
{
faceOfLink = make_pair( faces[0], iL );
if ( !freeLinks[ iL ]->HasEdgeNodes() )
break;
facesOfLink[0].push_back( faceOfLink );
}
else if ( facesOfLink[0].empty() )
{
faceOfLink = make_pair(( faces.empty() ? -1 : faces[0]), iL );
facesOfLink[ 1 + faces.empty() ].push_back( faceOfLink );
}
}
f2l = facesOfLink.begin();
if ( f2l->first.empty() )
return;
curFace = f2l->first[0];
curLink = freeLinks[ f2l->second ];
freeLinks[ f2l->second ] = 0;
for ( int i = 0; faceOfLink.second < 0 && i < 3; ++i )
if ( !facesOfLink[i].empty() )
faceOfLink = facesOfLink[i][0];
if ( faceOfLink.first < 0 ) // all faces used
{
for ( size_t i = 0; i < facesOfLink[2].size() && faceOfLink.first < 1; ++i )
{
curLink = freeLinks[ facesOfLink[2][i].second ];
faceOfLink.first = curLink->FirstNode()->IsLinked( curLink->FirstNode()->_intPoint );
}
usedFaceIDs.clear();
}
curFace = faceOfLink.first;
curLink = freeLinks[ faceOfLink.second ];
freeLinks[ faceOfLink.second ] = 0;
}
usedFaceIDs.insert( curFace );
polygon._links.push_back( *curLink );
@ -2059,6 +2118,17 @@ namespace
if ( polygon._links.size() == 2 )
{
if ( freeLinks.back() == &polygon._links.back() )
{
freeLinks.back() = 0;
--nbFreeLinks;
}
vector< _Face*>& polygs1 = polygon._links.front()._link->_faces;
vector< _Face*>& polygs2 = polygon._links.back()._link->_faces;
_Face* polyg1 = ( polygs1.empty() ? 0 : polygs1[0] );
_Face* polyg2 = ( polygs2.empty() ? 0 : polygs2[0] );
if ( polyg1 ) polygs2.push_back( polyg1 );
if ( polyg2 ) polygs1.push_back( polyg2 );
_polygons.pop_back();
}
else
@ -2131,7 +2201,7 @@ namespace
multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
for ( ; ip != line._intPoints.end(); ++ip )
{
//if ( !ip->_node ) continue;
// if ( !ip->_node ) continue; // intersection at a grid node
lineInd.SetIndexOnLine( ip->_indexOnLine );
for ( int iL = 0; iL < 4; ++iL ) // loop on 4 cells sharing a link
{
@ -2173,14 +2243,16 @@ namespace
if ( hex )
{
intHexInd[ nbIntHex++ ] = i;
if ( hex->_nbIntNodes > 0 ) continue; // treat intersected hex later
if ( hex->_nbIntNodes > 0 || ! hex->_edgeIntPnts.empty())
continue; // treat intersected hex later
this->init( hex->_i, hex->_j, hex->_k );
}
else
{
this->init( i );
}
if ( _nbCornerNodes == 8 && ( _nbBndNodes < _nbCornerNodes || !isInHole() ))
if (( _nbCornerNodes == 8 ) &&
( _nbBndNodes < _nbCornerNodes || !isInHole() ))
{
// order of _hexNodes is defined by enum SMESH_Block::TShapeID
SMDS_MeshElement* el =
@ -2557,24 +2629,123 @@ namespace
{
chn.clear();
chn.push_back( n1 );
bool found = false;
for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
if ( !quad._edgeNodes[ iP ]._isUsedInFace &&
n1->IsLinked( quad._edgeNodes[ iP ]._intPoint ) &&
n2->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
{
chn.push_back( & quad._edgeNodes[ iP ]);
chn.push_back( n2 );
quad._edgeNodes[ iP ]._isUsedInFace = true;
return true;
}
bool found;
do
{
found = false;
for ( size_t iP = 0; iP < quad._edgeNodes.size(); ++iP )
if (( std::find( ++chn.begin(), chn.end(), & quad._edgeNodes[iP]) == chn.end()) &&
chn.back()->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
if ( !quad._edgeNodes[ iP ]._isUsedInFace &&
chn.back()->IsLinked( quad._edgeNodes[ iP ]._intPoint ))
{
chn.push_back( & quad._edgeNodes[ iP ]);
found = true;
found = quad._edgeNodes[ iP ]._isUsedInFace = true;
break;
}
} while ( found && chn.back() != n2 );
} while ( found && ! chn.back()->IsLinked( n2->_intPoint ) );
if ( chn.back() != n2 )
if ( chn.back() != n2 && chn.back()->IsLinked( n2->_intPoint ))
chn.push_back( n2 );
return chn.size() > 2;
return chn.size() > 1;
}
//================================================================================
/*!
* \brief Try to heal a polygon whose ends are not connected
*/
bool Hexahedron::closePolygon( _Face* polygon, vector<_Node*>& chainNodes ) const
{
int i = -1, nbLinks = polygon->_links.size();
if ( nbLinks < 3 )
return false;
vector< _OrientedLink > newLinks;
// find a node lying on the same FACE as the last one
_Node* node = polygon->_links.back().LastNode();
int avoidFace = node->IsLinked( polygon->_links.back().FirstNode()->_intPoint );
for ( i = nbLinks - 2; i >= 0; --i )
if ( node->IsLinked( polygon->_links[i].FirstNode()->_intPoint, avoidFace ))
break;
if ( i >= 0 )
{
for ( ; i < nbLinks; ++i )
newLinks.push_back( polygon->_links[i] );
}
else
{
// find a node lying on the same FACE as the first one
node = polygon->_links[0].FirstNode();
avoidFace = node->IsLinked( polygon->_links[0].LastNode()->_intPoint );
for ( i = 1; i < nbLinks; ++i )
if ( node->IsLinked( polygon->_links[i].LastNode()->_intPoint, avoidFace ))
break;
if ( i < nbLinks )
for ( nbLinks = i + 1, i = 0; i < nbLinks; ++i )
newLinks.push_back( polygon->_links[i] );
}
if ( newLinks.size() > 1 )
{
polygon->_links.swap( newLinks );
chainNodes.clear();
chainNodes.push_back( polygon->_links.back().LastNode() );
chainNodes.push_back( polygon->_links[0].FirstNode() );
return true;
}
return false;
}
//================================================================================
/*!
* \brief Checks transition at the 1st node of a link
*/
bool Hexahedron::is1stNodeOut( int iLink ) const
{
if ( !_hexLinks[ iLink ]._nodes[0]->Node() ) // no node
return true;
if ( !_hexLinks[ iLink ]._nodes[0]->_intPoint ) // no intersection with geometry
return false;
switch ( _hexLinks[ iLink ]._nodes[0]->FaceIntPnt()->_transition ) {
case Trans_OUT: return true;
case Trans_IN : return false;
default: ; // tangent transition
}
// ijk of a GridLine corresponding to the link
int iDir = iLink / 4;
int indSub = iLink % 4;
LineIndexer li = _grid->GetLineIndexer( iDir );
li.SetIJK( _i,_j,_k );
size_t lineIndex[4] = { li.LineIndex (),
li.LineIndex10(),
li.LineIndex01(),
li.LineIndex11() };
GridLine& line = _grid->_lines[ iDir ][ lineIndex[ indSub ]];
// analyze transition of previous ip
bool isOut = true;
multiset< F_IntersectPoint >::const_iterator ip = line._intPoints.begin();
for ( ; ip != line._intPoints.end(); ++ip )
{
if ( &(*ip) == _hexLinks[ iLink ]._nodes[0]->_intPoint )
break;
switch ( ip->_transition ) {
case Trans_OUT: isOut = true;
case Trans_IN : isOut = false;
default:;
}
}
#ifdef _DEBUG_
if ( ip == line._intPoints.end() )
cout << "BUG: Wrong GridLine. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl;
#endif
return isOut;
}
//================================================================================
/*!
@ -2728,7 +2899,9 @@ namespace
// find a top node above the base node
_Link* link = _polygons[0]._links[iL]._link;
ASSERT( link->_faces.size() > 1 );
//ASSERT( link->_faces.size() > 1 );
if ( link->_faces.size() < 2 )
return debugDumpLink( link );
// a quadrangle sharing <link> with _polygons[0]
_Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
for ( int i = 0; i < 4; ++i )
@ -2757,7 +2930,9 @@ namespace
nodes[2] = _polygons[0]._links[2].FirstNode();
_Link* link = _polygons[0]._links[0]._link;
ASSERT( link->_faces.size() > 1 );
//ASSERT( link->_faces.size() > 1 );
if ( link->_faces.size() < 2 )
return debugDumpLink( link );
// a triangle sharing <link> with _polygons[0]
_Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[0] )];
@ -2795,7 +2970,9 @@ namespace
// find a top node above the base node
_Link* link = _polygons[ iTri ]._links[iL]._link;
ASSERT( link->_faces.size() > 1 );
//ASSERT( link->_faces.size() > 1 );
if ( link->_faces.size() < 2 )
return debugDumpLink( link );
// a quadrangle sharing <link> with a base triangle
_Face* quad = link->_faces[ bool( link->_faces[0] == & _polygons[ iTri ] )];
if ( quad->_links.size() != 4 ) return false;
@ -2835,6 +3012,8 @@ namespace
_Link* link = _polygons[iQuad]._links[0]._link;
ASSERT( link->_faces.size() > 1 );
if ( link->_faces.size() < 2 )
return debugDumpLink( link );
// a triangle sharing <link> with a base quadrangle
_Face* tria = link->_faces[ bool( link->_faces[0] == & _polygons[ iQuad ] )];
@ -2849,6 +3028,20 @@ namespace
return false;
}
//================================================================================
/*!
* \brief Dump a link and return \c false
*/
bool Hexahedron::debugDumpLink( Hexahedron::_Link* link )
{
#ifdef _DEBUG_
gp_Pnt p1 = link->_nodes[0]->Point(), p2 = link->_nodes[1]->Point();
cout << "BUG: not shared link. IKJ = ( "<< _i << " " << _j << " " << _k << " )" << endl
<< "n1 (" << p1.X() << ", "<< p1.Y() << ", "<< p1.Z() << " )" << endl
<< "n2 (" << p2.X() << ", "<< p2.Y() << ", "<< p2.Z() << " )" << endl;
#endif
return false;
}
//================================================================================
/*!
@ -2964,6 +3157,8 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
_computeCanceled = false;
SMESH_MesherHelper helper( theMesh );
try
{
Grid grid;
@ -2992,12 +3187,16 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
shapeBox.Add( facesItersectors[i].GetFaceBndBox() );
if ( _hyp->GetToAddEdges() )
{
helper.SetSubShape( faceVec[i] );
for ( eExp.Init( faceVec[i], TopAbs_EDGE ); eExp.More(); eExp.Next() )
{
const TopoDS_Edge& edge = TopoDS::Edge( eExp.Current() );
if ( !SMESH_Algo::isDegenerated( edge ))
if ( !SMESH_Algo::isDegenerated( edge ) &&
!helper.IsRealSeam( edge ))
edge2faceIDsMap[ grid._shapes.Add( edge )].push_back( facesItersectors[i]._faceID );
}
}
}
getExactBndBox( faceVec, _hyp->GetAxisDirs(), shapeBox );
@ -3037,7 +3236,6 @@ bool StdMeshers_Cartesian_3D::Compute(SMESH_Mesh & theMesh,
for ( size_t i = 0; i < facesItersectors.size(); ++i )
facesItersectors[i].StoreIntersections();
SMESH_MesherHelper helper( theMesh );
TopExp_Explorer solidExp (theShape, TopAbs_SOLID);
helper.SetSubShape( solidExp.Current() );
helper.SetElementsOnShape( true );