import salome
salome.salome_init()
-import GEOM
from salome.geom import geomBuilder
geompy = geomBuilder.New()
-
-import SMESH, SALOMEDS
from salome.smesh import smeshBuilder
smesh = smeshBuilder.New()
Compound2 = smesh.Concatenate([Mesh_inf, Mesh_sup], 1, 0, 1e-05, True,
name='Compound with UniteGrps and GrpsOfAllElems')
+# copy Gsup1 into a separate mesh and translate it
+groupMesh = Mesh_inf.TranslateObjectMakeMesh( Gsup1, [300,0,0] )
+
+# add Ginf2 to groupMesh
+smesh.Concatenate([Ginf2], False, meshToAppendTo = groupMesh )
+
+
if salome.sg.hasDesktop():
salome.sg.updateObjBrowser()
Building Compound Meshes
************************
-Compound Mesh is a combination of several meshes. All elements and groups present in input meshes are present in the compound mesh. However, it does not use geometry or hypotheses of the initial meshes.
+Compound Mesh is a combination of several mesh objects (meshes, groups, submeshes). All elements and groups present in input meshes are present in the compound mesh. However, it does not use geometry or hypotheses of the initial mesh objects.
The links between the input meshes and the compound mesh are not supported, consequently the modification of an input mesh does not lead to the update of the compound mesh.
+There are two modes of building a compound:
+
+* joining selected mesh objects into a new mesh.
+* appending selected mesh objects to an existing mesh.
+
*To Build a compound mesh:*
.. |img| image:: ../images/image161.png
.. image:: ../images/buildcompound.png
:align: center
-* **Name** - allows selecting the name of the resulting **Compound** mesh.
-* **Meshes, sub-meshes, groups** - allows selecting the meshes, sub-meshes and groups to be concatenated. They can be chosen in the Object Browser while holding **Ctrl** button.
-* **Processing identical groups** - allows selecting the method of processing the namesake groups existing in the input meshes. They can be either
+* **Result** group allows selecting a mode of operation
+
+ * Activating **Create new mesh named** enables typing the name of the resulting compound mesh.
+ * Activating **Append to mesh** enables selection of a mesh to append other selected objects to.
+
+* **Meshes, sub-meshes, groups** allows selecting the meshes, sub-meshes and groups to be concatenated. They can be chosen in the Object Browser while holding *Ctrl* button.
+* **Processing identical groups** allows selecting the method of processing the namesake groups existing in the input meshes. They can be either
* **United** - all elements of *Group1* of *Mesh_1* and *Group1* of *Mesh_2* become the elements of *Group1* of the *Compound_Mesh*, or
* **Renamed** - *Group1* of *Mesh_1* becomes *Group1_1* and *Group1* of *Mesh_2* becomes *Group1_2*.
void SetMesh( in SMESH_Mesh theMesh );
long_array GetElementsId( in SMESH_Mesh theMesh );
+ long_array GetElementsIdFromParts( in ListOfIDSources theParts );
ElementType GetElementType();
Predicate GetPredicate();
raises ( SALOME::SALOME_Exception );
/*!
- * Concatenate the given meshes or groups into one mesh.
+ * Concatenate the given meshes or groups into one mesh,
+ * optionally to theMeshToAppendTo.
* Union groups with the same name and type if
* theUniteIdenticalGroups flag is true.
* Merge coincident nodes and elements if
SMESH_Mesh Concatenate(in ListOfIDSources theMeshesArray,
in boolean theUniteIdenticalGroups,
in boolean theMergeNodesAndElements,
- in double theMergeTolerance)
+ in double theMergeTolerance,
+ in SMESH_Mesh theMeshToAppendTo)
raises ( SALOME::SALOME_Exception );
/*!
- * Concatenate the given meshes into one mesh.
+ * Concatenate the given meshes into one mesh,
+ * optionally to theMeshToAppendTo.
* Union groups with the same name and type if
* theUniteIdenticalGroups flag is true.
* Merge coincident nodes and elements if
SMESH_Mesh ConcatenateWithGroups(in ListOfIDSources theMeshesArray,
in boolean theUniteIdenticalGroups,
in boolean theMergeNodesAndElements,
- in double theMergeTolerance)
+ in double theMergeTolerance,
+ in SMESH_Mesh theMeshToAppendTo)
raises ( SALOME::SALOME_Exception );
/*!
* For given node returns list of IDs of inverse elements
* If there is not node for given ID - returns empty list
*/
- long_array GetNodeInverseElements(in long id);
+ long_array GetNodeInverseElements(in long id, in ElementType elemType);
/*!
* \brief Return position of a node on shape
long ProjectPoint(in double x,
in double y,
in double z,
- in SMESH_IDSource meshObject,
in ElementType type,
+ in SMESH_IDSource meshObject,
out double_array projecton)
raises (SALOME::SALOME_Exception);
boolean IsCoherentOrientation2D()
raises (SALOME::SALOME_Exception);
+ /*!
+ * Partition given 1D elements into groups of contiguous edges.
+ * A node where number of meeting edges != 2 is a group end.
+ * An optional startNode is used to orient groups it belongs to.
+ * \return a list of edge groups and a list of corresponding node groups.
+ * If a group is closed, the first and last nodes of the group are same.
+ */
+ array_of_long_array Get1DBranches( in SMESH_IDSource edges,
+ in long startNode,
+ out array_of_long_array nodeGroups)
+ raises (SALOME::SALOME_Exception);
+
/*!
* Return sharp edges of faces and non-manifold ones.
* Optionally add existing edges. Angle is in degrees.
void MakePolyLine(inout ListOfPolySegments segments,
in string groupName)
raises (SALOME::SALOME_Exception);
+
+ /*!
+ * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+ * The slot is consrtucted by cutting faces by cylindrical surfaces made
+ * around each segment. Segments are expected to be created by MakePolyLine().
+ * \return Edges located at the slot boundary
+ */
+ ListOfEdges MakeSlot( in SMESH_GroupBase segments,
+ in double width )
+ raises (SALOME::SALOME_Exception);
+
};
};
<parameter name="display_mode" value="1" />
<parameter name="fitall_on_displayonly" value="1" />
<parameter name="auto_groups" value="false"/>
+ <parameter name="med_ztolerance" value="0.0"/>
<parameter name="show_warning" value="true"/>
<parameter name="show_result_notification" value="2"/>
<parameter name="mesh_elem_info" value="1"/>
//================================================================================
/*
Class : Deflection2D
- Description : Functor for calculating number of faces conneted to the edge
+ Description : computes distance between a face center and an underlying surface
*/
//================================================================================
myPredicate = thePredicate;
}
-void Filter::GetElementsId( const SMDS_Mesh* theMesh,
- PredicatePtr thePredicate,
- TIdSequence& theSequence )
+void Filter::GetElementsId( const SMDS_Mesh* theMesh,
+ PredicatePtr thePredicate,
+ TIdSequence& theSequence,
+ SMDS_ElemIteratorPtr theElements )
{
theSequence.clear();
thePredicate->SetMesh( theMesh );
- SMDS_ElemIteratorPtr elemIt = theMesh->elementsIterator( thePredicate->GetType() );
- if ( elemIt ) {
- while ( elemIt->more() ) {
- const SMDS_MeshElement* anElem = elemIt->next();
- long anId = anElem->GetID();
- if ( thePredicate->IsSatisfy( anId ) )
- theSequence.push_back( anId );
+ if ( !theElements )
+ theElements = theMesh->elementsIterator( thePredicate->GetType() );
+
+ if ( theElements ) {
+ while ( theElements->more() ) {
+ const SMDS_MeshElement* anElem = theElements->next();
+ if ( thePredicate->GetType() == SMDSAbs_All ||
+ thePredicate->GetType() == anElem->GetType() )
+ {
+ long anId = anElem->GetID();
+ if ( thePredicate->IsSatisfy( anId ) )
+ theSequence.push_back( anId );
+ }
}
}
}
void Filter::GetElementsId( const SMDS_Mesh* theMesh,
- Filter::TIdSequence& theSequence )
+ Filter::TIdSequence& theSequence,
+ SMDS_ElemIteratorPtr theElements )
{
- GetElementsId(theMesh,myPredicate,theSequence);
+ GetElementsId(theMesh,myPredicate,theSequence,theElements);
}
/*
void ElementsOnSurface::SetTolerance( const double theToler )
{
if ( myToler != theToler )
- myIds.Clear();
- myToler = theToler;
+ {
+ myToler = theToler;
+ process();
+ }
}
double ElementsOnSurface::GetTolerance() const
virtual
void
- GetElementsId( const SMDS_Mesh* theMesh,
- TIdSequence& theSequence );
+ GetElementsId( const SMDS_Mesh* theMesh,
+ TIdSequence& theSequence,
+ SMDS_ElemIteratorPtr theElements=0);
static
void
- GetElementsId( const SMDS_Mesh* theMesh,
- PredicatePtr thePredicate,
- TIdSequence& theSequence );
+ GetElementsId( const SMDS_Mesh* theMesh,
+ PredicatePtr thePredicate,
+ TIdSequence& theSequence,
+ SMDS_ElemIteratorPtr theElements=0 );
protected:
PredicatePtr myPredicate;
int SMDS_MeshCell::GetNodeIndex( const SMDS_MeshNode* node ) const
{
+ if ( !node || node->IsNull() )
+ return -1;
+
if ( GetVtkType() == VTK_POLYHEDRON )
return static_cast< const SMDS_MeshVolume* >( this )->SMDS_MeshVolume::GetNodeIndex( node );
myName = theName;
myGroupDS->SetStoreName( theName );
}
+
+//================================================================================
+/*!
+ * \brief Return group ID. It is negative if no SMESHDS_GroupBase exist
+ */
+//================================================================================
+
+int SMESH_Group::GetID() const
+{
+ return myGroupDS ? myGroupDS->GetID() : -1;
+}
SMESHDS_GroupBase * GetGroupDS () { return myGroupDS; }
+ int GetID() const;
+
private:
SMESH_Group (const SMESH_Group& theOther);
// prohibited copy constructor
// Reading groups (sub-meshes are out of scope of MED import functionality)
std::list<TNameAndType> aGroupNames = myReader.GetGroupNamesAndTypes();
- int anId;
std::list<TNameAndType>::iterator name_type = aGroupNames.begin();
for ( ; name_type != aGroupNames.end(); name_type++ )
{
- SMESH_Group* aGroup = AddGroup( name_type->second, name_type->first.c_str(), anId );
+ SMESH_Group* aGroup = AddGroup( name_type->second, name_type->first.c_str() );
if ( aGroup ) {
SMESHDS_Group* aGroupDS = dynamic_cast<SMESHDS_Group*>( aGroup->GetGroupDS() );
if ( aGroupDS ) {
SMESH_Group* SMESH_Mesh::AddGroup (const SMDSAbs_ElementType theType,
const char* theName,
- int& theId,
+ const int theId,
const TopoDS_Shape& theShape,
const SMESH_PredicatePtr& thePredicate)
{
- if (_mapGroup.count(_groupId))
+ if ( _mapGroup.count( theId ))
return NULL;
- theId = _groupId;
- SMESH_Group* aGroup = new SMESH_Group (theId, this, theType, theName, theShape, thePredicate);
+ int id = ( theId < 0 ) ? _groupId : theId;
+ SMESH_Group* aGroup = new SMESH_Group ( id, this, theType, theName, theShape, thePredicate );
GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
- _mapGroup[_groupId++] = aGroup;
+ _mapGroup[ id ] = aGroup;
+ while ( _mapGroup.count( _groupId ))
+ ++_groupId;
return aGroup;
}
_mapGroup[ groupDS->GetID() ] = aGroup;
GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
- _groupId = 1 + _mapGroup.rbegin()->first;
+ while ( _mapGroup.count( _groupId ))
+ ++_groupId;
return aGroup;
}
if ( !_mapGroup.count( _groupId ))
_mapGroup[_groupId] = new SMESH_Group( groupDS );
}
- if ( !_mapGroup.empty() )
- _groupId = _mapGroup.rbegin()->first + 1;
+ while ( _mapGroup.count( _groupId ))
+ ++_groupId;
return nbGroups < _mapGroup.size();
}
*/
//=============================================================================
-SMESH_Group* SMESH_Mesh::GetGroup (const int theGroupID)
+SMESH_Group* SMESH_Mesh::GetGroup (const int theGroupID) const
{
- if (_mapGroup.find(theGroupID) == _mapGroup.end())
+ std::map <int, SMESH_Group*>::const_iterator id_grp = _mapGroup.find( theGroupID );
+ if ( id_grp == _mapGroup.end() )
return NULL;
- return _mapGroup[theGroupID];
+ return id_grp->second;
}
SMESH_Group* AddGroup (const SMDSAbs_ElementType theType,
const char* theName,
- int& theId,
- const TopoDS_Shape& theShape=TopoDS_Shape(),
- const SMESH_PredicatePtr& thePredicate=SMESH_PredicatePtr());
+ const int theId = -1,
+ const TopoDS_Shape& theShape = TopoDS_Shape(),
+ const SMESH_PredicatePtr& thePredicate = SMESH_PredicatePtr());
SMESH_Group* AddGroup (SMESHDS_GroupBase* groupDS) throw(SALOME_Exception);
std::list<int> GetGroupIds() const;
- SMESH_Group* GetGroup (const int theGroupID);
+ SMESH_Group* GetGroup (const int theGroupID) const;
bool RemoveGroup (const int theGroupID);
#include <Standard_Failure.hxx>
#include <Standard_ErrorHandler.hxx>
-#include <OSD_Parallel.hxx>
#include "SMESH_TryCatch.hxx" // include after OCCT headers!
if ( theElements.empty() ) eIt = meshDS->elementsIterator( SMDSAbs_Face );
else eIt = SMESHUtils::elemSetIterator( theElements );
- SMESH_MeshAlgos::TEPairVec new2OldFaces;
- SMESH_MeshAlgos::TNPairVec new2OldNodes;
+ SMESH_MeshAlgos::TElemIntPairVec new2OldFaces;
+ SMESH_MeshAlgos::TNodeIntPairVec new2OldNodes;
std::unique_ptr< SMDS_Mesh > offsetMesh
( SMESH_MeshAlgos::MakeOffset( eIt, *meshDS, theValue,
theFixSelfIntersection,
const SMDS_MeshNode* n2 =
tgtMeshDS->AddNodeWithID( n->X(), n->Y(), n->Z(), idShift + n->GetID() );
myLastCreatedNodes.push_back( n2 );
- srcNodes.push_back( new2OldNodes[ i ].second );
+ srcNodes.push_back( meshDS->FindNode( new2OldNodes[ i ].second ));
}
}
elemType.myNodes.push_back( tgtMeshDS->FindNode( idShift + n2->GetID() ));
}
tgtEditor.AddElement( elemType.myNodes, elemType );
- srcElems.push_back( new2OldFaces[ i ].second );
+ srcElems.push_back( meshDS->FindElement( new2OldFaces[ i ].second ));
}
myLastCreatedElems.swap( tgtEditor.myLastCreatedElems );
{
const SMDS_MeshElement* elem = (*insertMapIt).first;
list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
+ if ( nodeList.size() < 3 ) continue;
const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
//MESSAGE(".. Creation of elements: simple junction");
if (createJointElems)
{
- int idg;
string joints2DName = "joints2D";
- mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str(), idg);
+ mapOfJunctionGroups[joints2DName] = this->myMesh->AddGroup(SMDSAbs_Face, joints2DName.c_str());
SMESHDS_Group *joints2DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints2DName]->GetGroupDS());
string joints3DName = "joints3D";
- mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str(), idg);
+ mapOfJunctionGroups[joints3DName] = this->myMesh->AddGroup(SMDSAbs_Volume, joints3DName.c_str());
SMESHDS_Group *joints3DGrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[joints3DName]->GetGroupDS());
itface = faceDomains.begin();
grpname << dom2 << "_" << dom1;
string namegrp = grpname.str();
if (!mapOfJunctionGroups.count(namegrp))
- mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str(), idg);
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(vol->GetType(), namegrp.c_str());
SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
if (sgrp)
sgrp->Add(vol->GetID());
stringstream grpname;
grpname << "m2j_";
grpname << 0 << "_" << 0;
- int idg;
string namegrp = grpname.str();
if (!mapOfJunctionGroups.count(namegrp))
- mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str(), idg);
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Face, namegrp.c_str());
SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
if (sgrp)
sgrp->Add(face->GetID());
orderedNodes.push_back( nodeDomains[ nodes[ ino ]][ orderDom[ idom ]]);
SMDS_MeshVolume* vol = this->GetMeshDS()->AddVolumeFromVtkIds(orderedNodes);
- int idg;
string namegrp = "jointsMultiples";
if (!mapOfJunctionGroups.count(namegrp))
- mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str(), idg);
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str());
SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
if (sgrp)
sgrp->Add(vol->GetID());
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);
+ mapOfJunctionGroups[namegrp] = this->myMesh->AddGroup(SMDSAbs_Volume, namegrp.c_str());
SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(mapOfJunctionGroups[namegrp]->GetGroupDS());
if (sgrp)
sgrp->Add(vol->GetID());
// --- define groups to build
- int idg; // --- group of SMDS volumes
+ // --- group of SMDS volumes
string grpvName = groupName;
grpvName += "_vol";
- SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str(), idg);
+ SMESH_Group *grp = this->myMesh->AddGroup(SMDSAbs_Volume, grpvName.c_str());
if (!grp)
{
MESSAGE("group not created " << grpvName);
}
SMESHDS_Group *sgrp = dynamic_cast<SMESHDS_Group*>(grp->GetGroupDS());
- int idgs; // --- group of SMDS faces on the skin
+ // --- group of SMDS faces on the skin
string grpsName = groupName;
grpsName += "_skin";
- SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str(), idgs);
+ SMESH_Group *grps = this->myMesh->AddGroup(SMDSAbs_Face, grpsName.c_str());
if (!grps)
{
MESSAGE("group not created " << grpsName);
}
SMESHDS_Group *sgrps = dynamic_cast<SMESHDS_Group*>(grps->GetGroupDS());
- int idgi; // --- group of SMDS faces internal (several shapes)
+ // --- group of SMDS faces internal (several shapes)
string grpiName = groupName;
grpiName += "_internalFaces";
- SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str(), idgi);
+ SMESH_Group *grpi = this->myMesh->AddGroup(SMDSAbs_Face, grpiName.c_str());
if (!grpi)
{
MESSAGE("group not created " << grpiName);
}
SMESHDS_Group *sgrpi = dynamic_cast<SMESHDS_Group*>(grpi->GetGroupDS());
- int idgei; // --- group of SMDS faces internal (several shapes)
+ // --- group of SMDS faces internal (several shapes)
string grpeiName = groupName;
grpeiName += "_internalEdges";
- SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str(), idgei);
+ SMESH_Group *grpei = this->myMesh->AddGroup(SMDSAbs_Edge, grpeiName.c_str());
if (!grpei)
{
MESSAGE("group not created " << grpeiName);
default:;
}
}
-
-namespace // utils for MakePolyLine
-{
- //================================================================================
- /*!
- * \brief Sequence of found points and a current point data
- */
- struct Path
- {
- std::vector< gp_XYZ > myPoints;
- double myLength;
-
- const SMDS_MeshElement* myFace;
- SMESH_NodeXYZ myNode1; // nodes of the edge the path entered myFace
- SMESH_NodeXYZ myNode2;
- int myNodeInd1;
- int myNodeInd2;
- double myDot1;
- double myDot2;
-
- int mySrcPntInd; //!< start point index
- TIDSortedElemSet myElemSet, myAvoidSet;
-
- Path(): myLength(0.0), myFace(0) {}
-
- bool SetCutAtCorner( const SMESH_NodeXYZ& cornerNode,
- const SMDS_MeshElement* face,
- const gp_XYZ& plnNorm,
- const gp_XYZ& plnOrig );
-
- void AddPoint( const gp_XYZ& p );
-
- bool Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig );
-
- bool ReachSamePoint( const Path& other );
-
- static void Remove( std::vector< Path > & paths, size_t& i );
- };
-
- //================================================================================
- /*!
- * \brief Return true if this Path meats another
- */
- //================================================================================
-
- bool Path::ReachSamePoint( const Path& other )
- {
- return ( mySrcPntInd != other.mySrcPntInd &&
- myFace == other.myFace );
- }
-
- //================================================================================
- /*!
- * \brief Remove a path from a vector
- */
- //================================================================================
-
- void Path::Remove( std::vector< Path > & paths, size_t& i )
- {
- if ( paths.size() > 1 )
- {
- size_t j = paths.size() - 1; // last item to be removed
- if ( i < j )
- {
- paths[ i ].myPoints.swap( paths[ j ].myPoints );
- paths[ i ].myLength = paths[ j ].myLength;
- paths[ i ].mySrcPntInd = paths[ j ].mySrcPntInd;
- paths[ i ].myFace = paths[ j ].myFace;
- paths[ i ].myNode1 = paths[ j ].myNode1;
- paths[ i ].myNode2 = paths[ j ].myNode2;
- paths[ i ].myNodeInd1 = paths[ j ].myNodeInd1;
- paths[ i ].myNodeInd2 = paths[ j ].myNodeInd2;
- paths[ i ].myDot1 = paths[ j ].myDot1;
- paths[ i ].myDot2 = paths[ j ].myDot2;
- }
- }
- paths.pop_back();
- if ( i > 0 )
- --i;
- }
-
- //================================================================================
- /*!
- * \brief Store a point that is at a node of a face if the face is intersected by plane.
- * Return false if the node is a sole intersection point of the face and the plane
- */
- //================================================================================
-
- bool Path::SetCutAtCorner( const SMESH_NodeXYZ& cornerNode,
- const SMDS_MeshElement* face,
- const gp_XYZ& plnNorm,
- const gp_XYZ& plnOrig )
- {
- if ( face == myFace )
- return false;
- myNodeInd1 = face->GetNodeIndex( cornerNode._node );
- myNodeInd2 = ( myNodeInd1 + 1 ) % face->NbCornerNodes();
- int ind3 = ( myNodeInd1 + 2 ) % face->NbCornerNodes();
- myNode1.Set( face->GetNode( ind3 ));
- myNode2.Set( face->GetNode( myNodeInd2 ));
-
- myDot1 = plnNorm * ( myNode1 - plnOrig );
- myDot2 = plnNorm * ( myNode2 - plnOrig );
-
- bool ok = ( myDot1 * myDot2 < 0 );
- if ( !ok && myDot1 * myDot2 == 0 )
- {
- ok = ( myDot1 != myDot2 );
- if ( ok && myFace )
- ok = ( myFace->GetNodeIndex(( myDot1 == 0 ? myNode1 : myNode2 )._node ) < 0 );
- }
- if ( ok )
- {
- myFace = face;
- myDot1 = 0;
- AddPoint( cornerNode );
- }
- return ok;
- }
-
- //================================================================================
- /*!
- * \brief Store a point and update myLength
- */
- //================================================================================
-
- void Path::AddPoint( const gp_XYZ& p )
- {
- if ( !myPoints.empty() )
- myLength += ( p - myPoints.back() ).Modulus();
- else
- myLength = 0;
- myPoints.push_back( p );
- }
-
- //================================================================================
- /*!
- * \brief Try to find the next point
- * \param [in] plnNorm - cutting plane normal
- * \param [in] plnOrig - cutting plane origin
- */
- //================================================================================
-
- bool Path::Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig )
- {
- int nodeInd3 = ( myNodeInd1 + 1 ) % myFace->NbCornerNodes();
- if ( myNodeInd2 == nodeInd3 )
- nodeInd3 = ( myNodeInd1 + 2 ) % myFace->NbCornerNodes();
-
- SMESH_NodeXYZ node3 = myFace->GetNode( nodeInd3 );
- double dot3 = plnNorm * ( node3 - plnOrig );
-
- if ( dot3 * myDot1 < 0. )
- {
- myNode2 = node3;
- myNodeInd2 = nodeInd3;
- myDot2 = dot3;
- }
- else if ( dot3 * myDot2 < 0. )
- {
- myNode1 = node3;
- myNodeInd1 = nodeInd3;
- myDot1 = dot3;
- }
- else if ( dot3 == 0. )
- {
- SMDS_ElemIteratorPtr fIt = node3._node->GetInverseElementIterator(SMDSAbs_Face);
- while ( fIt->more() )
- if ( SetCutAtCorner( node3, fIt->next(), plnNorm, plnOrig ))
- return true;
- return false;
- }
- else if ( myDot2 == 0. )
- {
- SMESH_NodeXYZ node2 = myNode2; // copy as myNode2 changes in SetCutAtCorner()
- SMDS_ElemIteratorPtr fIt = node2._node->GetInverseElementIterator(SMDSAbs_Face);
- while ( fIt->more() )
- if ( SetCutAtCorner( node2, fIt->next(), plnNorm, plnOrig ))
- return true;
- return false;
- }
-
- double r = Abs( myDot1 / ( myDot2 - myDot1 ));
- AddPoint( myNode1 * ( 1 - r ) + myNode2 * r );
-
- myAvoidSet.clear();
- myAvoidSet.insert( myFace );
- myFace = SMESH_MeshAlgos::FindFaceInSet( myNode1._node, myNode2._node,
- myElemSet, myAvoidSet,
- &myNodeInd1, &myNodeInd2 );
- return myFace;
- }
-
- //================================================================================
- /*!
- * \brief Compute a path between two points of PolySegment
- */
- struct PolyPathCompute
- {
- SMESH_MeshEditor::TListOfPolySegments& mySegments; //!< inout PolySegment's
- std::vector< Path >& myPaths; //!< path of each of segments to compute
- SMESH_Mesh* myMesh;
- mutable std::vector< std::string > myErrors;
-
- PolyPathCompute( SMESH_MeshEditor::TListOfPolySegments& theSegments,
- std::vector< Path >& thePaths,
- SMESH_Mesh* theMesh):
- mySegments( theSegments ),
- myPaths( thePaths ),
- myMesh( theMesh ),
- myErrors( theSegments.size() )
- {
- }
-
-#undef SMESH_CAUGHT
-#define SMESH_CAUGHT myErrors[i] =
- void operator() ( const int i ) const
- {
- SMESH_TRY;
- const_cast< PolyPathCompute* >( this )->Compute( i );
- SMESH_CATCH( SMESH::returnError );
- }
-#undef SMESH_CAUGHT
-
- //================================================================================
- /*!
- * \brief Compute a path of a given segment
- */
- //================================================================================
-
- void Compute( const int iSeg )
- {
- SMESH_MeshEditor::PolySegment& polySeg = mySegments[ iSeg ];
-
- // the cutting plane
- gp_XYZ plnNorm = ( polySeg.myXYZ[0] - polySeg.myXYZ[1] ) ^ polySeg.myVector.XYZ();
- gp_XYZ plnOrig = polySeg.myXYZ[1];
-
- // Find paths connecting the 2 end points of polySeg
-
- std::vector< Path > paths; paths.reserve(10);
-
- // 1) initialize paths; two paths starts at each end point
-
- for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points
- {
- Path path;
- path.mySrcPntInd = iP;
- size_t nbPaths = paths.size();
-
- if ( polySeg.myFace[ iP ]) // the end point lies on polySeg.myFace[ iP ]
- {
- // check coincidence of polySeg.myXYZ[ iP ] with nodes
- const double tol = 1e-20;
- SMESH_NodeXYZ nodes[4];
- for ( int i = 0; i < 3 && !polySeg.myNode1[ iP ]; ++i )
- {
- nodes[ i ] = polySeg.myFace[ iP ]->GetNode( i );
- if (( nodes[ i ] - polySeg.myXYZ[ iP ]).SquareModulus() < tol*tol )
- polySeg.myNode1[ iP ] = nodes[ i ].Node();
- }
- nodes[ 3 ] = nodes[ 0 ];
-
- // check coincidence of polySeg.myXYZ[ iP ] with edges
- for ( int i = 0; i < 3 && !polySeg.myNode1[ iP ]; ++i )
- {
- SMDS_LinearEdge edge( nodes[i].Node(), nodes[i+1].Node() );
- if ( SMESH_MeshAlgos::GetDistance( &edge, polySeg.myXYZ[ iP ]) < tol )
- {
- polySeg.myNode1[ iP ] = nodes[ i ].Node();
- polySeg.myNode2[ iP ] = nodes[ i + 1 ].Node();
- }
- }
-
- if ( !polySeg.myNode1[ iP ] ) // polySeg.myXYZ[ iP ] is within polySeg.myFace[ iP ]
- {
- double dot[ 4 ];
- for ( int i = 0; i < 3; ++i )
- dot[ i ] = plnNorm * ( nodes[ i ] - plnOrig );
- dot[ 3 ] = dot[ 0 ];
-
- int iCut = 0; // index of a cut edge
- if ( dot[ 1 ] * dot[ 2 ] < 0. ) iCut = 1;
- else if ( dot[ 2 ] * dot[ 3 ] < 0. ) iCut = 2;
-
- // initialize path so as if it entered the face via iCut-th edge
- path.myFace = polySeg.myFace[ iP ];
- path.myNodeInd1 = iCut;
- path.myNodeInd2 = iCut + 1;
- path.myNode1.Set( nodes[ iCut ].Node() );
- path.myNode2.Set( nodes[ iCut + 1 ].Node() );
- path.myDot1 = dot[ iCut ];
- path.myDot2 = dot[ iCut + 1 ];
- path.myPoints.clear();
- path.AddPoint( polySeg.myXYZ[ iP ]);
- paths.push_back( path );
-
- path.Extend( plnNorm, plnOrig ); // to get another edge cut
- path.myFace = polySeg.myFace[ iP ];
- if ( path.myDot1 == 0. ) // cut at a node
- {
- path.myNodeInd1 = ( iCut + 2 ) % 3;
- path.myNodeInd2 = ( iCut + 3 ) % 3;
- path.myNode2.Set( path.myFace->GetNode( path.myNodeInd2 ));
- path.myDot2 = dot[ path.myNodeInd2 ];
- }
- else
- {
- path.myNodeInd1 = path.myFace->GetNodeIndex( path.myNode1.Node() );
- path.myNodeInd2 = path.myFace->GetNodeIndex( path.myNode2.Node() );
- }
- path.myPoints.clear();
- path.AddPoint( polySeg.myXYZ[ iP ]);
- paths.push_back( path );
- }
- }
-
- if ( polySeg.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] )
- {
- // the end point is on an edge
- while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ],
- polySeg.myNode2[ iP ],
- path.myElemSet,
- path.myAvoidSet,
- &path.myNodeInd1,
- &path.myNodeInd2 )))
- {
- path.myNode1.Set( polySeg.myNode1[ iP ]);
- path.myNode2.Set( polySeg.myNode2[ iP ]);
- path.myDot1 = plnNorm * ( path.myNode1 - plnOrig );
- path.myDot2 = plnNorm * ( path.myNode2 - plnOrig );
- path.myPoints.clear();
- path.AddPoint( polySeg.myXYZ[ iP ]);
- path.myAvoidSet.insert( path.myFace );
- paths.push_back( path );
- }
- if ( nbPaths == paths.size() )
- throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1
- << " in a PolySegment " << iSeg );
- }
- else if ( polySeg.myNode1[ iP ] ) // the end point is at a node
- {
- std::set<const SMDS_MeshNode* > nodes;
- SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face);
- while ( fIt->more() )
- {
- path.myPoints.clear();
- if ( path.SetCutAtCorner( polySeg.myNode1[ iP ], fIt->next(), plnNorm, plnOrig ))
- {
- if (( path.myDot1 * path.myDot2 != 0 ) ||
- ( nodes.insert( path.myDot1 == 0 ? path.myNode1._node : path.myNode2._node ).second ))
- paths.push_back( path );
- }
- }
- }
-
- // look for a one-segment path
- for ( size_t i = 0; i < nbPaths; ++i )
- for ( size_t j = nbPaths; j < paths.size(); ++j )
- if ( paths[i].myFace == paths[j].myFace )
- {
- myPaths[ iSeg ].myPoints.push_back( paths[i].myPoints[0] );
- myPaths[ iSeg ].myPoints.push_back( paths[j].myPoints[0] );
- paths.clear();
- }
- }
-
- // 2) extend paths and compose the shortest one connecting the two points
-
- myPaths[ iSeg ].myLength = 1e100;
-
- while ( paths.size() >= 2 )
- {
- for ( size_t i = 0; i < paths.size(); ++i )
- {
- Path& path = paths[ i ];
- if ( !path.Extend( plnNorm, plnOrig ) || // path reached a mesh boundary
- path.myLength > myPaths[ iSeg ].myLength ) // path is longer than others
- {
- Path::Remove( paths, i );
- continue;
- }
-
- // join paths that reach same point
- for ( size_t j = 0; j < paths.size(); ++j )
- {
- if ( i != j && paths[i].ReachSamePoint( paths[j] ))
- {
- double distLast = ( paths[i].myPoints.back() - paths[j].myPoints.back() ).Modulus();
- double fullLength = ( paths[i].myLength + paths[j].myLength + distLast );
- if ( fullLength < myPaths[ iSeg ].myLength )
- {
- myPaths[ iSeg ].myLength = fullLength;
- std::vector< gp_XYZ > & allPoints = myPaths[ iSeg ].myPoints;
- allPoints.swap( paths[i].myPoints );
- allPoints.insert( allPoints.end(),
- paths[j].myPoints.rbegin(),
- paths[j].myPoints.rend() );
- }
- Path::Remove( paths, i );
- Path::Remove( paths, j );
- }
- }
- }
- if ( !paths.empty() && (int) paths[0].myPoints.size() > myMesh->NbFaces() )
- throw SALOME_Exception(LOCALIZED( "Infinite loop in MakePolyLine()"));
- }
-
- if ( myPaths[ iSeg ].myPoints.empty() )
- throw SALOME_Exception( SMESH_Comment("Can't find a full path for PolySegment #") << iSeg );
-
- // reverse the path
- double d00 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.front() ).SquareModulus();
- double d01 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.back() ).SquareModulus();
- if ( d00 > d01 )
- std::reverse( myPaths[ iSeg ].myPoints.begin(), myPaths[ iSeg ].myPoints.end() );
-
- } // PolyPathCompute::Compute()
-
- }; // struct PolyPathCompute
-
-} // namespace
-
-//=======================================================================
-//function : MakePolyLine
-//purpose : Create a polyline consisting of 1D mesh elements each lying on a 2D element of
-// the initial mesh
-//=======================================================================
-
-void SMESH_MeshEditor::MakePolyLine( TListOfPolySegments& theSegments,
- SMESHDS_Group* theGroup,
- SMESH_ElementSearcher* theSearcher)
-{
- std::vector< Path > segPaths( theSegments.size() ); // path of each of segments
-
- SMESH_ElementSearcher* searcher = theSearcher;
- SMESHUtils::Deleter<SMESH_ElementSearcher> delSearcher;
- if ( !searcher )
- {
- searcher = SMESH_MeshAlgos::GetElementSearcher( *GetMeshDS() );
- delSearcher._obj = searcher;
- }
-
- // get cutting planes
-
- std::vector< bool > isVectorOK( theSegments.size(), true );
- const double planarCoef = 0.333; // plane height in planar case
-
- for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
- {
- PolySegment& polySeg = theSegments[ iSeg ];
-
- gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] );
- gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] );
- if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] ));
- if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] ));
-
- polySeg.myFace[0] = polySeg.myFace[1] = 0;
- if ( !polySeg.myNode1[0] && !polySeg.myNode2[0] )
- {
- p1 = searcher->Project( polySeg.myXYZ[0], SMDSAbs_Face, &polySeg.myFace[0] );
- }
- if ( !polySeg.myNode1[1] && !polySeg.myNode2[1] )
- {
- p2 = searcher->Project( polySeg.myXYZ[1], SMDSAbs_Face, &polySeg.myFace[1] );
- }
- polySeg.myXYZ[0] = p1;
- polySeg.myXYZ[1] = p2;
-
- gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
-
- isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits<double>::min() );
- if ( !isVectorOK[ iSeg ])
- {
- gp_XYZ pMid = 0.5 * ( p1 + p2 );
- const SMDS_MeshElement* face;
- polySeg.myMidProjPoint = searcher->Project( pMid, SMDSAbs_Face, &face );
- polySeg.myVector = polySeg.myMidProjPoint.XYZ() - pMid;
-
- gp_XYZ faceNorm;
- SMESH_MeshAlgos::FaceNormal( face, faceNorm );
-
- if ( polySeg.myVector.Magnitude() < Precision::Confusion() ||
- polySeg.myVector * faceNorm < Precision::Confusion() )
- {
- polySeg.myVector = faceNorm;
- polySeg.myMidProjPoint = pMid + faceNorm * ( p1 - p2 ).Modulus() * planarCoef;
- }
- }
- else
- {
- polySeg.myVector = plnNorm ^ ( p1 - p2 );
- }
- }
-
- // assure that inverse elements are constructed, avoid their concurrent building in threads
- GetMeshDS()->nodesIterator()->next()->NbInverseElements();
-
- // find paths
-
- PolyPathCompute algo( theSegments, segPaths, myMesh );
- OSD_Parallel::For( 0, theSegments.size(), algo, theSegments.size() == 1 );
-
- for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
- if ( !algo.myErrors[ iSeg ].empty() )
- throw SALOME_Exception( algo.myErrors[ iSeg ].c_str() );
-
- // create an 1D mesh
-
- const SMDS_MeshNode *n, *nPrev = 0;
- SMESHDS_Mesh* mesh = GetMeshDS();
-
- for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
- {
- const Path& path = segPaths[iSeg];
- if ( path.myPoints.size() < 2 )
- continue;
-
- double tol = path.myLength / path.myPoints.size() / 1000.;
- if ( !nPrev || ( SMESH_NodeXYZ( nPrev ) - path.myPoints[0] ).SquareModulus() > tol*tol )
- {
- nPrev = mesh->AddNode( path.myPoints[0].X(), path.myPoints[0].Y(), path.myPoints[0].Z() );
- myLastCreatedNodes.push_back( nPrev );
- }
- for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
- {
- n = mesh->AddNode( path.myPoints[iP].X(), path.myPoints[iP].Y(), path.myPoints[iP].Z() );
- myLastCreatedNodes.push_back( n );
-
- const SMDS_MeshElement* elem = mesh->AddEdge( nPrev, n );
- myLastCreatedElems.push_back( elem );
- if ( theGroup )
- theGroup->Add( elem );
-
- nPrev = n;
- }
-
- // return a vector
-
- gp_XYZ pMid = 0.5 * ( path.myPoints[0] + path.myPoints.back() );
- if ( isVectorOK[ iSeg ])
- {
- // find the most distance point of a path
- double maxDist = 0;
- for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
- {
- double dist = Abs( theSegments[iSeg].myVector * ( path.myPoints[iP] - path.myPoints[0] ));
- if ( dist > maxDist )
- {
- maxDist = dist;
- theSegments[iSeg].myMidProjPoint = path.myPoints[iP];
- }
- }
- if ( maxDist < Precision::Confusion() ) // planar case
- theSegments[iSeg].myMidProjPoint =
- pMid + theSegments[iSeg].myVector.XYZ().Normalized() * path.myLength * planarCoef;
- }
- theSegments[iSeg].myVector = gp_Vec( pMid, theSegments[iSeg].myMidProjPoint );
- }
-
- return;
-}
bool toAddExistingBondary = false,
bool aroundElements = false);
-
- // structure used in MakePolyLine() to define a cutting plane
- struct PolySegment
- {
- // 2 points, each defined as follows:
- // ( myNode1 && myNode2 ) ==> point is in the middle of an edge defined by two nodes
- // ( myNode1 && !myNode2 ) ==> point is at myNode1
- // else ==> point is at myXYZ
- const SMDS_MeshNode* myNode1[2];
- const SMDS_MeshNode* myNode2[2];
- gp_XYZ myXYZ [2];
-
- // face on which myXYZ projects (found by MakePolyLine())
- const SMDS_MeshElement* myFace [2];
-
- // vector on the plane; to use a default plane set vector = (0,0,0)
- gp_Vec myVector;
-
- // point to return coordinates of a middle of the two points, projected to mesh
- gp_Pnt myMidProjPoint;
- };
- typedef std::vector<PolySegment> TListOfPolySegments;
-
- /*!
- * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
- * the initial mesh. Positions of new nodes are found by cutting the mesh by the
- * plane passing through pairs of points specified by each PolySegment structure.
- * If there are several paths connecting a pair of points, the shortest path is
- * selected by the module. Position of the cutting plane is defined by the two
- * points and an optional vector lying on the plane specified by a PolySegment.
- * By default the vector is defined by Mesh module as following. A middle point
- * of the two given points is computed. The middle point is projected to the mesh.
- * The vector goes from the middle point to the projection point. In case of planar
- * mesh, the vector is normal to the mesh.
- * \param [inout] segments - PolySegment's defining positions of cutting planes.
- * Return the used vector and position of the middle point.
- * \param [in] group - an optional group where created mesh segments will
- * be added.
- */
- void MakePolyLine( TListOfPolySegments& segments,
- SMESHDS_Group* group=0,
- SMESH_ElementSearcher* searcher=0);
-
private:
/*!
#define SPACING 6
#define MARGIN 11
+enum { NEW_MESH_ID, APPEND_TO_ID };
+
//=================================================================================
// name : SMESHGUI_BuildCompoundDlg
// Purpose :
ButtonGroup->addButton(Constructor1, 0);
/***************************************************************/
- GroupName = new QGroupBox(tr("RESULT_NAME"), this);
- QHBoxLayout* GroupNameLayout = new QHBoxLayout(GroupName);
- GroupNameLayout->setSpacing(SPACING);
- GroupNameLayout->setMargin(MARGIN);
-
- TextLabelName = new QLabel(tr("SMESH_NAME"), GroupName);
- LineEditName = new QLineEdit(GroupName);
-
- GroupNameLayout->addWidget(TextLabelName);
- GroupNameLayout->addWidget(LineEditName);
+ GroupResult = new QGroupBox(tr("RESULT_NAME"), this);
+ QGridLayout* GroupResultLayout = new QGridLayout(GroupResult);
+ GroupResultLayout->setSpacing(SPACING);
+ GroupResultLayout->setMargin(MARGIN);
+
+ QRadioButton* newMeshRadioBtn = new QRadioButton( tr("NEW_MESH_NAME"), GroupResult );
+ QRadioButton* appendToRadioBtn = new QRadioButton( tr("MESH_APPEND_TO"), GroupResult );
+ LineEditNewName = new QLineEdit(GroupResult);
+ LineEditAppendTo = new QLineEdit(GroupResult);
+ SelectButtonAppendTo = new QPushButton(GroupResult);
+ SelectButtonAppendTo->setIcon(image1);
+ SelectButtonAppendTo->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
+ ResultButtonGroup = new QButtonGroup( GroupResult );
+ ResultButtonGroup->addButton( newMeshRadioBtn, NEW_MESH_ID );
+ ResultButtonGroup->addButton( appendToRadioBtn, APPEND_TO_ID );
+ newMeshRadioBtn->setChecked( true );
+
+ GroupResultLayout->addWidget( newMeshRadioBtn, 0, 0, 1, 2 );
+ GroupResultLayout->addWidget( LineEditNewName, 0, 2 );
+ GroupResultLayout->addWidget( appendToRadioBtn, 1, 0 );
+ GroupResultLayout->addWidget( SelectButtonAppendTo, 1, 1 );
+ GroupResultLayout->addWidget( LineEditAppendTo, 1, 2 );
/***************************************************************/
GroupArgs = new QGroupBox(tr("SMESH_ARGUMENTS"), this);
/***************************************************************/
aTopLayout->addWidget(GroupConstructors);
- aTopLayout->addWidget(GroupName);
+ aTopLayout->addWidget(GroupResult);
aTopLayout->addWidget(GroupArgs);
aTopLayout->addWidget(GroupButtons);
{
mySMESHGUI->SetActiveDialogBox((QDialog*)this);
- myMesh = SMESH::SMESH_IDSource::_nil();
+ myMeshToAppendTo = SMESH::SMESH_Mesh::_nil();
+ myMeshArray = new SMESH::ListOfIDSources();
- myMeshFilter = new SMESH_TypeFilter (SMESH::IDSOURCE);
-
- myMeshArray = new SMESH::ListOfIDSources();
+ myMeshFilter = new SMESH_TypeFilter (SMESH::IDSOURCE);
+ myAppendToFilter = new SMESH_TypeFilter (SMESH::MESH);
// signals and slots connections
connect(buttonOk, SIGNAL(clicked()), this, SLOT(ClickOnOk()));
connect(buttonApply, SIGNAL(clicked()), this, SLOT(ClickOnApply()));
connect(buttonHelp, SIGNAL(clicked()), this, SLOT(ClickOnHelp()));
- connect(SelectButton, SIGNAL(clicked()), this, SLOT(SelectionIntoArgument()));
+ connect(ResultButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(onResultTypeChange(int)));
+
+ connect(SelectButtonAppendTo, SIGNAL(clicked()), this, SLOT(onSelectionButton()));
+ connect(SelectButton, SIGNAL(clicked()), this, SLOT(onSelectionButton()));
connect(CheckBoxMerge, SIGNAL(toggled(bool)), this, SLOT(onSelectMerge(bool)));
connect(mySMESHGUI, SIGNAL(SignalDeactivateActiveDialog()), this, SLOT(DeactivateActiveDialog()));
connect(mySMESHGUI, SIGNAL(SignalCloseAllDialogs()), this, SLOT(reject()));
- LineEditName->setText(GetDefaultName(tr("COMPOUND_MESH")));
- LineEditMeshes->setFocus();
+ LineEditNewName->setText(GetDefaultName(tr("COMPOUND_MESH")));
ComboBoxUnion->addItem(tr("UNITE"));
ComboBoxUnion->addItem(tr("RENAME"));
SpinBoxTol->setEnabled(CheckBoxMerge->isChecked());
- mySelectionMgr->clearFilters();
- mySelectionMgr->installFilter(myMeshFilter);
+ onResultTypeChange( ResultButtonGroup->checkedId() );
- SelectionIntoArgument();
+ onSelectionButton();
}
//=================================================================================
SMESH::SMESH_Mesh_var aMesh;
- if (!myMesh->_is_nil())
+ int nbMeshes = myMeshArray->length() + ( !myMeshToAppendTo->_is_nil() );
+
+ if ( nbMeshes > 1 )
{
QStringList aParameters;
aParameters << (CheckBoxMerge->isChecked() ? SpinBoxTol->text() : QString(" "));
aMesh = aSMESHGen->ConcatenateWithGroups(myMeshArray,
!(ComboBoxUnion->currentIndex()),
CheckBoxMerge->isChecked(),
- SpinBoxTol->GetValue());
+ SpinBoxTol->GetValue(),
+ myMeshToAppendTo);
else
aMesh = aSMESHGen->Concatenate(myMeshArray,
!(ComboBoxUnion->currentIndex()),
CheckBoxMerge->isChecked(),
- SpinBoxTol->GetValue());
+ SpinBoxTol->GetValue(),
+ myMeshToAppendTo);
_PTR(SObject) aSO = SMESH::FindSObject( aMesh );
if( aSO ) {
- SMESH::SetName( aSO, LineEditName->text() );
+ if ( myMeshToAppendTo->_is_nil() )
+ SMESH::SetName( aSO, LineEditNewName->text() );
anEntryList.append( aSO->GetID().c_str() );
}
mySMESHGUI->updateObjBrowser();
return false;
}
- LineEditName->setText(GetDefaultName(tr("COMPOUND_MESH")));
+ LineEditNewName->setText(GetDefaultName(tr("COMPOUND_MESH")));
// IPAL21468 Compound is hidden after creation.
if ( SMESHGUI::automaticUpdate() ) {
return;
QString aString = "";
-
SALOME_ListIO aList;
+
mySelectionMgr->selectedObjects(aList);
int nbSel = SMESH::GetNameOfSelectedIObjects(mySelectionMgr, aString);
- if (nbSel != 0) {
- myMeshArray->length(nbSel);
- for (int i = 0; nbSel != 0; i++, nbSel--) {
- Handle(SALOME_InteractiveObject) IO = aList.First();
+ bool toAppend = ( CurrentLineEdit == LineEditAppendTo );
+ bool isOk = toAppend ? ( nbSel == 1 ) : ( nbSel > 0 );
+ if ( !isOk )
+ aString = "";
+
+ if ( toAppend )
+ {
+ myMeshToAppendTo = SMESH::SMESH_Mesh::_nil();
+ if ( isOk )
+ myMeshToAppendTo = SMESH::IObjectToInterface<SMESH::SMESH_Mesh>( aList.First() );
+ }
+ else
+ {
+ myMeshArray->length( nbSel );
+ for ( int i = 0; !aList.IsEmpty(); i++ ) {
+ myMeshArray[i] = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(aList.First());
aList.RemoveFirst();
- myMesh = SMESH::IObjectToInterface<SMESH::SMESH_IDSource>(IO);
- myMeshArray[i] = myMesh;
}
}
- else {
- myMesh = SMESH::SMESH_IDSource::_nil();
- aString = "";
- }
-
- LineEditMeshes->setText(aString);
-
- bool isEnabled = (!myMesh->_is_nil());
- buttonOk->setEnabled(isEnabled);
- buttonApply->setEnabled(isEnabled);
+ CurrentLineEdit->setText(aString);
+
+ bool isEnabled;
+ if ( ResultButtonGroup->checkedId() == NEW_MESH_ID )
+ isEnabled = ( myMeshArray->length() > 1 );
+ else
+ isEnabled = ( myMeshArray->length() > 0 &&
+ !myMeshToAppendTo->_is_nil() &&
+ LineEditAppendTo->text() != LineEditMeshes->text() );
+ buttonOk ->setEnabled( isEnabled );
+ buttonApply->setEnabled( isEnabled );
}
//=================================================================================
{
if (GroupConstructors->isEnabled()) {
GroupConstructors->setEnabled(false);
- GroupName->setEnabled(false);
+ GroupResult->setEnabled(false);
GroupArgs->setEnabled(false);
GroupButtons->setEnabled(false);
mySMESHGUI->ResetState();
/* Emit a signal to deactivate the active dialog */
mySMESHGUI->EmitSignalDeactivateDialog();
GroupConstructors->setEnabled(true);
- GroupName->setEnabled(true);
+ GroupResult->setEnabled(true);
GroupArgs->setEnabled(true);
GroupButtons->setEnabled(true);
SpinBoxTol->SetValue(1e-05);
}
+//=======================================================================
+//function : onResultTypeChange
+//purpose :
+//=======================================================================
+
+void SMESHGUI_BuildCompoundDlg::onResultTypeChange( int buttonID )
+{
+ LineEditNewName ->setEnabled( buttonID == NEW_MESH_ID );
+ SelectButtonAppendTo->setEnabled( buttonID == APPEND_TO_ID );
+ LineEditAppendTo ->setEnabled( buttonID == APPEND_TO_ID );
+
+ if ( CurrentLineEdit == LineEditAppendTo && buttonID == NEW_MESH_ID )
+ onSelectionButton(); // to select into myMeshArray
+
+ if ( buttonID == NEW_MESH_ID )
+ {
+ myMeshToAppendTo = SMESH::SMESH_Mesh::_nil();
+ LineEditAppendTo->setText("");
+ }
+ else
+ {
+ // activate selection of myMeshToAppendTo
+ SelectButtonAppendTo->click();
+ LineEditAppendTo->setFocus();
+ }
+}
+
+//=======================================================================
+//function : onSelectionButton
+//purpose :
+//=======================================================================
+
+void SMESHGUI_BuildCompoundDlg::onSelectionButton()
+{
+ mySelectionMgr->clearFilters();
+ if ( sender() == SelectButtonAppendTo )
+ {
+ mySelectionMgr->installFilter( myAppendToFilter );
+ CurrentLineEdit = LineEditAppendTo;
+ }
+ else
+ {
+ mySelectionMgr->installFilter( myMeshFilter );
+ CurrentLineEdit = LineEditMeshes;
+ }
+ CurrentLineEdit->setFocus();
+
+ SelectionIntoArgument();
+}
+
//=================================================================================
// function : isValid
// purpose :
#include CORBA_SERVER_HEADER(SMESH_Gen)
#include CORBA_SERVER_HEADER(SMESH_Mesh)
+class LightApp_SelectionMgr;
+class QButtonGroup;
+class QCheckBox;
+class QComboBox;
class QGroupBox;
class QLabel;
class QLineEdit;
class QPushButton;
class QRadioButton;
-class QCheckBox;
-class QComboBox;
class SMESHGUI;
class SMESHGUI_SpinBox;
-class LightApp_SelectionMgr;
class SUIT_SelectionFilter;
//=================================================================================
SMESHGUI* mySMESHGUI; /* Current SMESHGUI object */
LightApp_SelectionMgr* mySelectionMgr; /* User shape selection */
- SMESH::SMESH_IDSource_var myMesh;
- SUIT_SelectionFilter* myMeshFilter;
+ SMESH::SMESH_Mesh_var myMeshToAppendTo;
SMESH::ListOfIDSources_var myMeshArray;
+ SUIT_SelectionFilter* myMeshFilter;
+ SUIT_SelectionFilter* myAppendToFilter;
// Widgets
QGroupBox* GroupConstructors;
QPushButton* buttonApply;
QPushButton* buttonHelp;
- QGroupBox* GroupName;
- QLabel* TextLabelName;
- QLineEdit* LineEditName;
+ QGroupBox* GroupResult;
+ QButtonGroup* ResultButtonGroup;
+ QLineEdit* LineEditNewName;
+ QPushButton* SelectButtonAppendTo;
+ QLineEdit* LineEditAppendTo;
QGroupBox* GroupArgs;
QLabel* TextLabelMeshes;
QLabel* TextLabelTol;
SMESHGUI_SpinBox* SpinBoxTol;
+ QLineEdit* CurrentLineEdit;
+
QString myHelpFileName;
bool myIsApplyAndClose;
void DeactivateActiveDialog();
void ActivateThisDialog();
void onSelectMerge( bool );
+ void onResultTypeChange( int );
+ void onSelectionButton();
};
#endif // SMESHGUI_BUILDCOMPOUNDDLG_H
aSOrigin->setChecked( true );
#ifndef MINDIST_ENABLE_ELEMENT
aFElem->setEnabled( false ); // NOT AVAILABLE YET
- aSElem->setEnabled( false ); // NOT AVAILABLE YET
+ //aSElem->setEnabled( false ); // NOT AVAILABLE YET
#endif
#ifndef MINDIST_ENABLE_OBJECT
aFObject->setEnabled( false ); // NOT AVAILABLE YET
- aSObject->setEnabled( false ); // NOT AVAILABLE YET
+ //aSObject->setEnabled( false ); // NOT AVAILABLE YET
#endif
myDX->setReadOnly( true );
myDY->setReadOnly( true );
if ( isOrigin ) {
x2 = y2 = z2 = 0.;
}
- else {
+ else if ( mySecond->checkedId() == NodeTgt ) {
coord = s2->GetMesh()->GetNodeXYZ( result.node2 );
x2 = coord[0]; y2 = coord[1]; z2 = coord[2];
}
+ else
+ {
+ x2 = result.maxX; y2 = result.maxY; z2 = result.maxZ;
+ }
createPreview( x1, y1, z1, x2, y2, z2 );
displayPreview();
}
<source>MESHES</source>
<translation>Meshes, sub-meshes, groups</translation>
</message>
+ <message>
+ <source>NEW_MESH_NAME</source>
+ <translation>Create new mesh named</translation>
+ </message>
+ <message>
+ <source>MESH_APPEND_TO</source>
+ <translation>Append to mesh</translation>
+ </message>
<message>
<source>PROCESSING_IDENTICAL_GROUPS</source>
<translation>Processing identical groups</translation>
</message>
<message>
<source>RESULT_NAME</source>
- <translation>Result name</translation>
+ <translation>Result</translation>
</message>
<message>
<source>UNITE</source>
SMESH_FillHole.cxx
SMESH_Triangulate.cxx
SMESH_Offset.cxx
+ SMESH_Slot.cxx
+ SMESH_PolyLine.cxx
)
# --- rules ---
// Created : Tue Apr 30 18:00:36 2013
// Author : Edward AGAPOV (eap)
-// This file holds some low level algorithms extracted from SMESH_MeshEditor
+// Initially this file held some low level algorithms extracted from SMESH_MeshEditor
// to make them accessible from Controls package
#include "SMESH_MeshAlgos.hxx"
TElementBoxPool& elBoPool = getLimitAndPool()->_elBoPool;
+#ifdef _DEBUG_
+ if ( theElemIt && !theElemIt->more() )
+ std::cout << "WARNING: ElementBndBoxTree constructed on empty iterator!" << std::endl;
+#endif
+
SMDS_ElemIteratorPtr elemIt = theElemIt ? theElemIt : mesh.elementsIterator( elemType );
while ( elemIt->more() )
{
radius = point.Distance( boxCenter ) - 0.5 * ebbTree->maxSize();
if ( radius < 0 )
radius = ebbTree->maxSize() / pow( 2., getTreeHeight()) / 2;
- while ( suspectElems.empty() )
+ while ( suspectElems.empty() && radius < 1e100 )
{
ebbTree->getElementsInSphere( point.XYZ(), radius, suspectElems );
radius *= 1.1;
ElementBndBoxTree::TElemSeq elems;
ebbTree->getElementsInSphere( p, radius, elems );
- while ( elems.empty() )
+ while ( elems.empty() && radius < 1e100 )
{
radius *= 1.5;
ebbTree->getElementsInSphere( p, radius, elems );
ElementBndBoxTree::TElemSeq::iterator e = elems.begin();
for ( ; e != elems.end(); ++e )
{
- double d = SMESH_MeshAlgos::GetDistance( *e, p, &proj );
+ double d = SMESH_MeshAlgos::GetDistance( *e, point, &proj );
if ( d < minDist )
{
bestProj = proj;
// . RIGHT .
// . .
enum PositionName { POS_LEFT = 1, POS_VERTEX = 2, POS_RIGHT = 4, //POS_ON = 8,
- POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX };
+ POS_ALL = POS_LEFT | POS_RIGHT | POS_VERTEX,
+ POS_MAX = POS_RIGHT };
struct PointPos
{
PositionName _name;
const double badDistance = -1;
if ( !face ) return badDistance;
+ int nbCorners = face->NbCornerNodes();
+ if ( nbCorners > 3 )
+ {
+ std::vector< const SMDS_MeshNode* > nodes;
+ int nbTria = SMESH_MeshAlgos::Triangulate().GetTriangles( face, nodes );
+
+ double minDist = Precision::Infinite();
+ gp_XYZ cp;
+ for ( int i = 0; i < 3 * nbTria; i += 3 )
+ {
+ SMDS_FaceOfNodes triangle( nodes[i], nodes[i+1], nodes[i+2] );
+ double dist = GetDistance( &triangle, point, closestPnt );
+ if ( dist < minDist )
+ {
+ minDist = dist;
+ if ( closestPnt )
+ cp = *closestPnt;
+ }
+ }
+
+ if ( closestPnt )
+ *closestPnt = cp;
+ return minDist;
+ }
+
// coordinates of nodes (medium nodes, if any, ignored)
typedef SMDS_StdIterator< SMESH_TNodeXYZ, SMDS_ElemIteratorPtr > TXyzIterator;
std::vector<gp_XYZ> xyz( TXyzIterator( face->nodesIterator()), TXyzIterator() );
- xyz.resize( face->NbCornerNodes()+1 );
+ xyz.resize( 4 );
// transformation to get xyz[0] lies on the origin, xyz[1] lies on the Z axis,
// and xyz[2] lies in the XZ plane. This is to pass to 2D space on XZ plane.
// move all the nodes to 2D
std::vector<gp_XY> xy( xyz.size() );
- for ( size_t i = 0;i < xyz.size()-1; ++i )
+ for ( size_t i = 0; i < 3; ++i )
{
gp_XYZ p3d = xyz[i];
trsf.Transforms( p3d );
gp_XY point2D( tmpPnt.X(), tmpPnt.Z() );
// loop on edges of the face to analyze point position ralative to the face
- std::set< PointPos > pntPosSet;
+ std::vector< PointPos > pntPosByType[ POS_MAX + 1 ];
for ( size_t i = 1; i < xy.size(); ++i )
{
PointPos pos = getPointPosition( point2D, &xy[0], i-1 );
- pntPosSet.insert( pos );
+ pntPosByType[ pos._name ].push_back( pos );
}
// compute distance
- double minDist2 = Precision::Infinite();
- for ( std::set< PointPos >::iterator posIt = pntPosSet.begin(); posIt != pntPosSet.end(); ++posIt)
+ double dist = badDistance;
+
+ if ( pntPosByType[ POS_LEFT ].size() > 0 ) // point is most close to an edge
{
- PointPos pos = *posIt;
- if ( pos._name != pntPosSet.begin()->_name )
- break;
- switch ( pos._name )
- {
- case POS_LEFT: // point is most close to an edge
- {
- gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
- gp_Vec n1p ( xyz[ pos._index ], point );
- double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
- // projection of the point on the edge
- gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
- double dist2 = point.SquareDistance( proj );
- if ( dist2 < minDist2 )
- {
- if ( closestPnt ) *closestPnt = proj;
- minDist2 = dist2;
- }
- break;
- }
+ PointPos& pos = pntPosByType[ POS_LEFT ][0];
+
+ gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
+ gp_Vec n1p ( xyz[ pos._index ], point );
+ double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+ gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ(); // projection on the edge
+ dist = point.Distance( proj );
+ if ( closestPnt ) *closestPnt = proj;
+ }
- case POS_RIGHT: // point is inside the face
+ else if ( pntPosByType[ POS_RIGHT ].size() >= 2 ) // point is inside the face
+ {
+ dist = Abs( tmpPnt.Y() );
+ if ( closestPnt )
{
- double distToFacePlane = Abs( tmpPnt.Y() );
- if ( closestPnt )
- {
- if ( distToFacePlane < std::numeric_limits<double>::min() ) {
- *closestPnt = point.XYZ();
- }
- else {
- tmpPnt.SetY( 0 );
- trsf.Inverted().Transforms( tmpPnt );
- *closestPnt = tmpPnt;
- }
+ if ( dist < std::numeric_limits<double>::min() ) {
+ *closestPnt = point.XYZ();
+ }
+ else {
+ tmpPnt.SetY( 0 );
+ trsf.Inverted().Transforms( tmpPnt );
+ *closestPnt = tmpPnt;
}
- return distToFacePlane;
}
+ }
- case POS_VERTEX: // point is most close to a node
+ else if ( pntPosByType[ POS_VERTEX ].size() > 0 ) // point is most close to a node
+ {
+ double minDist2 = Precision::Infinite();
+ for ( size_t i = 0; i < pntPosByType[ POS_VERTEX ].size(); ++i )
{
- double dist2 = point.SquareDistance( xyz[ pos._index ]);
- if ( dist2 < minDist2 )
+ PointPos& pos = pntPosByType[ POS_VERTEX ][i];
+
+ double d2 = point.SquareDistance( xyz[ pos._index ]);
+ if ( minDist2 > d2 )
{
if ( closestPnt ) *closestPnt = xyz[ pos._index ];
- minDist2 = dist2;
+ minDist2 = d2;
}
- break;
- }
- default:;
- return badDistance;
}
+ dist = Sqrt( minDist2 );
}
- return Sqrt( minDist2 );
+
+ return dist;
}
//=======================================================================
return ( diff == 1 ) || ( diff == -face->NbNodes()+1 );
}
+//=======================================================================
+/*!
+ * \brief Partition given 1D elements into groups of contiguous edges.
+ * A node where number of meeting edges != 2 is a group end.
+ * An optional startNode is used to orient groups it belongs to.
+ * \return a list of edge groups and a list of corresponding node groups.
+ * If a group is closed, the first and last nodes of the group are same.
+ */
+//=======================================================================
+
+void SMESH_MeshAlgos::Get1DBranches( SMDS_ElemIteratorPtr theEdgeIt,
+ TElemGroupVector& theEdgeGroups,
+ TNodeGroupVector& theNodeGroups,
+ const SMDS_MeshNode* theStartNode )
+{
+ if ( !theEdgeIt )
+ return;
+
+ // build map of nodes and their adjacent edges
+
+ typedef std::vector< const SMDS_MeshNode* > TNodeVec;
+ typedef std::vector< const SMDS_MeshElement* > TEdgeVec;
+ typedef NCollection_DataMap< const SMDS_MeshNode*, TEdgeVec, SMESH_Hasher > TEdgesByNodeMap;
+ TEdgesByNodeMap edgesByNode;
+
+ while ( theEdgeIt->more() )
+ {
+ const SMDS_MeshElement* edge = theEdgeIt->next();
+ if ( edge->GetType() != SMDSAbs_Edge )
+ continue;
+
+ const SMDS_MeshNode* nodes[2] = { edge->GetNode(0), edge->GetNode(1) };
+ for ( int i = 0; i < 2; ++i )
+ {
+ TEdgeVec* nodeEdges = edgesByNode.ChangeSeek( nodes[i] );
+ if ( !nodeEdges )
+ {
+ nodeEdges = edgesByNode.Bound( nodes[i], TEdgeVec() );
+ nodeEdges->reserve(2);
+ }
+ nodeEdges->push_back( edge );
+ }
+ }
+
+ if ( edgesByNode.IsEmpty() )
+ return;
+
+
+ // build edge branches
+
+ TElemGroupVector branches(2);
+ TNodeGroupVector nodeBranches(2);
+
+ while ( !edgesByNode.IsEmpty() )
+ {
+ if ( !theStartNode || !edgesByNode.IsBound( theStartNode ))
+ {
+ theStartNode = TEdgesByNodeMap::Iterator( edgesByNode ).Key();
+ }
+
+ size_t nbBranches = 0;
+ bool startIsBranchEnd = false;
+
+ while ( edgesByNode.IsBound( theStartNode ))
+ {
+ // initialize a new branch
+
+ ++nbBranches;
+ if ( branches.size() < nbBranches )
+ {
+ branches.push_back ( TEdgeVec() );
+ nodeBranches.push_back( TNodeVec() );
+ }
+ TEdgeVec & branch = branches [ nbBranches - 1 ];
+ TNodeVec & nodeBranch = nodeBranches[ nbBranches - 1 ];
+ branch.clear();
+ nodeBranch.clear();
+ {
+ TEdgeVec& edges = edgesByNode( theStartNode );
+ startIsBranchEnd = ( edges.size() != 2 );
+
+ int nbEdges = 0;
+ const SMDS_MeshElement* startEdge = 0;
+ for ( size_t i = 0; i < edges.size(); ++i )
+ {
+ if ( !startEdge && edges[i] )
+ {
+ startEdge = edges[i];
+ edges[i] = 0;
+ }
+ nbEdges += bool( edges[i] );
+ }
+ if ( nbEdges == 0 )
+ edgesByNode.UnBind( theStartNode );
+ if ( !startEdge )
+ continue;
+
+ branch.push_back( startEdge );
+
+ nodeBranch.push_back( theStartNode );
+ nodeBranch.push_back( branch.back()->GetNode(0) );
+ if ( nodeBranch.back() == theStartNode )
+ nodeBranch.back() = branch.back()->GetNode(1);
+ }
+
+ // fill the branch
+
+ bool isBranchEnd = false;
+ TEdgeVec* edgesPtr;
+
+ while (( !isBranchEnd ) && ( edgesPtr = edgesByNode.ChangeSeek( nodeBranch.back() )))
+ {
+ TEdgeVec& edges = *edgesPtr;
+
+ isBranchEnd = ( edges.size() != 2 );
+
+ const SMDS_MeshNode* lastNode = nodeBranch.back();
+
+ switch ( edges.size() )
+ {
+ case 1:
+ edgesByNode.UnBind( lastNode );
+ break;
+
+ case 2:
+ {
+ if ( const SMDS_MeshElement* nextEdge = edges[ edges[0] == branch.back() ])
+ {
+ branch.push_back( nextEdge );
+
+ const SMDS_MeshNode* nextNode = nextEdge->GetNode(0);
+ if ( nodeBranch.back() == nextNode )
+ nextNode = nextEdge->GetNode(1);
+ nodeBranch.push_back( nextNode );
+ }
+ edgesByNode.UnBind( lastNode );
+ break;
+ }
+
+ default:
+ int nbEdges = 0;
+ for ( size_t i = 0; i < edges.size(); ++i )
+ {
+ if ( edges[i] == branch.back() )
+ edges[i] = 0;
+ nbEdges += bool( edges[i] );
+ }
+ if ( nbEdges == 0 )
+ edgesByNode.UnBind( lastNode );
+ }
+ }
+ } // while ( edgesByNode.IsBound( theStartNode ))
+
+
+ // put the found branches to the result
+
+ if ( nbBranches == 2 && !startIsBranchEnd ) // join two branches starting at the same node
+ {
+ if ( nodeBranches[0].back() == nodeBranches[1].back() )
+ {
+ // it is a closed branch, keep theStartNode first
+ nodeBranches[0].pop_back();
+ nodeBranches[0].reserve( nodeBranches[0].size() + nodeBranches[1].size() );
+ nodeBranches[0].insert( nodeBranches[0].end(),
+ nodeBranches[1].rbegin(), nodeBranches[1].rend() );
+ branches[0].reserve( branches[0].size() + branches[1].size() );
+ branches[0].insert( branches[0].end(), branches[1].rbegin(), branches[1].rend() );
+ }
+ else
+ {
+ std::reverse( nodeBranches[0].begin(), nodeBranches[0].end() );
+ nodeBranches[0].pop_back();
+ nodeBranches[0].reserve( nodeBranches[0].size() + nodeBranches[1].size() );
+ nodeBranches[0].insert( nodeBranches[0].end(),
+ nodeBranches[1].begin(), nodeBranches[1].end() );
+
+ std::reverse( branches[0].begin(), branches[0].end() );
+ branches[0].reserve( branches[0].size() + branches[1].size() );
+ branches[0].insert( branches[0].end(), branches[1].begin(), branches[1].end() );
+ }
+ nodeBranches[1].clear();
+ branches[1].clear();
+ }
+
+ for ( size_t i = 0; i < nbBranches; ++i )
+ {
+ if ( branches[i].empty() )
+ continue;
+
+ theEdgeGroups.push_back( TEdgeVec() );
+ theEdgeGroups.back().swap( branches[i] );
+
+ theNodeGroups.push_back( TNodeVec() );
+ theNodeGroups.back().swap( nodeBranches[i] );
+ }
+
+ } // while ( !edgesByNode.IsEmpty() )
+
+ return;
+}
+
//=======================================================================
/*!
* \brief Return SMESH_NodeSearcher
// Created : Tue Apr 30 18:00:36 2013
// Author : Edward AGAPOV (eap)
-// This file holds some low level algorithms extracted from SMESH_MeshEditor
+// Initially this file held some low level algorithms extracted from SMESH_MeshEditor
// to make them accessible from Controls package, and more
#include "SMESH_TypeDefs.hxx"
#include <TopAbs_State.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Vec.hxx>
+
#include <vector>
-class gp_Pnt;
-class gp_Ax1;
class Bnd_B3d;
-class SMDS_MeshNode;
-class SMDS_MeshElement;
+class gp_Ax1;
class SMDS_Mesh;
+class SMDS_MeshElement;
+class SMDS_MeshGroup;
+class SMDS_MeshNode;
//=======================================================================
/*!
bool IsRightOrder( const SMDS_MeshElement* face,
const SMDS_MeshNode* node0,
const SMDS_MeshNode* node1 );
+
+ typedef std::vector< std::vector< const SMDS_MeshElement* > > TElemGroupVector;
+ typedef std::vector< std::vector< const SMDS_MeshNode* > > TNodeGroupVector;
+ /*!
+ * \brief Partition given 1D elements into groups of contiguous edges.
+ * A node where number of meeting edges != 2 is a group end.
+ * An optional startNode is used to orient groups it belongs to.
+ * \return a list of edge groups and a list of corresponding node groups.
+ * If a group is closed, the first and last nodes of the group are same.
+ */
+ SMESHUtils_EXPORT
+ void Get1DBranches( SMDS_ElemIteratorPtr edgeIt,
+ TElemGroupVector& edgeGroups,
+ TNodeGroupVector& nodeGroups,
+ const SMDS_MeshNode* startNode = 0 );
+
/*!
* \brief Mark elements given by SMDS_Iterator
*/
std::vector<const SMDS_MeshElement*>& newFaces);
// Implemented in ./SMESH_FillHole.cxx
-
/*!
* \brief Find nodes whose merge makes the element invalid
*/
// Implemented in SMESH_DeMerge.cxx
- typedef std::vector< std::pair< const SMDS_MeshElement*, const SMDS_MeshElement* > > TEPairVec;
- typedef std::vector< std::pair< const SMDS_MeshNode*, const SMDS_MeshNode* > > TNPairVec;
+ typedef std::vector< std::pair< const SMDS_MeshElement*, int > > TElemIntPairVec;
+ typedef std::vector< std::pair< const SMDS_MeshNode*, int > > TNodeIntPairVec;
/*!
* \brief Create an offset mesh of given faces
* \param [in] faceIt - the input faces
SMDS_Mesh& mesh,
const double offset,
const bool theFixIntersections,
- TEPairVec& new2OldFaces,
- TNPairVec& new2OldNodes );
+ TElemIntPairVec& new2OldFaces,
+ TNodeIntPairVec& new2OldNodes );
// Implemented in ./SMESH_Offset.cxx
+ //=======================================================================
+ /*!
+ * \brief Cut faces of a triangular mesh.
+ * Usage work-flow: 1) call Cut() methods as many times as needed
+ * 2) call MakeNewFaces() to really modify the mesh faces
+ */
+ //=======================================================================
+ // implemented in SMESH_Offset.cxx
+
+ class SMESHUtils_EXPORT Intersector
+ {
+ public:
+ Intersector( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals );
+ ~Intersector();
+
+ //! Compute cut of two faces of the mesh
+ void Cut( const SMDS_MeshElement* face1,
+ const SMDS_MeshElement* face2,
+ const int nbCommonNodes = -1 );
+
+ //! Store a face cut by a line given by its ends lying either on face edges or inside the face.
+ // Line ends are accompanied by indices of intersected face edges.
+ // Edge index is <0 if a line end is inside the face.
+ void Cut( const SMDS_MeshElement* face,
+ SMESH_NodeXYZ& lineEnd1,
+ int edgeIndex1,
+ SMESH_NodeXYZ& lineEnd2,
+ int edgeIndex2 );
+
+ //! Split all faces intersected by Cut() methods.
+ // theSign = (-1|1) is used to choose which part of a face cut by another one to remove.
+ // 1 means to remove a part opposite to face normal.
+ // Optionally optimize quality of split faces by edge swapping.
+ void MakeNewFaces( SMESH_MeshAlgos::TElemIntPairVec& theNew2OldFaces,
+ SMESH_MeshAlgos::TNodeIntPairVec& theNew2OldNodes,
+ const double theSign = 1.,
+ const bool theOptimize = false );
+
+ typedef std::vector< SMESH_NodeXYZ > TFace;
+
+ //! Cut a face by planes, whose normals point to parts to keep.
+ // Return true if the whole face is cut off
+ static bool CutByPlanes(const SMDS_MeshElement* face,
+ const std::vector< gp_Ax1 > & planes,
+ const double tol,
+ std::vector< TFace > & newFaceConnectivity );
+
+ private:
+ struct Algo;
+ Algo* myAlgo;
+ };
+
+ //=======================================================================
/*!
* \brief Divide a mesh face into triangles
*/
+ //=======================================================================
// Implemented in ./SMESH_Triangulate.cxx
class SMESHUtils_EXPORT Triangulate
{
public:
+ Triangulate(bool optimize=false);
+ ~Triangulate();
+
static int GetNbTriangles( const SMDS_MeshElement* face );
int GetTriangles( const SMDS_MeshElement* face,
struct PolyVertex
{
SMESH_NodeXYZ _nxyz;
+ size_t _index;
gp_XY _xy;
PolyVertex* _prev;
PolyVertex* _next;
- void SetNodeAndNext( const SMDS_MeshNode* n, PolyVertex& v );
- void GetTriaNodes( const SMDS_MeshNode** nodes) const;
+ void SetNodeAndNext( const SMDS_MeshNode* n, PolyVertex& v, size_t index );
+ void GetTriaNodes( const SMDS_MeshNode** nodes, size_t* nodeIndices) const;
double TriaArea() const;
bool IsInsideTria( const PolyVertex* v );
PolyVertex* Delete();
};
+ struct Optimizer;
+
std::vector< PolyVertex > _pv;
+ std::vector< size_t > _nodeIndex;
+ Optimizer* _optimizer;
};
+ // structure used in MakePolyLine() to define a cutting plane
+ struct PolySegment
+ {
+ // 2 points, each defined as follows:
+ // ( myNode1 && myNode2 ) ==> point is in the middle of an edge defined by two nodes
+ // ( myNode1 && !myNode2 ) ==> point is at myNode1 of a some face
+ // else ==> point is at myXYZ
+ const SMDS_MeshNode* myNode1[2];
+ const SMDS_MeshNode* myNode2[2];
+ gp_XYZ myXYZ [2];
+
+ // face on which myXYZ projects (found by MakePolyLine())
+ const SMDS_MeshElement* myFace [2];
+
+ // vector on the plane; to use a default plane set vector = (0,0,0)
+ gp_Vec myVector;
+
+ // point returning coordinates of a middle of the two points, projected to mesh
+ gp_Pnt myMidProjPoint;
+ };
+ typedef std::vector<PolySegment> TListOfPolySegments;
+
+ /*!
+ * \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of
+ * the initial mesh. Positions of new nodes are found by cutting the mesh by the
+ * plane passing through pairs of points specified by each PolySegment structure.
+ * If there are several paths connecting a pair of points, the shortest path is
+ * selected by the module. Position of the cutting plane is defined by the two
+ * points and an optional vector lying on the plane specified by a PolySegment.
+ * By default the vector is defined by Mesh module as following. A middle point
+ * of the two given points is computed. The middle point is projected to the mesh.
+ * The vector goes from the middle point to the projection point. In case of planar
+ * mesh, the vector is normal to the mesh.
+ * \param [inout] segments - PolySegment's defining positions of cutting planes.
+ * Return the used vector and position of the middle point.
+ * \param [in] group - an optional group where created mesh segments will
+ * be added.
+ */
+ // Implemented in ./SMESH_PolyLine.cxx
+ SMESHUtils_EXPORT
+ void MakePolyLine( SMDS_Mesh* mesh,
+ TListOfPolySegments& segments,
+ std::vector<const SMDS_MeshElement*>& newEdges,
+ std::vector<const SMDS_MeshNode*>& newNodes,
+ SMDS_MeshGroup* group=0,
+ SMESH_ElementSearcher* searcher=0);
+
+ /*!
+ * Create a slot of given width around given 1D elements lying on a triangle mesh.
+ * The slot is consrtucted by cutting faces by cylindrical surfaces made around each segment.
+ * \return Edges located at the slot boundary
+ */
+ // Implemented in ./SMESH_Slot.cxx
+ SMESHUtils_EXPORT
+ std::vector< Edge > MakeSlot( SMDS_ElemIteratorPtr segmentIt,
+ double width,
+ SMDS_Mesh* mesh);
} // namespace SMESH_MeshAlgos
{
const int theMaxNbFaces = 256; // max number of faces sharing a node
- typedef NCollection_DataMap< Standard_Address, const SMDS_MeshNode* > TNNMap;
- typedef NCollection_Map< SMESH_Link, SMESH_Link > TLinkMap;
+ typedef NCollection_DataMap< const SMDS_MeshNode*, const SMDS_MeshNode*, SMESH_Hasher > TNNMap;
+ typedef NCollection_Map< SMESH_Link, SMESH_Link > TLinkMap;
//--------------------------------------------------------------------------------
/*!
struct CutLink
{
bool myReverse;
- const SMDS_MeshNode* myNode[2]; // side nodes
+ const SMDS_MeshNode* myNode[2]; // side nodes. WARNING: don't set them directly, use Set()
mutable SMESH_NodeXYZ myIntNode; // intersection node
const SMDS_MeshElement* myFace; // cutter face
int myIndex; // index of a node on the same link
return useOneNormal;
}
+} // namespace
+
+namespace SMESH_MeshAlgos
+{
//--------------------------------------------------------------------------------
/*!
* \brief Intersect faces of a mesh
*/
- struct Intersector
+ struct Intersector::Algo
{
SMDS_Mesh* myMesh;
double myTol, myEps;
int myNbOnPlane1, myNbOnPlane2;
TIntPointSet myIntPointSet;
- Intersector( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals )
+ Algo( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals )
: myMesh( mesh ),
myTol( tol ),
myEps( 1e-100 ),
void Cut( const SMDS_MeshElement* face1,
const SMDS_MeshElement* face2,
const int nbCommonNodes );
- void MakeNewFaces( SMESH_MeshAlgos::TEPairVec& theNew2OldFaces,
- SMESH_MeshAlgos::TNPairVec& theNew2OldNodes,
- const double theSign );
+ void Cut( const SMDS_MeshElement* face,
+ SMESH_NodeXYZ& lineEnd1,
+ int edgeIndex1,
+ SMESH_NodeXYZ& lineEnd2,
+ int edgeIndex2 );
+ void MakeNewFaces( TElemIntPairVec& theNew2OldFaces,
+ TNodeIntPairVec& theNew2OldNodes,
+ const double theSign,
+ const bool theOptimize );
+
+ //! Cut a face by planes, whose normals point to parts to keep
+ bool CutByPlanes(const SMDS_MeshElement* face,
+ const std::vector< gp_Ax1 > & planes,
+ std::vector< SMESH_NodeXYZ > & newConnectivity );
private:
*/
//================================================================================
- const SMDS_MeshNode* Intersector::createNode( const gp_XYZ& p )
+ const SMDS_MeshNode* Intersector::Algo::createNode( const gp_XYZ& p )
{
const SMDS_MeshNode* n = myMesh->AddNode( p.X(), p.Y(), p.Z() );
n->setIsMarked( true ); // cut nodes are marked
*/
//================================================================================
- void Intersector::addLink( CutLink& link )
+ void Intersector::Algo::addLink( CutLink& link )
{
link.myIndex = 0;
const CutLink* added = & myCutLinks.Added( link );
*/
//================================================================================
- bool Intersector::findLink( CutLink& link )
+ bool Intersector::Algo::findLink( CutLink& link )
{
link.myIndex = 0;
while ( myCutLinks.Contains( link ))
*/
//================================================================================
- bool Intersector::isPlaneIntersected( const gp_XYZ& n2,
- const double d2,
- const std::vector< SMESH_NodeXYZ >& nodes1,
- std::vector< double > & dist1,
- int & nbOnPlane1,
- int & iNotOnPlane1)
+ bool Intersector::Algo::isPlaneIntersected( const gp_XYZ& n2,
+ const double d2,
+ const std::vector< SMESH_NodeXYZ >& nodes1,
+ std::vector< double > & dist1,
+ int & nbOnPlane1,
+ int & iNotOnPlane1)
{
iNotOnPlane1 = nbOnPlane1 = 0;
dist1.resize( nodes1.size() );
*/
//================================================================================
- void Intersector::computeIntervals( const std::vector< SMESH_NodeXYZ >& nodes,
- const std::vector< double >& dist,
- const int nbOnPln,
- const int iMaxCoo,
- double * u,
- int* iE)
+ void Intersector::Algo::computeIntervals( const std::vector< SMESH_NodeXYZ >& nodes,
+ const std::vector< double >& dist,
+ const int nbOnPln,
+ const int iMaxCoo,
+ double * u,
+ int* iE)
{
if ( nbOnPln == 3 )
{
*/
//================================================================================
- void Intersector::findIntPointOnPlane( const std::vector< SMESH_NodeXYZ >& nodes,
- const std::vector< double > & dist,
- CutLink& link )
+ void Intersector::Algo::findIntPointOnPlane( const std::vector< SMESH_NodeXYZ >& nodes,
+ const std::vector< double > & dist,
+ CutLink& link )
{
int i1 = ( dist[0] == 0 ? 0 : 1 ), i2 = ( dist[2] == 0 ? 2 : 1 );
CutLink link2 = link;
*/
//================================================================================
- void Intersector::intersectLink( const std::vector< SMESH_NodeXYZ >& nodes1,
- const std::vector< double > & dist1,
- const int iEdge1,
- const SMDS_MeshElement* face2,
- CutLink& link1)
+ void Intersector::Algo::intersectLink( const std::vector< SMESH_NodeXYZ >& nodes1,
+ const std::vector< double > & dist1,
+ const int iEdge1,
+ const SMDS_MeshElement* face2,
+ CutLink& link1)
{
const int iEdge2 = ( iEdge1 + 1 ) % nodes1.size();
const SMESH_NodeXYZ& p1 = nodes1[ iEdge1 ];
*/
//================================================================================
- void Intersector::replaceIntNode( const SMDS_MeshNode* nToKeep,
- const SMDS_MeshNode* nToRemove )
+ void Intersector::Algo::replaceIntNode( const SMDS_MeshNode* nToKeep,
+ const SMDS_MeshNode* nToRemove )
{
if ( nToKeep == nToRemove )
return;
if ( nToRemove->GetID() < nToKeep->GetID() ) // keep node with lower ID
- myRemove2KeepNodes.Bind((void*) nToKeep, nToRemove );
+ myRemove2KeepNodes.Bind( nToKeep, nToRemove );
else
- myRemove2KeepNodes.Bind((void*) nToRemove, nToKeep );
+ myRemove2KeepNodes.Bind( nToRemove, nToKeep );
}
//================================================================================
*/
//================================================================================
- void Intersector::computeIntPoint( const double u1,
- const double u2,
- const int iE1,
- const int iE2,
- CutLink & link,
- const SMDS_MeshNode* & node1,
- const SMDS_MeshNode* & node2)
+ void Intersector::Algo::computeIntPoint( const double u1,
+ const double u2,
+ const int iE1,
+ const int iE2,
+ CutLink & link,
+ const SMDS_MeshNode* & node1,
+ const SMDS_MeshNode* & node2)
{
if ( u1 > u2 + myTol )
{
*/
//================================================================================
- void Intersector::cutCollinearLink( const int iNotOnPlane1,
- const std::vector< SMESH_NodeXYZ >& nodes1,
- const SMDS_MeshElement* face2,
- const CutLink& link1,
- const CutLink& link2)
+ void Intersector::Algo::cutCollinearLink( const int iNotOnPlane1,
+ const std::vector< SMESH_NodeXYZ >& nodes1,
+ const SMDS_MeshElement* face2,
+ const CutLink& link1,
+ const CutLink& link2)
{
int iN1 = ( iNotOnPlane1 + 1 ) % 3;
*/
//================================================================================
- void Intersector::setPlaneIndices( const gp_XYZ& planeNorm )
+ void Intersector::Algo::setPlaneIndices( const gp_XYZ& planeNorm )
{
switch ( MaxIndex( planeNorm )) {
case 1: myInd1 = 2; myInd2 = 3; break;
*/
//================================================================================
- void Intersector::Cut( const SMDS_MeshElement* face1,
- const SMDS_MeshElement* face2,
- const int nbCommonNodes)
+ void Intersector::Algo::Cut( const SMDS_MeshElement* face1,
+ const SMDS_MeshElement* face2,
+ const int nbCommonNodes)
{
myFace1 = face1;
myFace2 = face2;
return;
}
+ //================================================================================
+ /*!
+ * \brief Store a face cut by a line given by its ends
+ * accompanied by indices of intersected face edges.
+ * Edge index is <0 if a line end is inside the face.
+ * \param [in] face - a face to cut
+ * \param [inout] lineEnd1 - line end coordinates + optional node existing at this point
+ * \param [in] edgeIndex1 - index of face edge cut by lineEnd1
+ * \param [inout] lineEnd2 - line end coordinates + optional node existing at this point
+ * \param [in] edgeIndex2 - index of face edge cut by lineEnd2
+ */
+ //================================================================================
+
+ void Intersector::Algo::Cut( const SMDS_MeshElement* face,
+ SMESH_NodeXYZ& lineEnd1,
+ int edgeIndex1,
+ SMESH_NodeXYZ& lineEnd2,
+ int edgeIndex2 )
+ {
+ if ( lineEnd1.Node() && lineEnd2.Node() &&
+ face->GetNodeIndex( lineEnd1.Node() ) >= 0 &&
+ face->GetNodeIndex( lineEnd2.Node() ) >= 0 )
+ return; // intersection at a face node or edge
+
+ if ((int) myNormals.size() <= face->GetID() )
+ const_cast< std::vector< gp_XYZ >& >( myNormals ).resize( face->GetID() + 1 );
+
+ const CutFace& cf = myCutFaces.Added( CutFace( face ));
+ cf.InitLinks();
+
+ // look for intersection nodes coincident with line ends
+ CutLink links[2];
+ for ( int is2nd = 0; is2nd < 2; ++is2nd )
+ {
+ SMESH_NodeXYZ& lineEnd = is2nd ? lineEnd2 : lineEnd1;
+ int edgeIndex = is2nd ? edgeIndex2 : edgeIndex1;
+ CutLink & link = links[ is2nd ];
+
+ link.myIntNode = lineEnd;
+
+ for ( size_t i = ( edgeIndex < 0 ? 3 : 0 ); i < cf.myLinks.size(); ++i )
+ if ( coincide( lineEnd, SMESH_NodeXYZ( cf.myLinks[i].myNode1 ), myTol ))
+ {
+ link.myIntNode = cf.myLinks[i].myNode1;
+ break;
+ }
+
+ if ( edgeIndex >= 0 )
+ {
+ link.Set( face->GetNode ( edgeIndex ),
+ face->GetNodeWrap( edgeIndex + 1 ),
+ /*cuttingFace=*/0);
+ findLink( link );
+ }
+
+ if ( !link.myIntNode )
+ link.myIntNode.Set( createNode( lineEnd ));
+
+ lineEnd._node = link.IntNode();
+
+ if ( link.myNode[0] )
+ addLink( link );
+ }
+
+ cf.AddEdge( links[0], links[1], /*face=*/0, /*nbOnPlane=*/0, /*iNotOnPlane=*/-1 );
+ }
+
//================================================================================
/*!
* \brief Intersect two 2D line segments
*/
//================================================================================
- bool Intersector::intersectEdgeEdge( const gp_XY s1p0, const gp_XY s1p1,
- const gp_XY s2p0, const gp_XY s2p1,
- double & t1, double & t2,
- bool & isCollinear )
+ bool Intersector::Algo::intersectEdgeEdge( const gp_XY s1p0, const gp_XY s1p1,
+ const gp_XY s2p0, const gp_XY s2p1,
+ double & t1, double & t2,
+ bool & isCollinear )
{
gp_XY u = s1p1 - s1p0;
gp_XY v = s2p1 - s2p0;
*/
//================================================================================
- bool Intersector::intersectEdgeEdge( int iE1, int iE2, IntPoint2D& intPoint )
+ bool Intersector::Algo::intersectEdgeEdge( int iE1, int iE2, IntPoint2D& intPoint )
{
int i01 = iE1, i11 = ( iE1 + 1 ) % 3;
int i02 = iE2, i12 = ( iE2 + 1 ) % 3;
*/
//================================================================================
- bool Intersector::isPointInTriangle( const gp_XYZ& p, const std::vector< SMESH_NodeXYZ >& nodes )
+ bool Intersector::Algo::isPointInTriangle( const gp_XYZ& p, const std::vector< SMESH_NodeXYZ >& nodes )
{
double bc1, bc2;
SMESH_MeshAlgos::GetBarycentricCoords( p2D( p ),
*/
//================================================================================
- void Intersector::cutCoplanar()
+ void Intersector::Algo::cutCoplanar()
{
// find intersections of edges
}
return;
- } // Intersector::cutCoplanar()
+ } // Intersector::Algo::cutCoplanar()
//================================================================================
/*!
*/
//================================================================================
- void Intersector::intersectNewEdges( const CutFace& cf )
+ void Intersector::Algo::intersectNewEdges( const CutFace& cf )
{
IntPoint2D intPoint;
if ( cf.NbInternalEdges() < 2 )
return;
+ if ( myNodes1.empty() )
+ {
+ myNodes1.resize(2);
+ myNodes2.resize(2);
+ }
+
const gp_XYZ& faceNorm = myNormals[ cf.myInitFace->GetID() ];
setPlaneIndices( faceNorm ); // choose indices on an axis-aligned plane
}
}
if ( cf.myLinks.size() >= limit )
- throw SALOME_Exception( "Infinite loop in Intersector::intersectNewEdges()" );
+ throw SALOME_Exception( "Infinite loop in Intersector::Algo::intersectNewEdges()" );
}
++i1; // each internal edge encounters twice
}
*/
//================================================================================
- void Intersector::MakeNewFaces( SMESH_MeshAlgos::TEPairVec& theNew2OldFaces,
- SMESH_MeshAlgos::TNPairVec& theNew2OldNodes,
- const double theSign)
+ void Intersector::Algo::MakeNewFaces( SMESH_MeshAlgos::TElemIntPairVec& theNew2OldFaces,
+ SMESH_MeshAlgos::TNodeIntPairVec& theNew2OldNodes,
+ const double theSign,
+ const bool theOptimize)
{
+ // fill theNew2OldFaces if empty
+ TCutFaceMap::const_iterator cutFacesIt = myCutFaces.cbegin();
+ if ( theNew2OldFaces.empty() )
+ for ( ; cutFacesIt != myCutFaces.cend(); ++cutFacesIt )
+ {
+ const CutFace& cf = *cutFacesIt;
+ int index = cf.myInitFace->GetID(); // index in theNew2OldFaces
+ if ((int) theNew2OldFaces.size() <= index )
+ theNew2OldFaces.resize( index + 1 );
+ theNew2OldFaces[ index ] = std::make_pair( cf.myInitFace, index );
+ }
+
// unmark all nodes except intersection ones
for ( SMDS_NodeIteratorPtr nIt = myMesh->nodesIterator(); nIt->more(); )
// intersect edges added to myCutFaces
- TCutFaceMap::const_iterator cutFacesIt = myCutFaces.cbegin();
- for ( ; cutFacesIt != myCutFaces.cend(); ++cutFacesIt )
+ for ( cutFacesIt = myCutFaces.cbegin(); cutFacesIt != myCutFaces.cend(); ++cutFacesIt )
{
const CutFace& cf = *cutFacesIt;
cf.ReplaceNodes( myRemove2KeepNodes );
// make new faces
EdgeLoopSet loopSet;
- SMESH_MeshAlgos::Triangulate triangulator;
+ SMESH_MeshAlgos::Triangulate triangulator( theOptimize );
std::vector< EdgePart > cutOffLinks;
TLinkMap cutOffCoplanarLinks;
std::vector< const CutFace* > touchedFaces;
- SMESH_MeshAlgos::TEPairVec::value_type new2OldTria;
+ SMESH_MeshAlgos::TElemIntPairVec::value_type new2OldTria;
CutFace cutFace(0);
std::vector< const SMDS_MeshNode* > nodes;
std::vector<const SMDS_MeshElement *> faces;
// remove split faces
for ( size_t id = 1; id < theNew2OldFaces.size(); ++id )
{
- if ( theNew2OldFaces[id].first )
+ if ( theNew2OldFaces[id].first ||
+ theNew2OldFaces[id].second == 0 )
continue;
if ( const SMDS_MeshElement* f = myMesh->FindElement( id ))
myMesh->RemoveFreeElement( f );
}
- // remove face connected to cut off parts of cf.myInitFace
+ // remove faces connected to cut off parts of cf.myInitFace
nodes.resize(2);
for ( size_t i = 0; i < cutOffLinks.size(); ++i )
// add used new nodes to theNew2OldNodes
- SMESH_MeshAlgos::TNPairVec::value_type new2OldNode;
- new2OldNode.second = NULL;
+ SMESH_MeshAlgos::TNodeIntPairVec::value_type new2OldNode;
+ new2OldNode.second = 0;
for ( cutLinksIt = myCutLinks.cbegin(); cutLinksIt != myCutLinks.cend(); ++cutLinksIt )
{
const CutLink& link = *cutLinksIt;
return;
}
+ //================================================================================
+ Intersector::Intersector( SMDS_Mesh* mesh, double tol, const std::vector< gp_XYZ >& normals )
+ {
+ myAlgo = new Algo( mesh, tol, normals );
+ }
+ //================================================================================
+ Intersector::~Intersector()
+ {
+ delete myAlgo;
+ }
+ //================================================================================
+ //! compute cut of two faces of the mesh
+ void Intersector::Cut( const SMDS_MeshElement* face1,
+ const SMDS_MeshElement* face2,
+ const int nbCommonNodes )
+ {
+ myAlgo->Cut( face1, face2, nbCommonNodes );
+ }
+ //================================================================================
+ //! store a face cut by a line given by its ends
+ // accompanied by indices of intersected face edges.
+ // Edge index is <0 if a line end is inside the face.
+ void Intersector::Cut( const SMDS_MeshElement* face,
+ SMESH_NodeXYZ& lineEnd1,
+ int edgeIndex1,
+ SMESH_NodeXYZ& lineEnd2,
+ int edgeIndex2 )
+ {
+ myAlgo->Cut( face, lineEnd1, edgeIndex1, lineEnd2, edgeIndex2 );
+ }
+ //================================================================================
+ //! split all face intersected by Cut() methods
+ void Intersector::MakeNewFaces( SMESH_MeshAlgos::TElemIntPairVec& theNew2OldFaces,
+ SMESH_MeshAlgos::TNodeIntPairVec& theNew2OldNodes,
+ const double theSign,
+ const bool theOptimize )
+ {
+ myAlgo->MakeNewFaces( theNew2OldFaces, theNew2OldNodes, theSign, theOptimize );
+ }
+ //================================================================================
+ //! Cut a face by planes, whose normals point to parts to keep
+ bool Intersector::CutByPlanes(const SMDS_MeshElement* theFace,
+ const std::vector< gp_Ax1 > & thePlanes,
+ const double theTol,
+ std::vector< TFace > & theNewFaceConnectivity )
+ {
+ theNewFaceConnectivity.clear();
+
+ // check if theFace is wholly cut off
+ std::vector< SMESH_NodeXYZ > facePoints( theFace->begin_nodes(), theFace->end_nodes() );
+ facePoints.resize( theFace->NbCornerNodes() );
+ for ( size_t iP = 0; iP < thePlanes.size(); ++iP )
+ {
+ size_t nbOut = 0;
+ const gp_Pnt& O = thePlanes[iP].Location();
+ for ( size_t i = 0; i < facePoints.size(); ++i )
+ {
+ gp_Vec Op( O, facePoints[i] );
+ nbOut += ( Op * thePlanes[iP].Direction() <= 0 );
+ }
+ if ( nbOut == facePoints.size() )
+ return true;
+ }
+
+ // copy theFace into a temporary mesh
+ SMDS_Mesh mesh;
+ Bnd_B3d faceBox;
+ std::vector< const SMDS_MeshNode* > faceNodes;
+ faceNodes.resize( facePoints.size() );
+ for ( size_t i = 0; i < facePoints.size(); ++i )
+ {
+ const SMESH_NodeXYZ& n = facePoints[i];
+ faceNodes[i] = mesh.AddNode( n.X(), n.Y(), n.Z() );
+ faceBox.Add( n );
+ }
+ const SMDS_MeshElement* faceToCut = 0;
+ switch ( theFace->NbCornerNodes() )
+ {
+ case 3:
+ faceToCut = mesh.AddFace( faceNodes[0], faceNodes[1], faceNodes[2] );
+ break;
+ case 4:
+ faceToCut = mesh.AddFace( faceNodes[0], faceNodes[1], faceNodes[2], faceNodes[3] );
+ break;
+ default:
+ faceToCut = mesh.AddPolygonalFace( faceNodes );
+ }
+
+ std::vector< gp_XYZ > normals( 2 + thePlanes.size() );
+ SMESH_MeshAlgos::FaceNormal( faceToCut, normals[ faceToCut->GetID() ]);
+
+ // add faces corresponding to thePlanes
+ std::vector< const SMDS_MeshElement* > planeFaces;
+ double faceSize = Sqrt( faceBox.SquareExtent() );
+ gp_XYZ center = 0.5 * ( faceBox.CornerMin() + faceBox.CornerMax() );
+ for ( size_t i = 0; i < thePlanes.size(); ++i )
+ {
+ gp_Ax2 plnAx( thePlanes[i].Location(), thePlanes[i].Direction() );
+ gp_XYZ O = plnAx.Location().XYZ();
+ gp_XYZ X = plnAx.XDirection().XYZ();
+ gp_XYZ Y = plnAx.YDirection().XYZ();
+ gp_XYZ Z = plnAx.Direction().XYZ();
+
+ double dot = ( O - center ) * Z;
+ gp_XYZ o = center + Z * dot; // center projected to a plane
+
+ gp_XYZ p1 = o + X * faceSize * 2;
+ gp_XYZ p2 = o + Y * faceSize * 2;
+ gp_XYZ p3 = o - (X + Y ) * faceSize * 2;
+
+ const SMDS_MeshNode* n1 = mesh.AddNode( p1.X(), p1.Y(), p1.Z() );
+ const SMDS_MeshNode* n2 = mesh.AddNode( p2.X(), p2.Y(), p2.Z() );
+ const SMDS_MeshNode* n3 = mesh.AddNode( p3.X(), p3.Y(), p3.Z() );
+ planeFaces.push_back( mesh.AddFace( n1, n2, n3 ));
+
+ normals[ planeFaces.back()->GetID() ] = thePlanes[i].Direction().XYZ();
+ }
+
+ // cut theFace
+ Algo algo ( &mesh, theTol, normals );
+ for ( size_t i = 0; i < planeFaces.size(); ++i )
+ {
+ algo.Cut( faceToCut, planeFaces[i], 0 );
+ }
+
+ // retrieve a result
+ SMESH_MeshAlgos::TElemIntPairVec new2OldFaces;
+ SMESH_MeshAlgos::TNodeIntPairVec new2OldNodes;
+ TCutFaceMap::const_iterator cutFacesIt= algo.myCutFaces.cbegin();
+ for ( ; cutFacesIt != algo.myCutFaces.cend(); ++cutFacesIt )
+ {
+ const CutFace& cf = *cutFacesIt;
+ if ( cf.myInitFace != faceToCut )
+ continue;
+
+ if ( !cf.IsCut() )
+ {
+ theNewFaceConnectivity.push_back( facePoints );
+ break;
+ }
+ // form loops of new faces
+ EdgeLoopSet loopSet;
+ cf.MakeLoops( loopSet, normals[ faceToCut->GetID() ]);
+
+ // erase loops that are cut off by thePlanes
+ const double sign = 1;
+ std::vector< EdgePart > cutOffLinks;
+ TLinkMap cutOffCoplanarLinks;
+ cf.CutOffLoops( loopSet, sign, normals, cutOffLinks, cutOffCoplanarLinks );
+
+ for ( size_t iL = 0; iL < loopSet.myNbLoops; ++iL )
+ {
+ EdgeLoop& loop = loopSet.myLoops[ iL ];
+ if ( loop.myLinks.size() > 0 )
+ {
+ facePoints.clear();
+ for ( SMDS_NodeIteratorPtr nIt = loop.nodeIterator(); nIt->more(); )
+ {
+ const SMDS_MeshNode* n = nIt->next();
+ facePoints.push_back( n );
+ int iN = faceToCut->GetNodeIndex( n );
+ if ( iN < 0 )
+ facePoints.back()._node = 0; // an intersection point
+ else
+ facePoints.back()._node = theFace->GetNode( iN );
+ }
+ theNewFaceConnectivity.push_back( facePoints );
+ }
+ }
+ break;
+ }
+
+ return theNewFaceConnectivity.empty();
+ }
+
+} // namespace SMESH_MeshAlgos
+
+namespace
+{
//================================================================================
/*!
* \brief Debug
bool replaced = false;
for ( size_t i = 0; i < myLinks.size(); ++i )
{
- while ( theRm2KeepMap.IsBound((Standard_Address) myLinks[i].myNode1 ))
- replaced = ( myLinks[i].myNode1 = theRm2KeepMap((Standard_Address) myLinks[i].myNode1 ));
+ while ( theRm2KeepMap.IsBound( myLinks[i].myNode1 ))
+ replaced = ( myLinks[i].myNode1 = theRm2KeepMap( myLinks[i].myNode1 ));
- while ( theRm2KeepMap.IsBound((Standard_Address) myLinks[i].myNode2 ))
- replaced = ( myLinks[i].myNode2 = theRm2KeepMap((Standard_Address) myLinks[i].myNode2 ));
+ while ( theRm2KeepMap.IsBound( myLinks[i].myNode2 ))
+ replaced = ( myLinks[i].myNode2 = theRm2KeepMap( myLinks[i].myNode2 ));
}
//if ( replaced ) // remove equal links
//================================================================================
/*!
- * \brief Replace _COPLANAR cut edge by _INTERNAL oe vice versa
+ * \brief Replace _COPLANAR cut edge by _INTERNAL or vice versa
*/
//================================================================================
/*!
* \brief Create an offsetMesh of given faces
* \param [in] faceIt - the input faces
- * \param [out] new2OldFaces - history of faces
- * \param [out] new2OldNodes - history of nodes
+ * \param [out] new2OldFaces - history of faces (new face -> old face ID)
+ * \param [out] new2OldNodes - history of nodes (new node -> old node ID)
* \return SMDS_Mesh* - the new offset mesh, a caller should delete
*/
//================================================================================
SMDS_Mesh& theSrcMesh,
const double theOffset,
const bool theFixIntersections,
- TEPairVec& theNew2OldFaces,
- TNPairVec& theNew2OldNodes)
+ TElemIntPairVec& theNew2OldFaces,
+ TNodeIntPairVec& theNew2OldNodes)
{
if ( theSrcMesh.GetMeshInfo().NbFaces( ORDER_QUADRATIC ) > 0 )
throw SALOME_Exception( "Offset of quadratic mesh not supported" );
theNew2OldFaces.clear();
theNew2OldNodes.clear();
theNew2OldFaces.push_back
- ( std::make_pair(( const SMDS_MeshElement*) 0,
- ( const SMDS_MeshElement*) 0)); // to have index == face->GetID()
+ ( std::make_pair(( const SMDS_MeshElement*) 0, 0)); // to have index == face->GetID()
// copy input faces to the newMesh keeping IDs of nodes
{
SMESH_NodeXYZ xyz( nodes[i] );
newNode = newMesh->AddNodeWithID( xyz.X(), xyz.Y(), xyz.Z(), nodes[i]->GetID() );
- theNew2OldNodes.push_back( std::make_pair( newNode, nodes[i] ));
+ theNew2OldNodes.push_back( std::make_pair( newNode, nodes[i]->GetID() ));
nodes[i] = newNode;
}
}
default:
continue;
}
- theNew2OldFaces.push_back( std::make_pair( newFace, face ));
+ theNew2OldFaces.push_back( std::make_pair( newFace, face->GetID() ));
SMESH_NodeXYZ pPrev = nodes.back(), p;
for ( size_t i = 0; i < nodes.size(); ++i )
std::vector< gp_XYZ > normals( theNew2OldFaces.size() );
for ( size_t i = 1; i < normals.size(); ++i )
{
- if ( !SMESH_MeshAlgos::FaceNormal( theNew2OldFaces[i].second, normals[i] ))
+ if ( !SMESH_MeshAlgos::FaceNormal( theNew2OldFaces[i].first, normals[i] ))
normals[i].SetCoord( 0,0,0 ); // TODO find norm by neighbors
}
{
newNode = newMesh->AddNode( newXYZ.X(), newXYZ.Y(), newXYZ.Z() );
newNode->setIsMarked( true );
- theNew2OldNodes.push_back( std::make_pair( newNode, theNew2OldNodes[i].second ));
+ theNew2OldNodes.push_back( std::make_pair( newNode, 0 ));
multiPos.emplace_back( newNode );
}
}
--- /dev/null
+// Copyright (C) 2018 OPEN CASCADE
+//
+// 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, or (at your option) any later version.
+//
+// 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
+//
+// File : SMESH_PolyLine.cxx
+// Created : Thu Dec 6 17:33:26 2018
+// Author : Edward AGAPOV (eap)
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include "SMDS_MeshGroup.hxx"
+#include "SMDS_LinearEdge.hxx"
+#include "SMDS_Mesh.hxx"
+#include "SMESH_TryCatch.hxx"
+
+#include <OSD_Parallel.hxx>
+#include <Precision.hxx>
+
+namespace
+{
+ //================================================================================
+ /*!
+ * \brief Sequence of found points and a current point data
+ */
+ struct Path
+ {
+ std::vector< gp_XYZ > myPoints;
+ double myLength;
+
+ const SMDS_MeshElement* myFace;
+ SMESH_NodeXYZ myNode1; // nodes of the edge the path entered myFace
+ SMESH_NodeXYZ myNode2;
+ int myNodeInd1;
+ int myNodeInd2;
+ double myDot1;
+ double myDot2;
+
+ int mySrcPntInd; //!< start point index
+ TIDSortedElemSet myElemSet, myAvoidSet;
+
+ Path(): myLength(0.0), myFace(0) {}
+
+ bool SetCutAtCorner( const SMESH_NodeXYZ& cornerNode,
+ const SMDS_MeshElement* face,
+ const gp_XYZ& plnNorm,
+ const gp_XYZ& plnOrig );
+
+ void AddPoint( const gp_XYZ& p );
+
+ bool Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig );
+
+ bool ReachSamePoint( const Path& other );
+
+ static void Remove( std::vector< Path > & paths, size_t& i );
+ };
+
+ //================================================================================
+ /*!
+ * \brief Return true if this Path meats another
+ */
+ //================================================================================
+
+ bool Path::ReachSamePoint( const Path& other )
+ {
+ return ( mySrcPntInd != other.mySrcPntInd &&
+ myFace == other.myFace );
+ }
+
+ //================================================================================
+ /*!
+ * \brief Remove a path from a vector
+ */
+ //================================================================================
+
+ void Path::Remove( std::vector< Path > & paths, size_t& i )
+ {
+ if ( paths.size() > 1 )
+ {
+ size_t j = paths.size() - 1; // last item to be removed
+ if ( i < j )
+ {
+ paths[ i ].myPoints.swap( paths[ j ].myPoints );
+ paths[ i ].myLength = paths[ j ].myLength;
+ paths[ i ].mySrcPntInd = paths[ j ].mySrcPntInd;
+ paths[ i ].myFace = paths[ j ].myFace;
+ paths[ i ].myNode1 = paths[ j ].myNode1;
+ paths[ i ].myNode2 = paths[ j ].myNode2;
+ paths[ i ].myNodeInd1 = paths[ j ].myNodeInd1;
+ paths[ i ].myNodeInd2 = paths[ j ].myNodeInd2;
+ paths[ i ].myDot1 = paths[ j ].myDot1;
+ paths[ i ].myDot2 = paths[ j ].myDot2;
+ }
+ }
+ paths.pop_back();
+ if ( i > 0 )
+ --i;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Store a point that is at a node of a face if the face is intersected by plane.
+ * Return false if the node is a sole intersection point of the face and the plane
+ */
+ //================================================================================
+
+ bool Path::SetCutAtCorner( const SMESH_NodeXYZ& cornerNode,
+ const SMDS_MeshElement* face,
+ const gp_XYZ& plnNorm,
+ const gp_XYZ& plnOrig )
+ {
+ if ( face == myFace )
+ return false;
+ myNodeInd1 = face->GetNodeIndex( cornerNode._node );
+ myNodeInd2 = ( myNodeInd1 + 1 ) % face->NbCornerNodes();
+ int ind3 = ( myNodeInd1 + 2 ) % face->NbCornerNodes();
+ myNode1.Set( face->GetNode( ind3 ));
+ myNode2.Set( face->GetNode( myNodeInd2 ));
+
+ myDot1 = plnNorm * ( myNode1 - plnOrig );
+ myDot2 = plnNorm * ( myNode2 - plnOrig );
+
+ bool ok = ( myDot1 * myDot2 < 0 );
+ if ( !ok && myDot1 * myDot2 == 0 )
+ {
+ ok = ( myDot1 != myDot2 );
+ if ( ok && myFace )
+ ok = ( myFace->GetNodeIndex(( myDot1 == 0 ? myNode1 : myNode2 )._node ) < 0 );
+ }
+ if ( ok )
+ {
+ myFace = face;
+ myDot1 = 0;
+ AddPoint( cornerNode );
+ }
+ return ok;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Store a point and update myLength
+ */
+ //================================================================================
+
+ void Path::AddPoint( const gp_XYZ& p )
+ {
+ if ( !myPoints.empty() )
+ myLength += ( p - myPoints.back() ).Modulus();
+ else
+ myLength = 0;
+ myPoints.push_back( p );
+ }
+
+ //================================================================================
+ /*!
+ * \brief Try to find the next point
+ * \param [in] plnNorm - cutting plane normal
+ * \param [in] plnOrig - cutting plane origin
+ */
+ //================================================================================
+
+ bool Path::Extend( const gp_XYZ& plnNorm, const gp_XYZ& plnOrig )
+ {
+ int nodeInd3 = ( myNodeInd1 + 1 ) % myFace->NbCornerNodes();
+ if ( myNodeInd2 == nodeInd3 )
+ nodeInd3 = ( myNodeInd1 + 2 ) % myFace->NbCornerNodes();
+
+ SMESH_NodeXYZ node3 = myFace->GetNode( nodeInd3 );
+ double dot3 = plnNorm * ( node3 - plnOrig );
+
+ if ( dot3 * myDot1 < 0. )
+ {
+ myNode2 = node3;
+ myNodeInd2 = nodeInd3;
+ myDot2 = dot3;
+ }
+ else if ( dot3 * myDot2 < 0. )
+ {
+ myNode1 = node3;
+ myNodeInd1 = nodeInd3;
+ myDot1 = dot3;
+ }
+ else if ( dot3 == 0. )
+ {
+ SMDS_ElemIteratorPtr fIt = node3._node->GetInverseElementIterator(SMDSAbs_Face);
+ while ( fIt->more() )
+ if ( SetCutAtCorner( node3, fIt->next(), plnNorm, plnOrig ))
+ return true;
+ return false;
+ }
+ else if ( myDot2 == 0. )
+ {
+ SMESH_NodeXYZ node2 = myNode2; // copy as myNode2 changes in SetCutAtCorner()
+ SMDS_ElemIteratorPtr fIt = node2._node->GetInverseElementIterator(SMDSAbs_Face);
+ while ( fIt->more() )
+ if ( SetCutAtCorner( node2, fIt->next(), plnNorm, plnOrig ))
+ return true;
+ return false;
+ }
+
+ double r = Abs( myDot1 / ( myDot2 - myDot1 ));
+ AddPoint( myNode1 * ( 1 - r ) + myNode2 * r );
+
+ myAvoidSet.clear();
+ myAvoidSet.insert( myFace );
+ myFace = SMESH_MeshAlgos::FindFaceInSet( myNode1._node, myNode2._node,
+ myElemSet, myAvoidSet,
+ &myNodeInd1, &myNodeInd2 );
+ return myFace;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Compute a path between two points of PolySegment
+ */
+ struct PolyPathCompute
+ {
+ SMESH_MeshAlgos::TListOfPolySegments& mySegments; //!< inout PolySegment's
+ std::vector< Path >& myPaths; //!< path of each of segments to compute
+ SMDS_Mesh* myMesh;
+ mutable std::vector< std::string > myErrors;
+
+ PolyPathCompute( SMESH_MeshAlgos::TListOfPolySegments& theSegments,
+ std::vector< Path >& thePaths,
+ SMDS_Mesh* theMesh):
+ mySegments( theSegments ),
+ myPaths( thePaths ),
+ myMesh( theMesh ),
+ myErrors( theSegments.size() )
+ {
+ }
+
+#undef SMESH_CAUGHT
+#define SMESH_CAUGHT myErrors[i] =
+ void operator() ( const int i ) const
+ {
+ SMESH_TRY;
+ const_cast< PolyPathCompute* >( this )->Compute( i );
+ SMESH_CATCH( SMESH::returnError );
+ }
+#undef SMESH_CAUGHT
+
+ //================================================================================
+ /*!
+ * \brief Compute a path of a given segment
+ */
+ //================================================================================
+
+ void Compute( const int iSeg )
+ {
+ SMESH_MeshAlgos::PolySegment& polySeg = mySegments[ iSeg ];
+
+ // the cutting plane
+ gp_XYZ plnNorm = ( polySeg.myXYZ[0] - polySeg.myXYZ[1] ) ^ polySeg.myVector.XYZ();
+ gp_XYZ plnOrig = polySeg.myXYZ[1];
+
+ // Find paths connecting the 2 end points of polySeg
+
+ std::vector< Path > paths; paths.reserve(10);
+
+ // 1) initialize paths; two paths starts at each end point
+
+ for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points
+ {
+ Path path;
+ path.mySrcPntInd = iP;
+ size_t nbPaths = paths.size();
+
+ if ( polySeg.myFace[ iP ]) // the end point lies on polySeg.myFace[ iP ]
+ {
+ // check coincidence of polySeg.myXYZ[ iP ] with nodes
+ const double tol = 1e-20;
+ SMESH_NodeXYZ nodes[4];
+ for ( int i = 0; i < 3 && !polySeg.myNode1[ iP ]; ++i )
+ {
+ nodes[ i ] = polySeg.myFace[ iP ]->GetNode( i );
+ if (( nodes[ i ] - polySeg.myXYZ[ iP ]).SquareModulus() < tol*tol )
+ polySeg.myNode1[ iP ] = nodes[ i ].Node();
+ }
+ nodes[ 3 ] = nodes[ 0 ];
+
+ // check coincidence of polySeg.myXYZ[ iP ] with edges
+ for ( int i = 0; i < 3 && !polySeg.myNode1[ iP ]; ++i )
+ {
+ SMDS_LinearEdge edge( nodes[i].Node(), nodes[i+1].Node() );
+ if ( SMESH_MeshAlgos::GetDistance( &edge, polySeg.myXYZ[ iP ]) < tol )
+ {
+ polySeg.myNode1[ iP ] = nodes[ i ].Node();
+ polySeg.myNode2[ iP ] = nodes[ i + 1 ].Node();
+ }
+ }
+
+ if ( !polySeg.myNode1[ iP ] ) // polySeg.myXYZ[ iP ] is within polySeg.myFace[ iP ]
+ {
+ double dot[ 4 ];
+ for ( int i = 0; i < 3; ++i )
+ dot[ i ] = plnNorm * ( nodes[ i ] - plnOrig );
+ dot[ 3 ] = dot[ 0 ];
+
+ int iCut = 0; // index of a cut edge
+ if ( dot[ 1 ] * dot[ 2 ] < 0. ) iCut = 1;
+ else if ( dot[ 2 ] * dot[ 3 ] < 0. ) iCut = 2;
+
+ // initialize path so as if it entered the face via iCut-th edge
+ path.myFace = polySeg.myFace[ iP ];
+ path.myNodeInd1 = iCut;
+ path.myNodeInd2 = iCut + 1;
+ path.myNode1.Set( nodes[ iCut ].Node() );
+ path.myNode2.Set( nodes[ iCut + 1 ].Node() );
+ path.myDot1 = dot[ iCut ];
+ path.myDot2 = dot[ iCut + 1 ];
+ path.myPoints.clear();
+ path.AddPoint( polySeg.myXYZ[ iP ]);
+ paths.push_back( path );
+
+ path.Extend( plnNorm, plnOrig ); // to get another edge cut
+ path.myFace = polySeg.myFace[ iP ];
+ if ( path.myDot1 == 0. ) // cut at a node
+ {
+ path.myNodeInd1 = ( iCut + 2 ) % 3;
+ path.myNodeInd2 = ( iCut + 3 ) % 3;
+ path.myNode2.Set( path.myFace->GetNode( path.myNodeInd2 ));
+ path.myDot2 = dot[ path.myNodeInd2 ];
+ }
+ else
+ {
+ path.myNodeInd1 = path.myFace->GetNodeIndex( path.myNode1.Node() );
+ path.myNodeInd2 = path.myFace->GetNodeIndex( path.myNode2.Node() );
+ }
+ path.myPoints.clear();
+ path.AddPoint( polySeg.myXYZ[ iP ]);
+ paths.push_back( path );
+ }
+ }
+
+ if ( polySeg.myNode2[ iP ] && polySeg.myNode2[ iP ] != polySeg.myNode1[ iP ] )
+ {
+ // the end point is on an edge
+ while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ],
+ polySeg.myNode2[ iP ],
+ path.myElemSet,
+ path.myAvoidSet,
+ &path.myNodeInd1,
+ &path.myNodeInd2 )))
+ {
+ path.myNode1.Set( polySeg.myNode1[ iP ]);
+ path.myNode2.Set( polySeg.myNode2[ iP ]);
+ path.myDot1 = plnNorm * ( path.myNode1 - plnOrig );
+ path.myDot2 = plnNorm * ( path.myNode2 - plnOrig );
+ path.myPoints.clear();
+ path.AddPoint( polySeg.myXYZ[ iP ]);
+ path.myAvoidSet.insert( path.myFace );
+ paths.push_back( path );
+ }
+ if ( nbPaths == paths.size() )
+ throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1
+ << " in a PolySegment " << iSeg );
+ }
+ else if ( polySeg.myNode1[ iP ] ) // the end point is at a node
+ {
+ std::set<const SMDS_MeshNode* > nodes;
+ SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face);
+ while ( fIt->more() )
+ {
+ path.myPoints.clear();
+ if ( path.SetCutAtCorner( polySeg.myNode1[ iP ], fIt->next(), plnNorm, plnOrig ))
+ {
+ if (( path.myDot1 * path.myDot2 != 0 ) ||
+ ( nodes.insert( path.myDot1 == 0 ? path.myNode1._node : path.myNode2._node ).second ))
+ paths.push_back( path );
+ }
+ }
+ }
+
+ // look for a one-segment path
+ for ( size_t i = 0; i < nbPaths; ++i )
+ for ( size_t j = nbPaths; j < paths.size(); ++j )
+ if ( paths[i].myFace == paths[j].myFace )
+ {
+ myPaths[ iSeg ].myPoints.push_back( paths[i].myPoints[0] );
+ myPaths[ iSeg ].myPoints.push_back( paths[j].myPoints[0] );
+ paths.clear();
+ }
+ }
+
+ // 2) extend paths and compose the shortest one connecting the two points
+
+ myPaths[ iSeg ].myLength = 1e100;
+
+ while ( paths.size() >= 2 )
+ {
+ for ( size_t i = 0; i < paths.size(); ++i )
+ {
+ Path& path = paths[ i ];
+ if ( !path.Extend( plnNorm, plnOrig ) || // path reached a mesh boundary
+ path.myLength > myPaths[ iSeg ].myLength ) // path is longer than others
+ {
+ Path::Remove( paths, i );
+ continue;
+ }
+
+ // join paths that reach same point
+ for ( size_t j = 0; j < paths.size(); ++j )
+ {
+ if ( i != j && paths[i].ReachSamePoint( paths[j] ))
+ {
+ double distLast = ( paths[i].myPoints.back() - paths[j].myPoints.back() ).Modulus();
+ double fullLength = ( paths[i].myLength + paths[j].myLength + distLast );
+ if ( fullLength < myPaths[ iSeg ].myLength )
+ {
+ myPaths[ iSeg ].myLength = fullLength;
+ std::vector< gp_XYZ > & allPoints = myPaths[ iSeg ].myPoints;
+ allPoints.swap( paths[i].myPoints );
+ allPoints.insert( allPoints.end(),
+ paths[j].myPoints.rbegin(),
+ paths[j].myPoints.rend() );
+ }
+ Path::Remove( paths, i );
+ Path::Remove( paths, j );
+ }
+ }
+ }
+ if ( !paths.empty() && (int) paths[0].myPoints.size() > myMesh->NbFaces() )
+ throw SALOME_Exception(LOCALIZED( "Infinite loop in MakePolyLine()"));
+ }
+
+ if ( myPaths[ iSeg ].myPoints.empty() )
+ throw SALOME_Exception( SMESH_Comment("Can't find a full path for PolySegment #") << iSeg );
+
+ // reverse the path
+ double d00 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.front() ).SquareModulus();
+ double d01 = ( polySeg.myXYZ[0] - myPaths[ iSeg ].myPoints.back() ).SquareModulus();
+ if ( d00 > d01 )
+ std::reverse( myPaths[ iSeg ].myPoints.begin(), myPaths[ iSeg ].myPoints.end() );
+
+ } // PolyPathCompute::Compute()
+
+ }; // struct PolyPathCompute
+
+} // namespace
+
+//=======================================================================
+//function : MakePolyLine
+//purpose : Create a polyline consisting of 1D mesh elements each lying on a 2D element of
+// the initial mesh
+//=======================================================================
+
+void SMESH_MeshAlgos::MakePolyLine( SMDS_Mesh* theMesh,
+ TListOfPolySegments& theSegments,
+ std::vector<const SMDS_MeshElement*>& theNewEdges,
+ std::vector< const SMDS_MeshNode* >& theNewNodes,
+ SMDS_MeshGroup* theGroup,
+ SMESH_ElementSearcher* theSearcher)
+{
+ std::vector< Path > segPaths( theSegments.size() ); // path of each of segments
+
+ SMESH_ElementSearcher* searcher = theSearcher;
+ SMESHUtils::Deleter<SMESH_ElementSearcher> delSearcher;
+ if ( !searcher )
+ {
+ searcher = SMESH_MeshAlgos::GetElementSearcher( *theMesh );
+ delSearcher._obj = searcher;
+ }
+
+ // get cutting planes
+
+ std::vector< bool > isVectorOK( theSegments.size(), true );
+ const double planarCoef = 0.333; // plane height in planar case
+
+ for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
+ {
+ PolySegment& polySeg = theSegments[ iSeg ];
+
+ gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] );
+ gp_XYZ p2 = SMESH_NodeXYZ( polySeg.myNode1[1] );
+ if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] ));
+ if ( polySeg.myNode2[1] ) p2 = 0.5 * ( p2 + SMESH_NodeXYZ( polySeg.myNode2[1] ));
+
+ polySeg.myFace[0] = polySeg.myFace[1] = 0;
+ if ( !polySeg.myNode1[0] && !polySeg.myNode2[0] )
+ {
+ p1 = searcher->Project( polySeg.myXYZ[0], SMDSAbs_Face, &polySeg.myFace[0] );
+ }
+ if ( !polySeg.myNode1[1] && !polySeg.myNode2[1] )
+ {
+ p2 = searcher->Project( polySeg.myXYZ[1], SMDSAbs_Face, &polySeg.myFace[1] );
+ }
+ polySeg.myXYZ[0] = p1;
+ polySeg.myXYZ[1] = p2;
+
+ gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
+
+ isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits<double>::min() );
+ if ( !isVectorOK[ iSeg ])
+ {
+ gp_XYZ pMid = 0.5 * ( p1 + p2 );
+ const SMDS_MeshElement* face;
+ polySeg.myMidProjPoint = searcher->Project( pMid, SMDSAbs_Face, &face );
+ polySeg.myVector = polySeg.myMidProjPoint.XYZ() - pMid;
+
+ gp_XYZ faceNorm;
+ SMESH_MeshAlgos::FaceNormal( face, faceNorm );
+
+ if ( polySeg.myVector.Magnitude() < Precision::Confusion() ||
+ polySeg.myVector * faceNorm < Precision::Confusion() )
+ {
+ polySeg.myVector = faceNorm;
+ polySeg.myMidProjPoint = pMid + faceNorm * ( p1 - p2 ).Modulus() * planarCoef;
+ }
+ }
+ else
+ {
+ polySeg.myVector = plnNorm ^ ( p1 - p2 );
+ }
+ }
+
+ // assure that inverse elements are constructed, avoid their concurrent building in threads
+ theMesh->nodesIterator()->next()->NbInverseElements();
+
+ // find paths
+
+ PolyPathCompute algo( theSegments, segPaths, theMesh );
+ OSD_Parallel::For( 0, theSegments.size(), algo, theSegments.size() == 1 );
+
+ for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
+ if ( !algo.myErrors[ iSeg ].empty() )
+ throw SALOME_Exception( algo.myErrors[ iSeg ].c_str() );
+
+ // create an 1D mesh
+
+ const SMDS_MeshNode *n, *nPrev = 0;
+
+ for ( size_t iSeg = 0; iSeg < theSegments.size(); ++iSeg )
+ {
+ const Path& path = segPaths[iSeg];
+ if ( path.myPoints.size() < 2 )
+ continue;
+
+ double tol = path.myLength / path.myPoints.size() / 1000.;
+ if ( !nPrev || ( SMESH_NodeXYZ( nPrev ) - path.myPoints[0] ).SquareModulus() > tol*tol )
+ {
+ nPrev = theMesh->AddNode( path.myPoints[0].X(), path.myPoints[0].Y(), path.myPoints[0].Z() );
+ theNewNodes.push_back( nPrev );
+ }
+ for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
+ {
+ n = theMesh->AddNode( path.myPoints[iP].X(), path.myPoints[iP].Y(), path.myPoints[iP].Z() );
+ theNewNodes.push_back( n );
+
+ const SMDS_MeshElement* elem = theMesh->AddEdge( nPrev, n );
+ theNewEdges.push_back( elem );
+ if ( theGroup )
+ theGroup->Add( elem );
+
+ nPrev = n;
+ }
+
+ // return a vector
+
+ gp_XYZ pMid = 0.5 * ( path.myPoints[0] + path.myPoints.back() );
+ if ( isVectorOK[ iSeg ])
+ {
+ // find the most distant point of a path
+ double maxDist = 0;
+ for ( size_t iP = 1; iP < path.myPoints.size(); ++iP )
+ {
+ double dist = Abs( theSegments[iSeg].myVector * ( path.myPoints[iP] - path.myPoints[0] ));
+ if ( dist > maxDist )
+ {
+ maxDist = dist;
+ theSegments[iSeg].myMidProjPoint = path.myPoints[iP];
+ }
+ }
+ if ( maxDist < Precision::Confusion() ) // planar case
+ theSegments[iSeg].myMidProjPoint =
+ pMid + theSegments[iSeg].myVector.XYZ().Normalized() * path.myLength * planarCoef;
+ }
+ theSegments[iSeg].myVector = gp_Vec( pMid, theSegments[iSeg].myMidProjPoint );
+ }
+
+ return;
+}
--- /dev/null
+// Copyright (C) 2018 OPEN CASCADE
+//
+// 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, or (at your option) any later version.
+//
+// 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
+//
+// File : SMESH_Slot.cxx
+// Created : Fri Nov 30 15:58:37 2018
+// Author : Edward AGAPOV (eap)
+
+#include "SMESH_MeshAlgos.hxx"
+
+#include "ObjectPool.hxx"
+#include "SMDS_LinearEdge.hxx"
+#include "SMDS_Mesh.hxx"
+
+#include <IntAna_IntConicQuad.hxx>
+#include <IntAna_Quadric.hxx>
+#include <NCollection_DataMap.hxx>
+#include <NCollection_Map.hxx>
+#include <Precision.hxx>
+#include <gp_Ax1.hxx>
+#include <gp_Cylinder.hxx>
+#include <gp_Dir.hxx>
+#include <gp_Lin.hxx>
+#include <gp_Pln.hxx>
+#include <gp_Pnt.hxx>
+#include <gp_Vec.hxx>
+
+#include <Utils_SALOME_Exception.hxx>
+
+#include <boost/container/flat_set.hpp>
+
+namespace
+{
+ typedef SMESH_MeshAlgos::Edge TEdge;
+
+ //================================================================================
+ //! point of intersection of a face edge with the cylinder
+ struct IntPoint
+ {
+ SMESH_NodeXYZ myNode; // point and a node
+ int myEdgeIndex; // face edge index
+ bool myIsOutPln[2]; // isOut of two planes
+ };
+
+ //================================================================================
+ //! poly-line segment
+ struct Segment
+ {
+ typedef boost::container::flat_set< const SMDS_MeshNode* > TNodeSet;
+ //typedef std::list< TEdge > TEdgeList;
+
+ const SMDS_MeshElement* myEdge;
+ TNodeSet myEndNodes; // ends of cut edges
+ //TEdgeList myCutEdges[2];
+
+
+ // return its axis
+ gp_Ax1 Ax1( bool reversed = false ) const
+ {
+ SMESH_NodeXYZ n1 = myEdge->GetNode( reversed );
+ SMESH_NodeXYZ n2 = myEdge->GetNode( !reversed );
+ return gp_Ax1( n1, gp_Dir( n2 - n1 ));
+ }
+ // return a node
+ const SMDS_MeshNode* Node(int i) const
+ {
+ return myEdge->GetNode( i % 2 );
+ }
+ // store an intersection edge forming the slot border
+ void AddEdge( TEdge& e, double tol )
+ {
+ const SMDS_MeshNode** nodes = & e._node1;
+ for ( int i = 0; i < 2; ++i )
+ {
+ std::pair< TNodeSet::iterator, bool > nItAdded = myEndNodes.insert( nodes[ i ]);
+ if ( !nItAdded.second )
+ myEndNodes.erase( nItAdded.first );
+ }
+ }
+ // { -- PREV version
+ // int i = myCutEdges[0].empty() ? 0 : 1;
+ // std::insert_iterator< TEdgeList > where = inserter( myCutEdges[i], myCutEdges[i].begin() );
+
+ // //double minDist = 1e100;
+ // SMESH_NodeXYZ nNew[2] = { e._node1, e._node2 };
+ // int iNewMin = 0, iCurMin = 1;
+ // for ( i = 0; i < 2; ++i )
+ // {
+ // if ( myCutEdges[i].empty() )
+ // continue;
+ // SMESH_NodeXYZ nCur[2] = { myCutEdges[i].front()._node1,
+ // myCutEdges[i].back()._node2 };
+ // for ( int iN = 0; iN < 2; ++iN )
+ // for ( int iC = 0; iC < 2; ++iC )
+ // {
+ // if (( nCur[iC].Node() && nCur[iC] == nNew[iN] ) ||
+ // ( nCur[iC] - nNew[iN] ).SquareModulus() < tol * tol )
+ // {
+ // where = inserter( myCutEdges[i], iC ? myCutEdges[i].end() : myCutEdges[i].begin() );
+ // iNewMin = iN;
+ // iCurMin = iC;
+ // //minDist = dist;
+ // iN = 2;
+ // break;
+ // }
+ // }
+ // }
+ // if ( iNewMin == iCurMin )
+ // std::swap( e._node1, e._node2 );
+
+ // where = e;
+ // }
+ Segment( const SMDS_MeshElement* e = 0 ): myEdge(e) { myEndNodes.reserve( 4 ); }
+ };
+ typedef ObjectPoolIterator<Segment> TSegmentIterator;
+
+
+ //================================================================================
+ /*!
+ * \brief Intersect a face edge given by its nodes with a cylinder.
+ */
+ //================================================================================
+
+ void intersectEdge( const gp_Cylinder& cyl,
+ const SMESH_NodeXYZ& n1,
+ const SMESH_NodeXYZ& n2,
+ const double tol,
+ std::vector< IntPoint >& intPoints )
+ {
+ gp_Lin line( gp_Ax1( n1, gp_Dir( n2 - n1 )));
+ IntAna_IntConicQuad intersection( line, IntAna_Quadric( cyl ));
+
+ if ( !intersection.IsDone() ||
+ intersection.IsParallel() ||
+ intersection.IsInQuadric() ||
+ intersection.NbPoints() == 0 )
+ return;
+
+ gp_Vec edge( n1, n2 );
+
+ size_t oldNbPnts = intPoints.size();
+ for ( int iP = 1; iP <= intersection.NbPoints(); ++iP )
+ {
+ const gp_Pnt& p = intersection.Point( iP );
+
+ gp_Vec n1p ( n1, p );
+ const SMDS_MeshNode* n = 0;
+
+ double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
+ if ( u <= 0. ) {
+ if ( p.SquareDistance( n1 ) < tol * tol )
+ n = n1.Node();
+ else
+ continue;
+ }
+ else if ( u >= 1. ) {
+ if ( p.SquareDistance( n2 ) < tol * tol )
+ n = n2.Node();
+ else
+ continue;
+ }
+ else {
+ if ( p.SquareDistance( n1 ) < tol * tol )
+ n = n1.Node();
+ else if ( p.SquareDistance( n2 ) < tol * tol )
+ n = n2.Node();
+ }
+
+ intPoints.push_back( IntPoint() );
+ if ( n )
+ intPoints.back().myNode.Set( n );
+ else
+ intPoints.back().myNode.SetCoord( p.X(),p.Y(),p.Z() );
+ }
+
+ // set points order along an edge
+ if ( intPoints.size() - oldNbPnts == 2 &&
+ intersection.ParamOnConic( 1 ) > intersection.ParamOnConic( 2 ))
+ {
+ int i = intPoints.size() - 1;
+ std::swap( intPoints[ i ], intPoints[ i - 1 ]);
+ }
+
+ return;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return signed distance between a point and a plane
+ */
+ //================================================================================
+
+ double signedDist( const gp_Pnt& p, const gp_Ax1& planeNormal )
+ {
+ const gp_Pnt& O = planeNormal.Location();
+ gp_Vec Op( O, p );
+ return Op * planeNormal.Direction();
+ }
+
+ //================================================================================
+ /*!
+ * \brief Check if a point is outside a segment domain bound by two planes
+ */
+ //================================================================================
+
+ bool isOut( const gp_Pnt& p, const gp_Ax1* planeNormal, bool* isOutPtr )
+ {
+ isOutPtr[0] = isOutPtr[1] = false;
+
+ for ( int i = 0; i < 2; ++i )
+ {
+ isOutPtr[i] = ( signedDist( p, planeNormal[i] ) <= 0. );
+ }
+ return ( isOutPtr[0] && isOutPtr[1] );
+ }
+
+ //================================================================================
+ /*!
+ * \brief Check if a segment between two points is outside a segment domain bound by two planes
+ */
+ //================================================================================
+
+ bool isSegmentOut( bool* isOutPtr1, bool* isOutPtr2 )
+ {
+ return (( isOutPtr1[0] && isOutPtr2[0] ) ||
+ ( isOutPtr1[1] && isOutPtr2[1] ));
+ }
+
+ //================================================================================
+ /*!
+ * \brief cut off ip1 from edge (ip1 - ip2) by a plane
+ */
+ //================================================================================
+
+ void cutOff( IntPoint & ip1, const IntPoint & ip2, const gp_Ax1& planeNormal, double tol )
+ {
+ gp_Lin lin( ip1.myNode, ( ip2.myNode - ip1.myNode ));
+ gp_Pln pln( planeNormal.Location(), planeNormal.Direction() );
+
+ IntAna_IntConicQuad intersection( lin, pln, Precision::Angular/*Tolerance*/() );
+ if ( intersection.IsDone() &&
+ !intersection.IsParallel() &&
+ !intersection.IsInQuadric() &&
+ intersection.NbPoints() == 1 )
+ {
+ if ( intersection.Point( 1 ).SquareDistance( ip1.myNode ) > tol * tol )
+ {
+ static_cast< gp_XYZ& >( ip1.myNode ) = intersection.Point( 1 ).XYZ();
+ ip1.myNode._node = 0;
+ ip1.myEdgeIndex = -1;
+ }
+ }
+ }
+
+ //================================================================================
+ /*!
+ * \brief Assure that face normal is computed in faceNormals vector
+ */
+ //================================================================================
+
+ const gp_XYZ& computeNormal( const SMDS_MeshElement* face,
+ std::vector< gp_XYZ >& faceNormals )
+ {
+ bool toCompute;
+ if ((int) faceNormals.size() <= face->GetID() )
+ {
+ toCompute = true;
+ faceNormals.resize( face->GetID() + 1 );
+ }
+ else
+ {
+ toCompute = faceNormals[ face->GetID() ].SquareModulus() == 0.;
+ }
+ if ( toCompute )
+ SMESH_MeshAlgos::FaceNormal( face, faceNormals[ face->GetID() ], /*normalized=*/false );
+
+ return faceNormals[ face->GetID() ];
+ }
+}
+
+//================================================================================
+/*!
+ * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+ * The slot is consrtucted by cutting faces by cylindrical surfaces made around each segment.
+ * \return Edges located at the slot boundary
+ */
+//================================================================================
+
+std::vector< SMESH_MeshAlgos::Edge >
+SMESH_MeshAlgos::MakeSlot( SMDS_ElemIteratorPtr theSegmentIt,
+ double theWidth,
+ SMDS_Mesh* theMesh)
+{
+ std::vector< Edge > bndEdges;
+
+ if ( !theSegmentIt || !theSegmentIt->more() || !theMesh || theWidth == 0.)
+ return bndEdges;
+
+ // put the input segments to a data map in order to be able finding neighboring ones
+
+ typedef std::vector< Segment* > TSegmentVec;
+ typedef NCollection_DataMap< const SMDS_MeshNode*, TSegmentVec, SMESH_Hasher > TSegmentsOfNode;
+ TSegmentsOfNode segmentsOfNode;
+ ObjectPool< Segment > segmentPool;
+
+ while( theSegmentIt->more() )
+ {
+ const SMDS_MeshElement* edge = theSegmentIt->next();
+ if ( edge->GetType() != SMDSAbs_Edge )
+ throw SALOME_Exception( "A segment is not a mesh edge");
+
+ Segment* segment = segmentPool.getNew();
+ segment->myEdge = edge;
+
+ for ( SMDS_NodeIteratorPtr nIt = edge->nodeIterator(); nIt->more(); )
+ {
+ const SMDS_MeshNode* n = nIt->next();
+ TSegmentVec* segVec = segmentsOfNode.ChangeSeek( n );
+ if ( !segVec )
+ segVec = segmentsOfNode.Bound( n, TSegmentVec() );
+ segVec->reserve(2);
+ segVec->push_back( segment );
+ }
+ }
+
+ // Cut the mesh around the segments
+
+ const double tol = Precision::Confusion();
+ std::vector< gp_XYZ > faceNormals;
+ SMESH_MeshAlgos::Intersector meshIntersector( theMesh, tol, faceNormals );
+ std::unique_ptr< SMESH_ElementSearcher> faceSearcher;
+
+ std::vector< NLink > startEdges;
+ std::vector< const SMDS_MeshNode* > faceNodes(4), edgeNodes(2);
+ std::vector<const SMDS_MeshElement *> faces(2);
+ NCollection_Map<const SMDS_MeshElement*, SMESH_Hasher > checkedFaces;
+ std::vector< IntPoint > intPoints, p(2);
+ std::vector< SMESH_NodeXYZ > facePoints(4);
+ std::vector< Intersector::TFace > cutFacePoints;
+
+ std::vector< gp_Ax1 > planeNormalVec(2);
+ gp_Ax1 * planeNormal = & planeNormalVec[0];
+
+ for ( TSegmentIterator segIt( segmentPool ); segIt.more(); ) // loop on all segments
+ {
+ Segment* segment = const_cast< Segment* >( segIt.next() );
+
+ gp_Lin segLine( segment->Ax1() );
+ gp_Ax3 cylAxis( segLine.Location(), segLine.Direction() );
+ gp_Cylinder segCylinder( cylAxis, 0.5 * theWidth );
+ double radius2( segCylinder.Radius() * segCylinder.Radius() );
+
+ // get normals of planes separating domains of neighboring segments
+ for ( int i = 0; i < 2; ++i ) // loop on 2 segment ends
+ {
+ planeNormal[i] = segment->Ax1(i);
+
+ const SMDS_MeshNode* n = segment->Node( i );
+ const TSegmentVec& segVec = segmentsOfNode( n );
+ for ( size_t iS = 0; iS < segVec.size(); ++iS )
+ {
+ if ( segVec[iS] == segment )
+ continue;
+
+ gp_Ax1 axis2 = segVec[iS]->Ax1();
+ if ( n != segVec[iS]->Node( 1 ))
+ axis2.Reverse(); // along a wire
+
+ planeNormal[i].SetDirection( planeNormal[i].Direction().XYZ() + axis2.Direction().XYZ() );
+ }
+ }
+
+ // we explore faces around a segment starting from face edges;
+ // initialize a list of starting edges
+ startEdges.clear();
+ {
+ // get a face to start searching intersected faces from
+ const SMDS_MeshNode* n0 = segment->Node( 0 );
+ SMDS_ElemIteratorPtr fIt = n0->GetInverseElementIterator( SMDSAbs_Face );
+ const SMDS_MeshElement* face = ( fIt->more() ) ? fIt->next() : 0;
+ if ( !theMesh->Contains( face ))
+ {
+ if ( !faceSearcher )
+ faceSearcher.reset( SMESH_MeshAlgos::GetElementSearcher( *theMesh ));
+ face = faceSearcher->FindClosestTo( SMESH_NodeXYZ( n0 ), SMDSAbs_Face );
+ }
+ // collect face edges
+ int nbNodes = face->NbCornerNodes();
+ faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+ faceNodes.resize( nbNodes + 1 );
+ faceNodes[ nbNodes ] = faceNodes[ 0 ];
+ for ( int i = 0; i < nbNodes; ++i )
+ startEdges.push_back( NLink( faceNodes[i], faceNodes[i+1] ));
+ }
+
+ // intersect faces located around a segment
+ checkedFaces.Clear();
+ while ( !startEdges.empty() )
+ {
+ edgeNodes[0] = startEdges[0].first;
+ edgeNodes[1] = startEdges[0].second;
+
+ theMesh->GetElementsByNodes( edgeNodes, faces, SMDSAbs_Face );
+ for ( size_t iF = 0; iF < faces.size(); ++iF ) // loop on faces sharing a start edge
+ {
+ const SMDS_MeshElement* face = faces[iF];
+ if ( !checkedFaces.Add( face ))
+ continue;
+
+ int nbNodes = face->NbCornerNodes();
+ if ( nbNodes != 3 )
+ throw SALOME_Exception( "MakeSlot() accepts triangles only" );
+ facePoints.assign( face->begin_nodes(), face->end_nodes() );
+ facePoints.resize( nbNodes + 1 );
+ facePoints[ nbNodes ] = facePoints[ 0 ];
+
+ // check if cylinder axis || face
+ const gp_XYZ& faceNorm = computeNormal( face, faceNormals );
+ bool isCylinderOnFace = ( Abs( faceNorm * cylAxis.Direction().XYZ() ) < tol );
+
+ if ( !isCylinderOnFace )
+ {
+ if ( Intersector::CutByPlanes( face, planeNormalVec, tol, cutFacePoints ))
+ continue; // whole face cut off
+ facePoints.swap( cutFacePoints[0] );
+ facePoints.push_back( facePoints[0] );
+ }
+
+ // find intersection points on face edges
+ intPoints.clear();
+ int nbPoints = facePoints.size()-1;
+ int nbFarPoints = 0;
+ for ( int i = 0; i < nbPoints; ++i )
+ {
+ const SMESH_NodeXYZ& n1 = facePoints[i];
+ const SMESH_NodeXYZ& n2 = facePoints[i+1];
+
+ size_t iP = intPoints.size();
+ intersectEdge( segCylinder, n1, n2, tol, intPoints );
+
+ // save edge index
+ if ( isCylinderOnFace )
+ for ( ; iP < intPoints.size(); ++iP )
+ intPoints[ iP ].myEdgeIndex = i;
+ else
+ for ( ; iP < intPoints.size(); ++iP )
+ if ( n1.Node() && n2.Node() )
+ intPoints[ iP ].myEdgeIndex = face->GetNodeIndex( n1.Node() );
+ else
+ intPoints[ iP ].myEdgeIndex = -(i+1);
+
+ nbFarPoints += ( segLine.SquareDistance( n1 ) > radius2 );
+ }
+
+ // feed startEdges
+ if ( nbFarPoints < nbPoints || !intPoints.empty() )
+ for ( int i = 0; i < nbPoints; ++i )
+ {
+ const SMESH_NodeXYZ& n1 = facePoints[i];
+ const SMESH_NodeXYZ& n2 = facePoints[i+1];
+ if ( n1.Node() && n2.Node() )
+ {
+ isOut( n1, planeNormal, p[0].myIsOutPln );
+ isOut( n2, planeNormal, p[1].myIsOutPln );
+ if ( !isSegmentOut( p[0].myIsOutPln, p[1].myIsOutPln ))
+ {
+ startEdges.push_back( NLink( n1.Node(), n2.Node() ));
+ }
+ }
+ }
+
+ if ( intPoints.size() < 2 )
+ continue;
+
+ // classify intPoints by planes
+ for ( size_t i = 0; i < intPoints.size(); ++i )
+ isOut( intPoints[i].myNode, planeNormal, intPoints[i].myIsOutPln );
+
+ // cut the face
+
+ if ( intPoints.size() > 2 )
+ intPoints.push_back( intPoints[0] );
+
+ for ( size_t iE = 1; iE < intPoints.size(); ++iE ) // 2 <= intPoints.size() <= 5
+ {
+ if (( intPoints[iE].myIsOutPln[0] && intPoints[iE].myIsOutPln[1] ) ||
+ ( isSegmentOut( intPoints[iE].myIsOutPln, intPoints[iE-1].myIsOutPln )))
+ continue; // intPoint is out of domain
+
+ // check if a cutting edge connecting two intPoints is on cylinder surface
+ if ( intPoints[iE].myEdgeIndex == intPoints[iE-1].myEdgeIndex )
+ continue; // on same edge
+ if ( intPoints[iE].myNode.Node() &&
+ intPoints[iE].myNode == intPoints[iE-1].myNode ) // coincide
+ continue;
+
+ gp_XYZ edegDir = intPoints[iE].myNode - intPoints[iE-1].myNode;
+
+ bool toCut; // = edegDir.SquareModulus() > tol * tol;
+ if ( intPoints.size() == 2 )
+ toCut = true;
+ else if ( isCylinderOnFace )
+ toCut = cylAxis.Direction().IsParallel( edegDir, tol );
+ else
+ {
+ SMESH_NodeXYZ nBetween;
+ int eInd = intPoints[iE-1].myEdgeIndex;
+ if ( eInd < 0 )
+ nBetween = facePoints[( 1 - (eInd-1)) % nbPoints ];
+ else
+ nBetween = faceNodes[( 1 + eInd ) % nbNodes ];
+ toCut = ( segLine.SquareDistance( nBetween ) > radius2 );
+ }
+ if ( !toCut )
+ continue;
+
+ // limit the edge by planes
+ if ( intPoints[iE].myIsOutPln[0] ||
+ intPoints[iE].myIsOutPln[1] )
+ cutOff( intPoints[iE], intPoints[iE-1],
+ planeNormal[ intPoints[iE].myIsOutPln[1] ], tol );
+
+ if ( intPoints[iE-1].myIsOutPln[0] ||
+ intPoints[iE-1].myIsOutPln[1] )
+ cutOff( intPoints[iE-1], intPoints[iE],
+ planeNormal[ intPoints[iE-1].myIsOutPln[1] ], tol );
+
+ edegDir = intPoints[iE].myNode - intPoints[iE-1].myNode;
+ if ( edegDir.SquareModulus() < tol * tol )
+ continue; // fully cut off
+
+ // face cut
+ meshIntersector.Cut( face,
+ intPoints[iE-1].myNode, intPoints[iE-1].myEdgeIndex,
+ intPoints[iE ].myNode, intPoints[iE ].myEdgeIndex );
+
+ Edge e = { intPoints[iE].myNode.Node(), intPoints[iE-1].myNode.Node(), 0 };
+ segment->AddEdge( e, tol );
+ bndEdges.push_back( e );
+ }
+ } // loop on faces sharing an edge
+
+ startEdges[0] = startEdges.back();
+ startEdges.pop_back();
+
+ } // loop on startEdges
+ } // loop on all input segments
+
+
+ // Make cut at the end of group of segments
+
+ std::vector<const SMDS_MeshElement*> polySegments;
+
+ for ( TSegmentsOfNode::Iterator nSegsIt( segmentsOfNode ); nSegsIt.More(); nSegsIt.Next() )
+ {
+ const TSegmentVec& segVec = nSegsIt.Value();
+ if ( segVec.size() != 1 )
+ continue;
+
+ const Segment* segment = segVec[0];
+ const SMDS_MeshNode* segNode = nSegsIt.Key();
+
+ // find two end nodes of cut edges to make a cut between
+ if ( segment->myEndNodes.size() != 4 )
+ throw SALOME_Exception( "MakeSlot(): too short end edge?" );
+ SMESH_MeshAlgos::PolySegment linkNodes;
+ gp_Ax1 planeNorm = segment->Ax1( segNode != segment->Node(0) );
+ double minDist[2] = { 1e100, 1e100 };
+ Segment::TNodeSet::const_iterator nIt = segment->myEndNodes.begin();
+ for ( ; nIt != segment->myEndNodes.end(); ++nIt )
+ {
+ SMESH_NodeXYZ n = *nIt;
+ double d = Abs( signedDist( n, planeNorm ));
+ double diff1 = minDist[0] - d, diff2 = minDist[1] - d;
+ int i;
+ if ( diff1 > 0 && diff2 > 0 )
+ {
+ i = ( diff1 < diff2 );
+ }
+ else if ( diff1 > 0 )
+ {
+ i = 0;
+ }
+ else if ( diff2 > 0 )
+ {
+ i = 1;
+ }
+ else
+ {
+ continue;
+ }
+ linkNodes.myXYZ[ i ] = n;
+ minDist [ i ] = d;
+ }
+ // for ( int iSide = 0; iSide < 2; ++iSide )
+ // {
+ // if ( segment->myCutEdges[ iSide ].empty() )
+ // throw SALOME_Exception( "MakeSlot(): too short end edge?" );
+ // SMESH_NodeXYZ n1 = segment->myCutEdges[ iSide ].front()._node1;
+ // SMESH_NodeXYZ n2 = segment->myCutEdges[ iSide ].back ()._node2;
+ // double d1 = Abs( signedDist( n1, planeNorm ));
+ // double d2 = Abs( signedDist( n2, planeNorm ));
+ // linkNodes.myXYZ [ iSide ] = ( d1 < d2 ) ? n1 : n2;
+ // linkNodes.myNode1[ iSide ] = linkNodes.myNode2[ iSide ] = 0;
+ // }
+ linkNodes.myVector = planeNorm.Direction() ^ (linkNodes.myXYZ[0] - linkNodes.myXYZ[1]);
+ linkNodes.myNode1[ 0 ] = linkNodes.myNode2[ 0 ] = 0;
+ linkNodes.myNode1[ 1 ] = linkNodes.myNode2[ 1 ] = 0;
+
+ // create segments connecting linkNodes
+ std::vector<const SMDS_MeshElement*> newSegments;
+ std::vector<const SMDS_MeshNode*> newNodes;
+ SMESH_MeshAlgos::TListOfPolySegments polySegs(1, linkNodes);
+ SMESH_MeshAlgos::MakePolyLine( theMesh, polySegs, newSegments, newNodes,
+ /*group=*/0, faceSearcher.get() );
+ // cut faces by newSegments
+ intPoints.resize(2);
+ for ( size_t i = 0; i < newSegments.size(); ++i )
+ {
+ intPoints[0].myNode = edgeNodes[0] = newSegments[i]->GetNode(0);
+ intPoints[1].myNode = edgeNodes[1] = newSegments[i]->GetNode(1);
+
+ // find an underlying face
+ gp_XYZ middle = 0.5 * ( intPoints[0].myNode + intPoints[1].myNode );
+ const SMDS_MeshElement* face = faceSearcher->FindClosestTo( middle, SMDSAbs_Face );
+
+ // find intersected edges of the face
+ int nbNodes = face->NbCornerNodes();
+ faceNodes.assign( face->begin_nodes(), face->end_nodes() );
+ faceNodes.resize( nbNodes + 1 );
+ faceNodes[ nbNodes ] = faceNodes[ 0 ];
+ for ( int iP = 0; iP < 2; ++iP )
+ {
+ intPoints[iP].myEdgeIndex = -1;
+ for ( int iN = 0; iN < nbNodes && intPoints[iP].myEdgeIndex < 0; ++iN )
+ {
+ SMDS_LinearEdge edge( faceNodes[iN], faceNodes[iN+1] );
+ if ( SMESH_MeshAlgos::GetDistance( &edge, intPoints[iP].myNode) < tol )
+ intPoints[iP].myEdgeIndex = iN;
+ }
+ }
+
+
+ // face cut
+ computeNormal( face, faceNormals );
+ meshIntersector.Cut( face,
+ intPoints[0].myNode, intPoints[0].myEdgeIndex,
+ intPoints[1].myNode, intPoints[1].myEdgeIndex );
+
+ Edge e = { intPoints[0].myNode.Node(), intPoints[1].myNode.Node(), 0 };
+ bndEdges.push_back( e );
+
+ // add cut points to an adjacent face at ends of poly-line
+ // if they fall onto face edges
+ if (( i == 0 && intPoints[0].myEdgeIndex >= 0 ) ||
+ ( i == newSegments.size() - 1 && intPoints[1].myEdgeIndex >= 0 ))
+ {
+ for ( int iE = 0; iE < 2; ++iE ) // loop on ends of a new segment
+ {
+ if ( iE ? ( i != newSegments.size() - 1 ) : ( i != 0 ))
+ continue;
+ int iEdge = intPoints[ iE ].myEdgeIndex;
+ edgeNodes[0] = faceNodes[ iEdge ];
+ edgeNodes[1] = faceNodes[ iEdge+1 ];
+ theMesh->GetElementsByNodes( edgeNodes, faces, SMDSAbs_Face );
+ for ( size_t iF = 0; iF < faces.size(); ++iF )
+ if ( faces[iF] != face )
+ {
+ int iN1 = faces[iF]->GetNodeIndex( edgeNodes[0] );
+ int iN2 = faces[iF]->GetNodeIndex( edgeNodes[1] );
+ intPoints[ iE ].myEdgeIndex = Abs( iN1 - iN2 ) == 1 ? Min( iN1, iN2 ) : 2;
+ computeNormal( faces[iF], faceNormals );
+ meshIntersector.Cut( faces[iF],
+ intPoints[iE].myNode, intPoints[iE].myEdgeIndex,
+ intPoints[iE].myNode, intPoints[iE].myEdgeIndex );
+ }
+ }
+ }
+
+ } // loop on newSegments
+
+ polySegments.insert( polySegments.end(), newSegments.begin(), newSegments.end() );
+
+ } // loop on map of input segments
+
+ // actual mesh splitting
+ TElemIntPairVec new2OldFaces;
+ TNodeIntPairVec new2OldNodes;
+ meshIntersector.MakeNewFaces( new2OldFaces, new2OldNodes, /*sign=*/1, /*optimize=*/true );
+
+ // remove poly-line edges
+ for ( size_t i = 0; i < polySegments.size(); ++i )
+ {
+ edgeNodes[0] = polySegments[i]->GetNode(0);
+ edgeNodes[1] = polySegments[i]->GetNode(1);
+
+ theMesh->RemoveFreeElement( polySegments[i] );
+
+ if ( edgeNodes[0]->NbInverseElements() == 0 )
+ theMesh->RemoveNode( edgeNodes[0] );
+ if ( edgeNodes[1]->NbInverseElements() == 0 )
+ theMesh->RemoveNode( edgeNodes[1] );
+ }
+
+ return bndEdges;
+}
#include <Standard_Failure.hxx>
#include <gp_Ax2.hxx>
+#include <boost/container/flat_set.hpp>
+
using namespace SMESH_MeshAlgos;
+namespace
+{
+ struct Node // node of a triangle
+ {
+ size_t _triaIndex; // triangle index == index of the 1st triangle node in triangulation array
+ size_t _nodeIndex; // node index within triangle [0-2]
+
+ //! return node index within the node array
+ size_t Index() const { return _triaIndex + _nodeIndex; }
+
+ //! return local 3-d index [0-2]
+ static size_t ThirdIndex( size_t i1, size_t i2 )
+ {
+ size_t i3 = ( i2 + 1 ) % 3;
+ if ( i3 == i1 )
+ i3 = ( i2 + 2 ) % 3;
+ return i3;
+ }
+ //! return 3-d node index within the node array
+ static size_t ThirdIndex( const Node& n1, const Node& n2 )
+ {
+ return n1._triaIndex + ThirdIndex( n1._nodeIndex, n2._nodeIndex );
+ }
+ bool operator<(const Node& other) const { return _triaIndex < other._triaIndex; }
+ };
+ typedef boost::container::flat_set< Node > TNodeSet;
+
+}
+
+struct Triangulate::Optimizer
+{
+ std::vector< TNodeSet > _nodeUsage; // inclusions of a node in triangles
+
+ //================================================================================
+ /*!
+ * \brief Optimize triangles by edge swapping
+ * \param [inout] nodes - polygon triangulation, i.e. connectivity of all triangles to optimize
+ * \param [in] points - coordinates of nodes of the input polygon
+ * \param [in] nodeIndices - indices of triangulation nodes within the input polygon
+ */
+ //================================================================================
+
+ void optimize( std::vector< const SMDS_MeshNode*>& nodes,
+ std::vector< PolyVertex > & points,
+ std::vector< size_t > & nodeIndices)
+ {
+ // for each node of the polygon, remember triangles using it
+ _nodeUsage.resize( points.size() );
+ for ( size_t i = 0; i < points.size(); ++i ) // clear old data
+ {
+ _nodeUsage[ i ].clear();
+ }
+ for ( size_t i = 0, iTria = 0; i < nodeIndices.size(); ++iTria )
+ {
+ _nodeUsage[ nodeIndices[ i++ ]].insert({ iTria * 3, 0 });
+ _nodeUsage[ nodeIndices[ i++ ]].insert({ iTria * 3, 1 });
+ _nodeUsage[ nodeIndices[ i++ ]].insert({ iTria * 3, 2 });
+ }
+
+ // optimization
+ for ( size_t iTria = 0; iTria < nodeIndices.size(); iTria += 3 )
+ {
+ double badness1 = computeBadness( nodeIndices[ iTria + 0 ],
+ nodeIndices[ iTria + 1 ],
+ nodeIndices[ iTria + 2 ],
+ points );
+ for ( size_t i = 0; i < 3; ++i ) // loop on triangle edges to find a neighbor triangle
+ {
+ size_t i1 = iTria + i; // node index in nodeIndices
+ size_t i2 = iTria + ( i + 1 ) % 3;
+ size_t ind1 = nodeIndices[ i1 ]; // node index in points
+ size_t ind2 = nodeIndices[ i2 ];
+ TNodeSet & usage1 = _nodeUsage[ ind1 ]; // triangles using a node
+ TNodeSet & usage2 = _nodeUsage[ ind2 ];
+ if ( usage1.size() < 2 ||
+ usage2.size() < 2 )
+ continue;
+
+ // look for another triangle using two nodes
+ TNodeSet::iterator usIt1 = usage1.begin();
+ for ( ; usIt1 != usage1.end(); ++usIt1 )
+ {
+ if ( usIt1->_triaIndex == iTria )
+ continue; // current triangle
+ TNodeSet::iterator usIt2 = usage2.find( *usIt1 );
+ if ( usIt2 == usage2.end() )
+ continue; // no common _triaIndex in two usages
+
+ size_t i3 = iTria + ( i + 2 ) % 3;
+ size_t i4 = Node::ThirdIndex( *usIt1, *usIt2 ); // 4th node of quadrangle
+ size_t ind3 = nodeIndices[ i3 ];
+ size_t ind4 = nodeIndices[ i4 ];
+
+ double badness2 = computeBadness( ind2, ind1, ind4, points );
+ double badness3 = computeBadness( ind1, ind4, ind3, points, /*checkArea=*/true );
+ double badness4 = computeBadness( ind2, ind3, ind4, points, /*checkArea=*/true );
+
+ if ( Max( badness1, badness2 ) < Max( badness3, badness4 ))
+ continue;
+
+ // swap edge by modifying nodeIndices
+
+ nodeIndices[ i2 ] = ind4;
+ _nodeUsage[ ind2 ].erase ({ iTria, i2 - iTria });
+ _nodeUsage[ ind4 ].insert({ iTria, i2 - iTria });
+
+ i1 = usIt1->Index();
+ nodeIndices[ i1 ] = ind3;
+ _nodeUsage[ ind1 ].erase ( *usIt1 );
+ _nodeUsage[ ind3 ].insert( *usIt1 );
+
+ --i; // to re-check a current edge
+ badness1 = badness3;
+ break;
+ }
+ }
+ }
+
+ // update nodes by updated nodeIndices
+ for ( size_t i = 0; i < nodeIndices.size(); ++i )
+ nodes[ i ] = points[ nodeIndices[ i ]]._nxyz.Node();
+
+ return;
+ }
+
+ //================================================================================
+ /*!
+ * \brief Return 1./area. Initially: max cos^2 of triangle angles
+ */
+ //================================================================================
+
+ double computeBadness( size_t i1, size_t i2, size_t i3,
+ std::vector< PolyVertex > & points,
+ bool checkArea = false )
+ {
+ //if ( checkArea )
+ {
+ points[ i2 ]._prev = & points[ i1 ];
+ points[ i2 ]._next = & points[ i3 ];
+ double a = points[ i2 ].TriaArea();
+ if ( a < 0 )
+ return std::numeric_limits<double>::max();
+ return 1. / a;
+
+ if ( points[ i2 ].TriaArea() < 0 )
+ return 2;
+ }
+ const gp_XY & p1 = points[ i1 ]._xy;
+ const gp_XY & p2 = points[ i2 ]._xy;
+ const gp_XY & p3 = points[ i3 ]._xy;
+ gp_XY vec[3] = { p2 - p1,
+ p3 - p2,
+ p1 - p3 };
+ double len[3] = { vec[0].SquareModulus(),
+ vec[1].SquareModulus(),
+ vec[2].SquareModulus() };
+ if ( len[0] < gp::Resolution() ||
+ len[1] < gp::Resolution() ||
+ len[2] < gp::Resolution() )
+ return 2;
+
+ double maxCos2 = 0;
+ for ( int i = 0; i < 3; ++i )
+ {
+ int i2 = ( i+1 ) % 3;
+ double dot = -vec[ i ] * vec[ i2 ];
+ if ( dot > 0 )
+ maxCos2 = Max( maxCos2, dot * dot / len[ i ] / len[ i2 ] );
+ }
+ return maxCos2;
+ }
+};
+
//================================================================================
/*!
* \brief Initialization
//================================================================================
void Triangulate::PolyVertex::SetNodeAndNext( const SMDS_MeshNode* n,
- PolyVertex& v )
+ PolyVertex& v,
+ size_t index )
{
_nxyz.Set( n );
_next = &v;
v._prev = this;
+ _index = index;
}
//================================================================================
/*!
*/
//================================================================================
-void Triangulate::PolyVertex::GetTriaNodes( const SMDS_MeshNode** nodes) const
+ void Triangulate::PolyVertex::GetTriaNodes( const SMDS_MeshNode** nodes,
+ size_t* nodeIndices) const
{
nodes[0] = _prev->_nxyz._node;
nodes[1] = this->_nxyz._node;
nodes[2] = _next->_nxyz._node;
+ nodeIndices[0] = _prev->_index;
+ nodeIndices[1] = this->_index;
+ nodeIndices[2] = _next->_index;
}
//================================================================================
gp_XY p = _prev->_xy - v->_xy;
gp_XY t = this->_xy - v->_xy;
gp_XY n = _next->_xy - v->_xy;
- const double tol = -1e-12;
+ const double tol = -1e-7;
return (( p ^ t ) >= tol &&
( t ^ n ) >= tol &&
( n ^ p ) >= tol );
//================================================================================
bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
- const size_t nbNodes )
+ const size_t nbNodes)
{
// connect nodes into a ring
_pv.resize( nbNodes );
for ( size_t i = 1; i < nbNodes; ++i )
- _pv[i-1].SetNodeAndNext( nodes[i-1], _pv[i] );
- _pv[ nbNodes-1 ].SetNodeAndNext( nodes[ nbNodes-1 ], _pv[0] );
+ _pv[i-1].SetNodeAndNext( nodes[i-1], _pv[i], i-1 );
+ _pv[ nbNodes-1 ].SetNodeAndNext( nodes[ nbNodes-1 ], _pv[0], nbNodes-1 );
// get a polygon normal
gp_XYZ normal(0,0,0), p0,v01,v02;
// in a loop, find triangles with positive area and having no vertices inside
int iN = 0, nbTria = nbNodes - 2;
- nodes.reserve( nbTria * 3 );
+ nodes.resize( nbTria * 3 );
+ _nodeIndex.resize( nbTria * 3 );
const double minArea = 1e-6;
PolyVertex* v = &_pv[0], *vi;
int nbVertices = nbNodes, nbBadTria = 0, isGoodTria;
}
if ( isGoodTria )
{
- v->GetTriaNodes( &nodes[ iN ] );
+ v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
iN += 3;
v = v->Delete();
if ( --nbVertices == 3 )
{
// last triangle remains
- v->GetTriaNodes( &nodes[ iN ] );
+ v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
+ if ( _optimizer )
+ _optimizer->optimize( nodes, _pv, _nodeIndex );
return true;
}
nbBadTria = 0;
isGoodTria = v->TriaArea() > minArea;
if ( isGoodTria )
{
- v->GetTriaNodes( &nodes[ iN ] );
+ v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
iN += 3;
v = v->Delete();
if ( --nbVertices == 3 )
{
// last triangle remains
- v->GetTriaNodes( &nodes[ iN ] );
+ v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
return true;
}
nbBadTria = 0;
// add all the rest triangles
while ( nbVertices >= 3 )
{
- v->GetTriaNodes( &nodes[ iN ] );
+ v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
iN += 3;
v = v->Delete();
--nbVertices;
} // triangulate()
+//================================================================================
+/*!
+ * \brief Constructor
+ */
+//================================================================================
+
+Triangulate::Triangulate( bool optimize ): _optimizer(0)
+{
+ if ( optimize )
+ _optimizer = new Optimizer;
+}
+
+//================================================================================
+/*!
+ * \brief Destructor
+ */
+//================================================================================
+
+Triangulate::~Triangulate()
+{
+ delete _optimizer;
+ _optimizer = 0;
+}
+
//================================================================================
/*!
* \brief Return nb triangles in a decomposed mesh face
+++ /dev/null
-// Copyright (C) 2007-2016 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
-//
-// 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, or (at your option) any later version.
-//
-// 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
-//
-// File : SMESH_Triangulate.hxx
-// Created : Thu Jan 18 17:51:34 2018
-// Author : Edward AGAPOV (eap)
-
-
-#ifndef __SMESH_Triangulate_HXX__
-#define __SMESH_Triangulate_HXX__
-
-/*!
- * \brief Divide a mesh face into triangles
- */
-class SMESHUtils_EXPORT SMESH_Triangulate
-{
- public:
-
- static int GetNbTriangles( const SMDS_MeshElement* face );
-
- int GetTriangles( const SMDS_MeshElement* face,
- std::vector< const SMDS_MeshNode*>& nodes);
-
- private:
-
- bool triangulate( std::vector< const SMDS_MeshNode*>& nodes, const size_t nbNodes );
-
- struct PolyVertex;
- std::vector< PolyVertex > _pv;
-};
-
-
-#endif
};
typedef SMESH_TNodeXYZ SMESH_NodeXYZ;
+// --------------------------------------------------------------------------------
+// SMESH_Hasher provide methods needed to put mesh data to NCollection maps
+
+struct SMESH_Hasher
+{
+ static Standard_Integer HashCode(const SMDS_MeshElement* e, const Standard_Integer upper)
+ {
+ return ::HashCode( e->GetID(), upper );
+ }
+ static Standard_Boolean IsEqual( const SMDS_MeshElement* e1, const SMDS_MeshElement* e2 )
+ {
+ return ( e1 == e2 );
+ }
+};
+
//--------------------------------------------------
/*!
* \brief Data of a node generated on FACE boundary
return anArray._retn();
}
+SMESH::long_array*
+Filter_i::
+GetElementsIdFromParts( const ListOfIDSources& theParts )
+{
+ SMESH::long_array_var array = new SMESH::long_array;
+ if ( theParts.length() > 0 && myPredicate )
+ {
+ SMESH_Mesh_ptr mesh = theParts[0]->GetMesh();
+ mesh->Load();
+ const SMDS_Mesh* meshDS = MeshPtr2SMDSMesh( mesh );
+ Controls::Filter::TIdSequence totalSequence;
+ for ( CORBA::ULong i = 0; i < theParts.length(); ++i )
+ {
+ if ( SMESH::Filter_i* filter = SMESH::DownCast<SMESH::Filter_i*>( theParts[i] ))
+ filter->SetMesh( mesh );
+ SMDS_ElemIteratorPtr iter = SMESH_Mesh_i::GetElements( theParts[i], GetElementType() );
+ if ( iter && meshDS )
+ {
+ Controls::Filter::TIdSequence sequence;
+ Controls::Filter::GetElementsId( meshDS, myPredicate->GetPredicate(), sequence, iter );
+ totalSequence.insert( totalSequence.end(), sequence.begin(), sequence.end() );
+ }
+ }
+ array->length( totalSequence.size() );
+ for ( size_t i = 0; i < totalSequence.size(); ++i )
+ array[ i ] = totalSequence[ i ];
+ }
+ return array._retn();
+}
+
//=============================================================================
/*!
* \brief Returns number of mesh elements per each \a EntityType
GetElementsId( SMESH_Mesh_ptr );
virtual
- ElementType
+ long_array*
+ GetElementsIdFromParts( const ListOfIDSources& theParts );
+
+ virtual
+ ElementType
GetElementType();
virtual
SMESH_Gen_i::Concatenate(const SMESH::ListOfIDSources& theMeshesArray,
CORBA::Boolean theUniteIdenticalGroups,
CORBA::Boolean theMergeNodesAndElements,
- CORBA::Double theMergeTolerance)
+ CORBA::Double theMergeTolerance,
+ SMESH::SMESH_Mesh_ptr theMeshToAppendTo)
throw ( SALOME::SALOME_Exception )
{
return ConcatenateCommon(theMeshesArray,
theUniteIdenticalGroups,
theMergeNodesAndElements,
theMergeTolerance,
- false);
+ false,
+ theMeshToAppendTo);
}
//================================================================================
SMESH_Gen_i::ConcatenateWithGroups(const SMESH::ListOfIDSources& theMeshesArray,
CORBA::Boolean theUniteIdenticalGroups,
CORBA::Boolean theMergeNodesAndElements,
- CORBA::Double theMergeTolerance)
+ CORBA::Double theMergeTolerance,
+ SMESH::SMESH_Mesh_ptr theMeshToAppendTo)
throw ( SALOME::SALOME_Exception )
{
return ConcatenateCommon(theMeshesArray,
theUniteIdenticalGroups,
theMergeNodesAndElements,
theMergeTolerance,
- true);
+ true,
+ theMeshToAppendTo);
}
//================================================================================
CORBA::Boolean theUniteIdenticalGroups,
CORBA::Boolean theMergeNodesAndElements,
CORBA::Double theMergeTolerance,
- CORBA::Boolean theCommonGroups)
+ CORBA::Boolean theCommonGroups,
+ SMESH::SMESH_Mesh_ptr theMeshToAppendTo)
throw ( SALOME::SALOME_Exception )
{
std::unique_ptr< TPythonDump > pPythonDump( new TPythonDump );
TPythonDump& pythonDump = *pPythonDump; // prevent dump of called methods
- // create mesh
- SMESH::SMESH_Mesh_var newMesh = CreateEmptyMesh();
- SMESH_Mesh_i* newImpl = SMESH::DownCast<SMESH_Mesh_i*>( newMesh );
+ // create mesh if theMeshToAppendTo not provided
+ SMESH::SMESH_Mesh_var newMesh;
+ if ( CORBA::is_nil( theMeshToAppendTo ))
+ newMesh = CreateEmptyMesh();
+ else
+ newMesh = SMESH::SMESH_Mesh::_duplicate( theMeshToAppendTo );
+ SMESH_Mesh_i* newImpl = SMESH::DownCast<SMESH_Mesh_i*>( newMesh );
if ( !newImpl ) return newMesh._retn();
+ newImpl->Load();
::SMESH_Mesh& locMesh = newImpl->GetImpl();
SMESHDS_Mesh* newMeshDS = locMesh.GetMeshDS();
SMESH::SMESH_Mesh_var initMesh = theMeshesArray[i]->GetMesh();
SMESH_Mesh_i* initImpl = SMESH::DownCast<SMESH_Mesh_i*>( initMesh );
if ( !initImpl ) continue;
+ if ( initMesh->_is_equivalent( theMeshToAppendTo ))
+ continue;
initImpl->Load();
// assure that IDs increments by one during iteration
// Update Python script
pythonDump << newMesh << " = " << this
- << "." << ( theCommonGroups ? "ConcatenateWithGroups" : "Concatenate" ) << "("
+ << "." << ( theCommonGroups ? "ConcatenateWithGroups" : "Concatenate" ) << "( "
<< theMeshesArray << ", "
<< theUniteIdenticalGroups << ", "
<< theMergeNodesAndElements << ", "
- << TVar( theMergeTolerance ) << ")";
+ << TVar( theMergeTolerance ) << ", "
+ << theMeshToAppendTo << " )";
pPythonDump.reset(); // enable python dump from GetGroups()
CORBA::String_var objStr = GetORB()->object_to_string( grImpl->_this() );
int anId = myStudyContext->findId( string( objStr.in() ) );
char grpName[ 30 ];
- sprintf( grpName, "Group %d", anId );
+ sprintf( grpName, "Group %d %d", anId, grImpl->GetLocalID() );
SMESHDS_GroupBase* aGrpBaseDS = grImpl->GetGroupDS();
aGrpBaseDS->SetStoreName( grpName );
}
// get mesh old id
CORBA::String_var iorString = GetORB()->object_to_string( myNewMeshImpl->_this() );
int newId = myStudyContext->findId( iorString.in() );
- int id = myStudyContext->getOldId( newId );
+ int meshOldId = myStudyContext->getOldId( newId );
// try to find mesh data dataset
if ( aTopGroup->ExistInternalObject( "Has data" ) ) {
aDataset->ReadFromDisk( strHasData );
aDataset->CloseOnDisk();
if ( strcmp( strHasData, "1") == 0 ) {
- // read mesh data from MED file
- // myReader.SetMesh( mySMESHDSMesh );
- // myReader.SetMeshId( id );
- // myReader.Perform();
hasData = true;
}
delete [] strHasData;
// check if it is a group
if ( name_dataset.substr( 0, 5 ) == "Group" ) {
// --> get group id
- int subid = atoi( name_dataset.substr( 5 ).c_str() );
+ char * endptr;
+ int subid = strtol( name_dataset.data() + 5, &endptr, 10 );
if ( subid <= 0 )
continue;
+ int groupID = -1; // group local ID (also persistent)
+ if ( *endptr )
+ groupID = atoi( endptr + 1 );
aDataset = new HDFdataset( name_dataset.c_str(), aGroup );
aDataset->OpenOnDisk();
// Create group servant
SMESH::ElementType type = (SMESH::ElementType)(ii - GetNodeGroupsTag() + 1);
SMESH::SMESH_GroupBase_var aNewGroup = SMESH::SMESH_GroupBase::_duplicate
- ( myNewMeshImpl->createGroup( type, nameFromFile, aShape, predicate ) );
+ ( myNewMeshImpl->createGroup( type, nameFromFile, groupID, aShape, predicate ) );
delete [] nameFromFile;
// Obtain a SMESHDS_Group object
if ( aNewGroup->_is_nil() )
} // reading GROUPs
// instead of reading mesh data, we read only brief information of all
- // objects: mesh, groups, sub-meshes (issue 0021208 )
+ // objects: mesh, groups, sub-meshes (issue 0021208)
if ( hasData )
{
- SMESH_PreMeshInfo::LoadFromFile( myNewMeshImpl, id,
+ SMESH_PreMeshInfo::LoadFromFile( myNewMeshImpl, meshOldId,
meshfile.ToCString(), filename.ToCString(),
!isMultiFile );
}
// Returns errors of hypotheses definition
SMESH::algo_error_array* GetAlgoState( SMESH::SMESH_Mesh_ptr theMesh,
GEOM::GEOM_Object_ptr theSubObject )
- throw ( SALOME::SALOME_Exception );
+ throw ( SALOME::SALOME_Exception );
// Return mesh elements preventing computation of a subshape
SMESH::MeshPreviewStruct* GetBadInputElements( SMESH::SMESH_Mesh_ptr theMesh,
CORBA::Boolean uniteIdenticalGroups,
CORBA::Boolean mergeNodesAndElements,
CORBA::Double mergeTolerance,
- CORBA::Boolean commonGroups)
+ CORBA::Boolean commonGroups,
+ SMESH::SMESH_Mesh_ptr meshToAppendTo)
throw ( SALOME::SALOME_Exception );
// Concatenate the given meshes into one mesh
SMESH::SMESH_Mesh_ptr Concatenate(const SMESH::ListOfIDSources& meshesArray,
CORBA::Boolean uniteIdenticalGroups,
CORBA::Boolean mergeNodesAndElements,
- CORBA::Double mergeTolerance)
+ CORBA::Double mergeTolerance,
+ SMESH::SMESH_Mesh_ptr meshToAppendTo)
throw ( SALOME::SALOME_Exception );
// Concatenate the given meshes into one mesh
SMESH::SMESH_Mesh_ptr ConcatenateWithGroups(const SMESH::ListOfIDSources& meshesArray,
CORBA::Boolean uniteIdenticalGroups,
CORBA::Boolean mergeNodesAndElements,
- CORBA::Double mergeTolerance)
+ CORBA::Double mergeTolerance,
+ SMESH::SMESH_Mesh_ptr meshToAppendTo)
throw ( SALOME::SALOME_Exception );
// Get version of MED format being used.
return true;
}
+static bool getNodeElemDistance (SMESH::Measure& theMeasure,
+ const SMDS_MeshNode* theNode,
+ SMESH_ElementSearcher* theElemSearcher)
+{
+ if ( !theNode || !theElemSearcher )
+ return false;
+
+ const SMDS_MeshElement* closestElement = 0;
+ gp_Pnt point = SMESH_NodeXYZ( theNode );
+ gp_Pnt closestPoint = theElemSearcher->Project( point, SMDSAbs_All, &closestElement );
+
+ if ( closestElement )
+ {
+ theMeasure.value = point.Distance( closestPoint );
+ theMeasure.node1 = theNode->GetID();
+ theMeasure.elem2 = closestElement->GetID();
+ theMeasure.maxX = closestPoint.X();
+ theMeasure.maxY = closestPoint.Y();
+ theMeasure.maxZ = closestPoint.Z();
+ theMeasure.minX = closestPoint.X() - point.X();
+ theMeasure.minY = closestPoint.Y() - point.Y();
+ theMeasure.minZ = closestPoint.Z() - point.Z();
+ }
+
+ return closestElement;
+}
+
static SMESHDS_Mesh* getMesh(SMESH::SMESH_IDSource_ptr theSource)
{
if (!CORBA::is_nil( theSource ))
SMESH::long_array_var aElementsId1 = theSource1->GetIDs();
SMESH::long_array_var aElementsId2;
- if ( !isOrigin ) aElementsId2 = theSource2->GetIDs();
// compute distance between two entities
/* NOTE: currently only node-to-node case is implemented
// node - node
const SMESHDS_Mesh* aMesh1 = getMesh( theSource1 );
const SMESHDS_Mesh* aMesh2 = isOrigin ? 0 : getMesh( theSource2 );
+ if ( !isOrigin ) aElementsId2 = theSource2->GetIDs();
const SMDS_MeshNode* theNode1 = aMesh1 ? aMesh1->FindNode( aElementsId1[0] ) : 0;
const SMDS_MeshNode* theNode2 = aMesh2 ? aMesh2->FindNode( aElementsId2[0] ) : 0;
getNodeNodeDistance( aMeasure, theNode1, theNode2 );
}
+ if (isNode1 && !isNode2 && aElementsId1->length() == 1 )
+ {
+ // node - elements
+ SMESHDS_Mesh* aMesh1 = getMesh( theSource1 );
+ SMESHDS_Mesh* aMesh2 = getMesh( theSource2 );
+ if ( aMesh1 && aMesh2 )
+ {
+ const SMDS_MeshNode* aNode = aMesh1->FindNode( aElementsId1[0] );
+ SMDS_ElemIteratorPtr anElemIt = SMESH_Mesh_i::GetElements( theSource2, SMESH::ALL );
+ std::unique_ptr< SMESH_ElementSearcher > aSearcher
+ ( SMESH_MeshAlgos::GetElementSearcher( *aMesh2, anElemIt ));
+ getNodeElemDistance( aMeasure, aNode, aSearcher.get() );
+ }
+ }
else
{
// NOT_IMPLEMENTED
string getPartIOR( SMESH::SMESH_IDSource_ptr theMeshPart, SMESH::ElementType type = SMESH::ALL )
{
+ if ( SMESH::DownCast<SMESH_Mesh_i*>( theMeshPart ))
+ return "";
string partIOR = SMESH_Gen_i::GetORB()->object_to_string( theMeshPart );
if ( SMESH_Group_i* group_i = SMESH::DownCast<SMESH_Group_i*>( theMeshPart ))
// take into account passible group modification
::SMESH_MeshEditor::TFacetOfElem elemSet;
const int noneFacet = -1;
- SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME );
- while( volIt->more() )
- elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
+ prepareIdSource( elems );
+ if ( SMDS_ElemIteratorPtr volIt = myMesh_i->GetElements( elems, SMESH::VOLUME ))
+ while ( volIt->more() )
+ elemSet.insert( elemSet.end(), make_pair( volIt->next(), noneFacet ));
getEditor().SplitVolumes( elemSet, int( methodFlags ));
declareMeshModified( /*isReComputeSafe=*/true ); // it does not influence Compute()
facetToSplitNormal.PS.y,
facetToSplitNormal.PS.z ));
TIDSortedElemSet elemSet;
+ prepareIdSource( elems );
SMESH::long_array_var anElementsId = elems->GetIDs();
SMDS_MeshElement::GeomFilter filter( SMDSGeom_HEXA );
arrayToSet( anElementsId, getMeshDS(), elemSet, SMDSAbs_Volume, &filter );
TIDSortedElemSet elemsNodes[2];
for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
- SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
- while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+ if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+ while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
}
for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
TIDSortedElemSet elemsNodes[2];
for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
- SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
- while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+ if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+ while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
}
for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
TIDSortedElemSet elemsNodes[2];
for ( int i = 0, nb = theNodes.length(); i < nb; ++i ) {
- SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE );
- while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
+ if ( SMDS_ElemIteratorPtr nIt = myMesh_i->GetElements( theNodes[i], SMESH::NODE ))
+ while ( nIt->more() ) elemsNodes[1].insert( nIt->next() );
}
for ( int i = 0, nb = theEdges.length(); i < nb; ++i )
idSourceToSet( theEdges[i], getMeshDS(), elemsNodes[0], SMDSAbs_Edge );
initData();
TIDSortedNodeSet nodes;
+ prepareIdSource( theObject );
idSourceToNodeSet( theObject, getMeshDS(), nodes );
findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
initData();
TIDSortedNodeSet nodes;
+ prepareIdSource( theObject );
idSourceToNodeSet( theObject, getMeshDS(), nodes );
for ( CORBA::ULong i = 0; i < theExceptSubMeshOrGroups.length(); ++i )
{
- SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
- SMESH::NODE );
- while ( nodeIt->more() )
- nodes.erase( cast2Node( nodeIt->next() ));
+ if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( theExceptSubMeshOrGroups[i],
+ SMESH::NODE ))
+ while ( nodeIt->more() )
+ nodes.erase( cast2Node( nodeIt->next() ));
}
findCoincidentNodes( nodes, theTolerance, theGroupsOfNodes, theSeparateCornersAndMedium );
for ( CORBA::ULong i = 0; i < NodesToKeep.length(); ++i )
{
prepareIdSource( NodesToKeep[i] );
- SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE );
- while ( nodeIt->more() )
- setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
+ if ( SMDS_ElemIteratorPtr nodeIt = myMesh_i->GetElements( NodesToKeep[i], SMESH::NODE ))
+ while ( nodeIt->more() )
+ setOfNodesToKeep.insert( setOfNodesToKeep.end(), cast2Node( nodeIt->next() ));
}
::SMESH_MeshEditor::TListOfListOfNodes aListOfListOfNodes;
initData();
SMESH::SMESH_GroupBase_var group = SMESH::SMESH_GroupBase::_narrow(theObject);
- if ( !(!group->_is_nil() && group->GetType() == SMESH::NODE) )
+ if ( !( !group->_is_nil() && group->GetType() == SMESH::NODE ))
{
TIDSortedElemSet elems;
idSourceToSet( theObject, getMeshDS(), elems, SMDSAbs_All, /*emptyIfIsMesh=*/true);
SMESH_TRY;
SMESH::long_array_var res = new SMESH::long_array;
+ prepareIdSource( elementIDs );
if ( type != SMESH::NODE )
{
SMESH::array_of_ElementType_var types = elementIDs->GetTypes();
type != types[0] ) // but search of elements of dim > 0
return res._retn();
}
+
+ SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
+ SMESH_Mesh_i* mesh_i = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+ if ( mesh_i != myMesh_i )
+ {
+ SMESH::SMESH_MeshEditor_var editor=
+ myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
+ return editor->FindAmongElementsByPoint( elementIDs, x,y,z, type );
+ }
+
if ( SMESH::DownCast<SMESH_Mesh_i*>( elementIDs )) // elementIDs is the whole mesh
return FindElementsByPoint( x,y,z, type );
if ( !theElementSearcher )
{
// create a searcher from elementIDs
- SMESH::SMESH_Mesh_var mesh = elementIDs->GetMesh();
- SMESHDS_Mesh* meshDS = SMESH::DownCast<SMESH_Mesh_i*>( mesh )->GetImpl().GetMeshDS();
-
- if ( !idSourceToSet( elementIDs, meshDS, elements,
- ( type == SMESH::NODE ? SMDSAbs_All : (SMDSAbs_ElementType) type ),
- /*emptyIfIsMesh=*/true))
- return res._retn();
-
- typedef SMDS_SetIterator<const SMDS_MeshElement*, TIDSortedElemSet::const_iterator > TIter;
- SMDS_ElemIteratorPtr elemsIt( new TIter( elements.begin(), elements.end() ));
-
- theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemsIt );
+ SMDS_ElemIteratorPtr elemIt;
+ if ( ! SMESH::DownCast<SMESH_Mesh_i*>( elementIDs ))
+ {
+ //prepareIdSource( elementIDs );
+ elemIt = myMesh_i->GetElements( elementIDs, type );
+ if ( !elemIt )
+ return res._retn();
+ }
+ theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
}
vector< const SMDS_MeshElement* > foundElems;
CORBA::Long SMESH_MeshEditor_i::ProjectPoint(CORBA::Double x,
CORBA::Double y,
CORBA::Double z,
- SMESH::SMESH_IDSource_ptr meshObject,
SMESH::ElementType type,
+ SMESH::SMESH_IDSource_ptr meshObject,
SMESH::double_array_out projecton)
throw (SALOME::SALOME_Exception)
{
{
SMESH::SMESH_MeshEditor_var editor=
myIsPreviewMode ? mesh_i->GetMeshEditPreviewer() : mesh_i->GetMeshEditor();
- return editor->ProjectPoint( x,y,z, meshObject, type, projecton );
+ return editor->ProjectPoint( x,y,z, type, meshObject, projecton );
}
- theSearchersDeleter.Set( myMesh, getPartIOR( meshObject ));
+ theSearchersDeleter.Set( myMesh, getPartIOR( meshObject, type ));
if ( !theElementSearcher )
{
// create a searcher from meshObject
SMDS_ElemIteratorPtr elemIt;
if ( ! SMESH::DownCast<SMESH_Mesh_i*>( meshObject ))
+ {
+ prepareIdSource( meshObject );
elemIt = myMesh_i->GetElements( meshObject, type );
-
+ if ( !elemIt )
+ return -1;
+ }
theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS(), elemIt );
}
return isGoodOri;
}
+//=======================================================================
+//function : Get1DBranches
+//purpose : Partition given 1D elements into groups of contiguous edges.
+// A node where number of meeting edges != 2 is a group end.
+// An optional startNode is used to orient groups it belongs to.
+//return : a list of edge groups and a list of corresponding node groups.
+// If a group is closed, the first and last nodes of the group are same.
+//=======================================================================
+
+SMESH::array_of_long_array*
+SMESH_MeshEditor_i::Get1DBranches( SMESH::SMESH_IDSource_ptr theEdges,
+ CORBA::Long theStartNode,
+ SMESH::array_of_long_array_out theNodeGroups )
+ throw (SALOME::SALOME_Exception)
+{
+ if ( CORBA::is_nil( theEdges ))
+ THROW_SALOME_CORBA_EXCEPTION("Get1DBranches(): NULL group given", SALOME::BAD_PARAM);
+
+ SMESH::array_of_long_array_var edgeGroupArray = new SMESH::array_of_long_array;
+ theNodeGroups = new SMESH::array_of_long_array;
+
+ SMESH_TRY;
+
+ prepareIdSource( theEdges );
+
+ SMESH_MeshAlgos::TElemGroupVector edgeBranches;
+ SMESH_MeshAlgos::TNodeGroupVector nodeBranches;
+ SMESH_MeshAlgos::Get1DBranches( SMESH_Mesh_i::GetElements( theEdges, SMESH::EDGE ),
+ edgeBranches,
+ nodeBranches,
+ getMeshDS()->FindNode( theStartNode ));
+
+ edgeGroupArray->length( edgeBranches.size() );
+ for ( size_t iG = 0; iG < edgeBranches.size(); ++iG )
+ {
+ edgeGroupArray[ iG ].length( edgeBranches[ iG ].size() );
+ for ( size_t i = 0; i < edgeBranches[ iG ].size(); ++i )
+ edgeGroupArray[ iG ][ i ] = edgeBranches[ iG ][ i ]->GetID();
+ }
+
+ theNodeGroups->length( nodeBranches.size() );
+ for ( size_t iG = 0; iG < nodeBranches.size(); ++iG )
+ {
+ theNodeGroups[ iG ].length( nodeBranches[ iG ].size() );
+ for ( size_t i = 0; i < nodeBranches[ iG ].size(); ++i )
+ theNodeGroups[ iG ][ i ] = nodeBranches[ iG ][ i ]->GetID();
+ }
+
+ SMESH_CATCH( SMESH::throwCorbaException );
+
+ return edgeGroupArray._retn();
+}
+
//=======================================================================
//function : FindSharpEdges
//purpose : Return sharp edges of faces and non-manifold ones. Optionally add existing edges.
bool elemsOK;
if ( !( elemsOK = CORBA::is_nil( theObject )))
{
- elemsOK = idSourceToSet( theObject, getMeshDS(), elems,
- SMDSAbs_All, /*emptyIfIsMesh=*/true );
+ elemsOK = idSourceToSet( theObject, getMeshDS(), elems,
+ SMDSAbs_All, /*emptyIfIsMesh=*/true );
}
if ( elemsOK )
{
for ( CORBA::ULong i = 0; i < groups.length(); ++i )
{
SMESH::SMESH_Mesh_var m = groups[i]->GetMesh();
- if ( myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
+ if ( !m->_is_nil() && myMesh_i != SMESH::DownCast<SMESH_Mesh_i*>( m ))
groupsOfOtherMesh[ nbGroupsOfOtherMesh++ ] = groups[i];
else
groupsOfThisMesh[ nbGroups++ ] = groups[i];
}
// convert input polySegments
- ::SMESH_MeshEditor::TListOfPolySegments segments( theSegments.length() );
+ SMESH_MeshAlgos::TListOfPolySegments segments( theSegments.length() );
for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
{
- SMESH::PolySegment& segIn = theSegments[ i ];
- ::SMESH_MeshEditor::PolySegment& segOut = segments[ i ];
+ SMESH::PolySegment& segIn = theSegments[ i ];
+ SMESH_MeshAlgos::PolySegment& segOut = segments[ i ];
segOut.myNode1[0] = meshDS->FindNode( segIn.node1ID1 );
segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 );
segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 );
theElementSearcher = SMESH_MeshAlgos::GetElementSearcher( *getMeshDS() );
// compute
- getEditor().MakePolyLine( segments, groupDS, theElementSearcher );
+ std::vector<const SMDS_MeshElement*> newEdges;
+ std::vector<const SMDS_MeshNode*> newNodes;
+ SMESH_MeshAlgos::MakePolyLine( meshDS, segments, newEdges, newNodes,
+ groupDS ? &groupDS->SMDSGroup() : 0,
+ theElementSearcher );
+
+ const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedElems() ).
+ swap( newEdges );
+ const_cast< SMESH_SequenceOfElemPtr& >( getEditor().GetLastCreatedNodes() ).
+ assign( newNodes.begin(), newNodes.end() );
// return vectors
if ( myIsPreviewMode )
{
for ( CORBA::ULong i = 0; i < theSegments.length(); ++i )
{
- SMESH::PolySegment& segOut = theSegments[ i ];
- ::SMESH_MeshEditor::PolySegment& segIn = segments[ i ];
+ SMESH::PolySegment& segOut = theSegments[ i ];
+ SMESH_MeshAlgos::PolySegment& segIn = segments[ i ];
segOut.vector.PS.x = segIn.myVector.X();
segOut.vector.PS.y = segIn.myVector.Y();
segOut.vector.PS.z = segIn.myVector.Z();
SMESH_CATCH( SMESH::throwCorbaException );
return;
}
+
+//================================================================================
+/*!
+ * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+ * The slot is consrtucted by cutting faces by cylindrical surfaces made
+ * around each segment. Segments are expected to be created by MakePolyLine().
+ * \return Edges located at the slot boundary
+ */
+//================================================================================
+
+SMESH::ListOfEdges* SMESH_MeshEditor_i::MakeSlot(SMESH::SMESH_GroupBase_ptr theSegments,
+ CORBA::Double theWidth)
+ throw (SALOME::SALOME_Exception)
+{
+ if ( CORBA::is_nil( theSegments ) ||
+ theSegments->GetType() != SMESH::EDGE )
+ THROW_SALOME_CORBA_EXCEPTION("No segments given", SALOME::BAD_PARAM );
+ if ( myMesh->NbFaces() == 0 )
+ THROW_SALOME_CORBA_EXCEPTION("No faces in the mesh", SALOME::BAD_PARAM );
+
+ SMESH::ListOfEdges_var resultEdges = new SMESH::ListOfEdges;
+
+ SMESH_TRY;
+ initData(/*deleteSearchers=*/false);
+
+ SMESHDS_Mesh* meshDS = getMeshDS();
+
+ std::vector< SMESH_MeshAlgos::Edge > edges =
+ SMESH_MeshAlgos::MakeSlot( SMESH_Mesh_i::GetElements( theSegments, SMESH::EDGE ),
+ theWidth, meshDS );
+
+ resultEdges->length( edges.size() );
+ for ( size_t i = 0; i < edges.size(); ++i )
+ {
+ resultEdges[ i ].node1 = edges[i]._node1->GetID();
+ resultEdges[ i ].node2 = edges[i]._node2->GetID();
+ resultEdges[ i ].medium = edges[i]._medium ? edges[i]._medium->GetID() : 0;
+ }
+
+ meshDS->Modified();
+ SMESH_CATCH( SMESH::throwCorbaException );
+
+ TSearchersDeleter::Delete(); // face searcher becomes invalid as some faces were removed
+
+ return resultEdges._retn();
+}
CORBA::Long ProjectPoint(CORBA::Double x,
CORBA::Double y,
CORBA::Double z,
- SMESH::SMESH_IDSource_ptr meshObject,
SMESH::ElementType type,
+ SMESH::SMESH_IDSource_ptr meshObject,
SMESH::double_array_out projecton)
throw (SALOME::SALOME_Exception);
CORBA::Boolean IsCoherentOrientation2D()
throw (SALOME::SALOME_Exception);
+ /*!
+ * Partition given 1D elements into groups of contiguous edges.
+ * A node where number of meeting edges != 2 is a group end.
+ * An optional startNode is used to orient groups it belongs to.
+ * \return a list of edge groups and a list of corresponding node groups.
+ * If a group is closed, the first and last nodes of the group are same.
+ */
+ SMESH::array_of_long_array* Get1DBranches( SMESH::SMESH_IDSource_ptr edges,
+ CORBA::Long startNode,
+ SMESH::array_of_long_array_out nodeGroups)
+ throw (SALOME::SALOME_Exception);
+
/*!
* Return sharp edges of faces and non-manifold ones. Optionally adds existing edges.
*/
* be added.
*/
void MakePolyLine(SMESH::ListOfPolySegments& segments,
- const char* groupName)
+ const char* groupName)
+ throw (SALOME::SALOME_Exception);
+
+ /*!
+ * \brief Create a slot of given width around given 1D elements lying on a triangle mesh.
+ * The slot is consrtucted by cutting faces by cylindrical surfaces made
+ * around each segment. Segments are expected to be created by MakePolyLine().
+ * \return Edges located at the slot boundary
+ */
+ SMESH::ListOfEdges* MakeSlot(SMESH::SMESH_GroupBase_ptr segments,
+ CORBA::Double width)
throw (SALOME::SALOME_Exception);
if ( !aShape.IsNull() )
{
aNewGroup =
- SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, aShape ));
+ SMESH::SMESH_GroupOnGeom::_narrow( createGroup( theElemType, theName, /*id=*/-1, aShape ));
if ( _gen_i->CanPublishInStudy( aNewGroup ) )
{
THROW_SALOME_CORBA_EXCEPTION("Invalid filter", SALOME::BAD_PARAM);
SMESH::SMESH_GroupOnFilter_var aNewGroup = SMESH::SMESH_GroupOnFilter::_narrow
- ( createGroup( theElemType, theName, TopoDS_Shape(), predicate ));
+ ( createGroup( theElemType, theName, /*id=*/-1, TopoDS_Shape(), predicate ));
TPythonDump pd;
if ( !aNewGroup->_is_nil() )
SALOMEDS::SObject_wrap groupSO = _gen_i->ObjectToSObject( _mapGroups[oldID] );
CORBA::String_var name = groupSO->GetName();
// update
- SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID] );
- int newID;
- if ( group_i && _impl->AddGroup( geomType->second, name.in(), newID, geom._shape ))
- group_i->changeLocalId( newID );
+ if ( SMESH_GroupBase_i* group_i = SMESH::DownCast<SMESH_GroupBase_i*>(_mapGroups[oldID]))
+ if ( SMESH_Group* group = _impl->AddGroup( geomType->second, name.in(),
+ /*id=*/-1, geom._shape ))
+ group_i->changeLocalId( group->GetID() );
}
break; // everything has been updated
SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType theElemType,
const char* theName,
+ const int theID,
const TopoDS_Shape& theShape,
const SMESH_PredicatePtr& thePredicate )
{
} while ( !presentNames.insert( newName ).second );
theName = newName.c_str();
}
- int anId;
SMESH::SMESH_GroupBase_var aGroup;
- if ( _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName, anId, theShape, thePredicate ))
+ if ( SMESH_Group* g = _impl->AddGroup( (SMDSAbs_ElementType)theElemType, theName,
+ theID, theShape, thePredicate ))
{
+ int anId = g->GetID();
SMESH_GroupBase_i* aGroupImpl;
if ( !theShape.IsNull() )
aGroupImpl = new SMESH_GroupOnGeom_i( SMESH_Gen_i::GetPOA(), this, anId );
// register CORBA object for persistence
int nextId = _gen_i->RegisterObject( aGroup );
if(MYDEBUG) { MESSAGE( "Add group to map with id = "<< nextId); }
- else { nextId = 0; } // avoid "unused variable" warning in release mode
+ else { nextId = ( nextId > 0 ); } // avoid "unused variable" warning in release mode
// to track changes of GEOM groups
if ( !theShape.IsNull() ) {
*/
//=============================================================================
-SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id)
+SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id,
+ SMESH::ElementType elemType)
{
if ( _preMeshInfo )
_preMeshInfo->FullLoadFromFile();
return aResult._retn();
// find node
- const SMDS_MeshNode* aNode = aMeshDS->FindNode(id);
- if(!aNode)
+ const SMDS_MeshNode* aNode = aMeshDS->FindNode( id );
+ if ( !aNode )
return aResult._retn();
// find inverse elements
- SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator();
- aResult->length( aNode->NbInverseElements() );
+ SMDSAbs_ElementType type = SMDSAbs_ElementType( elemType );
+ SMDS_ElemIteratorPtr eIt = aNode->GetInverseElementIterator( type );
+ aResult->length( aNode->NbInverseElements( type ));
for( int i = 0; eIt->more(); ++i )
{
const SMDS_MeshElement* elem = eIt->next();
SMDS_ElemIteratorPtr _elemIter;
PredicatePtr _predicate;
const SMDS_MeshElement* _elem;
+ SMDSAbs_ElementType _type;
- PredicateIterator( SMDS_ElemIteratorPtr iterator,
- PredicatePtr predicate):
- _elemIter(iterator), _predicate(predicate)
+ PredicateIterator( SMDS_ElemIteratorPtr iterator,
+ PredicatePtr predicate,
+ SMDSAbs_ElementType type):
+ _elemIter(iterator), _predicate(predicate), _type(type)
{
next();
}
_elem = 0;
while ( _elemIter->more() && !_elem )
{
- _elem = _elemIter->next();
- if ( _elem && ( !_predicate->IsSatisfy( _elem->GetID() )))
+ if ((_elem = _elemIter->next()) &&
+ (( _type != SMDSAbs_All && _type != _elem->GetType() ) ||
+ ( !_predicate->IsSatisfy( _elem->GetID() ))))
_elem = 0;
}
return res;
else if ( SMESH::Filter_i* filter_i = SMESH::DownCast<SMESH::Filter_i*>( theObject ))
{
if ( filter_i->GetElementType() == theType ||
+ filter_i->GetElementType() == SMESH::ALL ||
elemType == SMDSAbs_Node ||
elemType == SMDSAbs_All)
{
{
SMDSAbs_ElementType filterType = SMDSAbs_ElementType( filter_i->GetElementType() );
SMDS_ElemIteratorPtr allElemIt = meshDS->elementsIterator( filterType );
- elemIt = SMDS_ElemIteratorPtr( new PredicateIterator( allElemIt, pred_i->GetPredicate() ));
- typeOK = ( filterType == elemType || elemType == SMDSAbs_All );
+ SMDSAbs_ElementType iterType = elemType == SMDSAbs_Node ? filterType : elemType;
+ elemIt = SMDS_ElemIteratorPtr
+ ( new PredicateIterator( allElemIt, pred_i->GetPredicate(), iterType ));
+ typeOK = ( elemType == SMDSAbs_Node ? filterType == SMDSAbs_Node : elemIt->more() );
}
}
}
const bool isNodes = ( types->length() == 1 && types[0] == SMESH::NODE );
if ( isNodes && elemType != SMDSAbs_Node && elemType != SMDSAbs_All )
return elemIt;
+ SMDSAbs_ElementType iterType = isNodes ? SMDSAbs_Node : elemType;
if ( SMESH_MeshEditor_i::IsTemporaryIDSource( theObject ))
{
int nbIds;
if ( CORBA::Long* ids = SMESH_MeshEditor_i::GetTemporaryIDs( theObject, nbIds ))
- elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, elemType ));
+ elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids, nbIds, iterType ));
}
else
{
SMESH::long_array_var ids = theObject->GetIDs();
- elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), elemType ));
+ elemIt = SMDS_ElemIteratorPtr( new IDSourceIterator( meshDS, ids._retn(), iterType ));
}
typeOK = ( isNodes == ( elemType == SMDSAbs_Node )) || ( elemType == SMDSAbs_All );
}
SMESH::SMESH_GroupBase_ptr createGroup(SMESH::ElementType theElemType,
const char* theName,
+ const int theID = -1,
const TopoDS_Shape& theShape = TopoDS_Shape(),
const SMESH_PredicatePtr& thePred = SMESH_PredicatePtr());
* For given node returns list of IDs of inverse elements
* If there is not node for given ID - returns empty list
*/
- SMESH::long_array* GetNodeInverseElements(CORBA::Long id);
+ SMESH::long_array* GetNodeInverseElements(CORBA::Long id,
+ SMESH::ElementType elemType);
/*!
* \brief Return position of a node on shape
def Concatenate( self, meshes, uniteIdenticalGroups,
mergeNodesAndElements = False, mergeTolerance = 1e-5, allGroups = False,
- name = ""):
+ name = "", meshToAppendTo = None):
"""
- Concatenate the given meshes into one mesh. All groups of input meshes will be
- present in the new mesh.
+ Concatenate the given meshes into one mesh, optionally to meshToAppendTo.
+ All groups of input meshes will be present in the new mesh.
Parameters:
meshes: :class:`meshes, sub-meshes, groups or filters <SMESH.SMESH_IDSource>` to combine into one mesh
mergeTolerance: tolerance for merging nodes
allGroups: forces creation of groups corresponding to every input mesh
name: name of a new mesh
+ meshToAppendTo a mesh to append all given meshes
Returns:
an instance of class :class:`Mesh`
if isinstance(m, Mesh):
meshes[i] = m.GetMesh()
mergeTolerance,Parameters,hasVars = ParseParameters(mergeTolerance)
- meshes[0].SetParameters(Parameters)
+ if hasattr(meshes[0], "SetParameters"):
+ meshes[0].SetParameters(Parameters)
+ else:
+ meshes[0].GetMesh().SetParameters(Parameters)
+ if isinstance( meshToAppendTo, Mesh ):
+ meshToAppendTo = meshToAppendTo.GetMesh()
if allGroups:
aSmeshMesh = SMESH._objref_SMESH_Gen.ConcatenateWithGroups(
- self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance)
+ self,meshes,uniteIdenticalGroups,mergeNodesAndElements,
+ mergeTolerance,meshToAppendTo)
else:
aSmeshMesh = SMESH._objref_SMESH_Gen.Concatenate(
- self,meshes,uniteIdenticalGroups,mergeNodesAndElements,mergeTolerance)
+ self,meshes,uniteIdenticalGroups,mergeNodesAndElements,
+ mergeTolerance,meshToAppendTo)
+
aMesh = Mesh(self, self.geompyD, aSmeshMesh, name=name)
return aMesh
def GetGravityCenter(self, obj):
"""
- Get gravity center of all nodes of the mesh object.
+ Get gravity center of all nodes of a mesh object.
Parameters:
obj: :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
Returns:
- Three components of the gravity center (x,y,z)
+ Three components of the gravity center (x,y,z)
+
+ See also:
+ :meth:`Mesh.BaryCenter`
"""
if isinstance(obj, Mesh): obj = obj.mesh
if isinstance(obj, Mesh_Algorithm): obj = obj.GetSubMesh()
return self.mesh
+ def GetEngine(self):
+ """
+ Return a smeshBuilder instance created this mesh
+ """
+ return self.smeshpyD
+
+ def GetGeomEngine(self):
+ """
+ Return a geomBuilder instance
+ """
+ return self.geompyD
+
def GetName(self):
"""
Get the name of the mesh
Create a standalone group of entities basing on nodes of other groups.
Parameters:
- groups: list of reference :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>`, of any type.
+ groups: list of :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>`, of any type.
elemType: a type of elements to include to the new group; either of
(SMESH.NODE, SMESH.EDGE, SMESH.FACE, SMESH.VOLUME).
name: a name of the new group.
return self.mesh.GetNodeXYZ(id)
- def GetNodeInverseElements(self, id):
+ def GetNodeInverseElements(self, id, elemType=SMESH.ALL):
"""
Return list of IDs of inverse elements for the given node.
If there is no node for the given ID - return an empty list
+ Parameters:
+ id: node ID
+ elementType: :class:`type of elements <SMESH.ElementType>` (SMESH.EDGE, SMESH.FACE, SMESH.VOLUME, etc.)
+
Returns:
list of integer values
"""
- return self.mesh.GetNodeInverseElements(id)
+ return self.mesh.GetNodeInverseElements(id,elemType)
def GetNodePosition(self,NodeID):
"""
Returns:
a list of three double values
+
+ See also:
+ :meth:`smeshBuilder.GetGravityCenter`
"""
return self.mesh.BaryCenter(id)
- def GetIdsFromFilter(self, theFilter):
+ def GetIdsFromFilter(self, filter, meshParts=[] ):
"""
Pass mesh elements through the given filter and return IDs of fitting elements
Parameters:
- theFilter: :class:`SMESH.Filter`
+ filter: :class:`SMESH.Filter`
+ meshParts: list of mesh parts (:class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`) to filter
Returns:
a list of ids
See Also:
:meth:`SMESH.Filter.GetIDs`
+ :meth:`SMESH.Filter.GetElementsIdFromParts`
"""
- theFilter.SetMesh( self.mesh )
- return theFilter.GetIDs()
+ filter.SetMesh( self.mesh )
+
+ if meshParts:
+ if isinstance( meshParts, Mesh ):
+ filter.SetMesh( meshParts.GetMesh() )
+ return theFilter.GetIDs()
+ if isinstance( meshParts, SMESH._objref_SMESH_IDSource ):
+ meshParts = [ meshParts ]
+ return filter.GetElementsIdFromParts( meshParts )
+
+ return filter.GetIDs()
# Get mesh measurements information:
# ------------------------------------
the ID of a node
"""
- #preview = self.mesh.GetMeshEditPreviewer()
- #return preview.MoveClosestNodeToPoint(x, y, z, -1)
return self.editor.FindNodeClosestTo(x, y, z)
def FindElementsByPoint(self, x, y, z, elementType = SMESH.ALL, meshPart=None):
else:
return self.editor.FindElementsByPoint(x, y, z, elementType)
- def ProjectPoint(self, x,y,z, meshObject, elementType):
+ def ProjectPoint(self, x,y,z, elementType, meshObject=None):
"""
Project a point to a mesh object.
Return ID of an element of given type where the given point is projected
and coordinates of the projection point.
In the case if nothing found, return -1 and []
"""
- if ( isinstance( meshObject, Mesh )):
+ if isinstance( meshObject, Mesh ):
meshObject = meshObject.GetMesh()
- return self.editor.ProjectPoint( x,y,z, meshObject, elementType )
+ if not meshObject:
+ meshObject = self.GetMesh()
+ return self.editor.ProjectPoint( x,y,z, elementType, meshObject )
def GetPointState(self, x, y, z):
"""
return self.editor.IsCoherentOrientation2D()
+ def Get1DBranches( self, edges, startNode = 0 ):
+ """
+ Partition given 1D elements into groups of contiguous edges.
+ A node where number of meeting edges != 2 is a group end.
+ An optional startNode is used to orient groups it belongs to.
+
+ Returns:
+ A list of edge groups and a list of corresponding node groups,
+ where the group is a list of IDs of edges or elements.
+ If a group is closed, the first and last nodes of the group are same.
+ """
+ if isinstance( edges, Mesh ):
+ edges = edges.GetMesh()
+ unRegister = genObjUnRegister()
+ if isinstance( edges, list ):
+ edges = self.GetIDSource( edges, SMESH.EDGE )
+ unRegister.set( edges )
+ return self.editor.Get1DBranches( edges, startNode )
+
def FindSharpEdges( self, angle, addExisting=False ):
"""
Return sharp edges of faces and non-manifold ones.
groups: list of :class:`sub-meshes, groups or filters <SMESH.SMESH_IDSource>` of elements to make boundary around
Returns:
- tuple( long, mesh, groups )
+ tuple( long, mesh, group )
- long - number of added boundary elements
- mesh - the :class:`Mesh` where elements were added to
- group - the :class:`group <SMESH.SMESH_Group>` of boundary elements or None
Parameters:
Tolerance: the value of tolerance
- SubMeshOrGroup: :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>`
+ SubMeshOrGroup: :class:`sub-mesh, group or filter <SMESH.SMESH_IDSource>` or node IDs
exceptNodes: list of either SubMeshes, Groups or node IDs to exclude from search
SeparateCornerAndMediumNodes: if *True*, in quadratic mesh puts
corner and medium nodes in separate groups thus preventing
unRegister = genObjUnRegister()
if (isinstance( SubMeshOrGroup, Mesh )):
SubMeshOrGroup = SubMeshOrGroup.GetMesh()
+ if isinstance( SubMeshOrGroup, list ):
+ SubMeshOrGroup = self.GetIDSource( SubMeshOrGroup, SMESH.NODE )
+ unRegister.set( SubMeshOrGroup )
+
if not isinstance( exceptNodes, list ):
exceptNodes = [ exceptNodes ]
if exceptNodes and isinstance( exceptNodes[0], int ):
exceptNodes = [ self.GetIDSource( exceptNodes, SMESH.NODE )]
unRegister.set( exceptNodes )
+
return self.editor.FindCoincidentNodesOnPartBut(SubMeshOrGroup, Tolerance,
exceptNodes, SeparateCornerAndMediumNodes)
segments[i].vector = seg.vector
if isPreview:
return editor.GetPreviewData()
- return None
+ return None
+
+ def MakeSlot(self, segmentGroup, width ):
+ """
+ Create a slot of given width around given 1D elements lying on a triangle mesh.
+ The slot is consrtucted by cutting faces by cylindrical surfaces made
+ around each segment. Segments are expected to be created by MakePolyLine().
+
+ Returns:
+ FaceEdge's located at the slot boundary
+ """
+ return self.editor.MakeSlot( segmentGroup, width )
def GetFunctor(self, funcType ):
"""
node1,node2,node3: IDs of the three nodes
Returns:
- Angle in radians
+ Angle in radians [0,PI]. -1 if failure case.
"""
- return self.smeshpyD.GetAngle( self.GetNodeXYZ( node1 ),
- self.GetNodeXYZ( node2 ),
- self.GetNodeXYZ( node3 ))
+ p1 = self.GetNodeXYZ( node1 )
+ p2 = self.GetNodeXYZ( node2 )
+ p3 = self.GetNodeXYZ( node3 )
+ if p1 and p2 and p3:
+ return self.smeshpyD.GetAngle( p1,p2,p3 )
+ return -1.
+
def GetMaxElementLength(self, elemId):
"""
int nb = 1;
while ( !namesByType[ srcGroupDS->GetType() ].insert( name ).second )
name = SMESH_Comment(srcGroup->GetName()) << "_imported_" << nb++;
- SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str(), nb );
+ SMESH_Group* newGroup = tgtMesh.AddGroup( srcGroupDS->GetType(), name.c_str() );
SMESHDS_Group* newGroupDS = (SMESHDS_Group*)newGroup->GetGroupDS();
resultGroups.push_back( newGroup );