23627: [IMACS] ASERIS: project point to the mesh and create a slot

1) Enable appending to an existing mesh via smesh.Concatenate() (compound mesh)
2) Enable filtering a mesh part: Filter::GetElementsIdFromParts( ListOfIDSources )
3) Add ElementType arg to SMESH_Mesh::GetNodeInverseElements()
4) Add Mesh.Get1DBranches( edgeIDs )
5) Define a default Z med tolerance
6) Update ElementsOnSurface upon SetTolerance()
7) Change group management to have group ID persistent
8) Extract SMESH_PolyLine.cxx from SMESH_MeshEditor.cxx
9) Enable Min Distance measure for node-element and node-object
10) Fix SMESH_MeshAlgos::GetDistance( XYZ, face )
11) Extract SMESH_MeshAlgos::Intersector from SMESH_Offset.cxx
12) Enable optimization in SMESH_MeshAlgos::Triangulate
13) Add mestods Mesh.GetEngine() and Mesh.GetGeomEngine()
This commit is contained in:
eap 2019-01-17 15:53:49 +03:00
parent 6d3cec2c38
commit 09bc0414c9
41 changed files with 3101 additions and 1074 deletions

View File

@ -2,11 +2,8 @@
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()
@ -77,5 +74,12 @@ Compound1 = smesh.Concatenate([Mesh_inf, Mesh_sup], 0, 1, 1e-05,
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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

@ -4,9 +4,14 @@
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
@ -16,9 +21,13 @@ From the **Mesh** menu select **Build Compound** or click *"Build Compound Mesh"
.. 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*.

View File

@ -523,6 +523,7 @@ module SMESH
void SetMesh( in SMESH_Mesh theMesh );
long_array GetElementsId( in SMESH_Mesh theMesh );
long_array GetElementsIdFromParts( in ListOfIDSources theParts );
ElementType GetElementType();
Predicate GetPredicate();

View File

@ -312,7 +312,8 @@ module SMESH
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
@ -321,11 +322,13 @@ module SMESH
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
@ -335,7 +338,8 @@ module SMESH
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 );
/*!

View File

@ -902,7 +902,7 @@ module SMESH
* 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

View File

@ -798,8 +798,8 @@ module SMESH
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);
@ -822,6 +822,18 @@ module SMESH
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.
@ -1295,6 +1307,17 @@ module SMESH
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);
};
};

View File

@ -86,6 +86,7 @@
<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"/>

View File

@ -1888,7 +1888,7 @@ void Length2D::GetValues(TValues& theValues)
//================================================================================
/*
Class : Deflection2D
Description : Functor for calculating number of faces conneted to the edge
Description : computes distance between a face center and an underlying surface
*/
//================================================================================
@ -3589,9 +3589,10 @@ void Filter::SetPredicate( PredicatePtr thePredicate )
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();
@ -3600,21 +3601,28 @@ void Filter::GetElementsId( const SMDS_Mesh* theMesh,
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);
}
/*
@ -4042,8 +4050,10 @@ SMDSAbs_ElementType ElementsOnSurface::GetType() const
void ElementsOnSurface::SetTolerance( const double theToler )
{
if ( myToler != theToler )
myIds.Clear();
myToler = theToler;
{
myToler = theToler;
process();
}
}
double ElementsOnSurface::GetTolerance() const

View File

@ -1178,14 +1178,16 @@ namespace SMESH{
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;

View File

@ -639,6 +639,9 @@ const SMDS_MeshNode* SMDS_MeshCell::GetNode(const int ind) const
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 );

View File

@ -96,3 +96,14 @@ void SMESH_Group::SetName (const char* theName)
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;
}

View File

@ -58,6 +58,8 @@ class SMESH_EXPORT SMESH_Group
SMESHDS_GroupBase * GetGroupDS () { return myGroupDS; }
int GetID() const;
private:
SMESH_Group (const SMESH_Group& theOther);
// prohibited copy constructor

View File

@ -521,11 +521,10 @@ int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName)
// 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 ) {
@ -2029,16 +2028,18 @@ bool SMESH_Mesh::IsMainShape(const TopoDS_Shape& theShape) const
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;
}
@ -2065,7 +2066,8 @@ SMESH_Group* SMESH_Mesh::AddGroup (SMESHDS_GroupBase* groupDS) throw(SALOME_Exce
_mapGroup[ groupDS->GetID() ] = aGroup;
GetMeshDS()->AddGroup( aGroup->GetGroupDS() );
_groupId = 1 + _mapGroup.rbegin()->first;
while ( _mapGroup.count( _groupId ))
++_groupId;
return aGroup;
}
@ -2091,8 +2093,8 @@ bool SMESH_Mesh::SynchronizeGroups()
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();
}
@ -2115,11 +2117,12 @@ SMESH_Mesh::GroupIteratorPtr SMESH_Mesh::GetGroups() const
*/
//=============================================================================
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;
}

View File

@ -315,9 +315,9 @@ class SMESH_EXPORT SMESH_Mesh
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);
@ -326,7 +326,7 @@ class SMESH_EXPORT SMESH_Mesh
std::list<int> GetGroupIds() const;
SMESH_Group* GetGroup (const int theGroupID);
SMESH_Group* GetGroup (const int theGroupID) const;
bool RemoveGroup (const int theGroupID);

View File

@ -97,7 +97,6 @@
#include <Standard_Failure.hxx>
#include <Standard_ErrorHandler.hxx>
#include <OSD_Parallel.hxx>
#include "SMESH_TryCatch.hxx" // include after OCCT headers!
@ -6752,8 +6751,8 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElem
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,
@ -6796,7 +6795,7 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElem
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 ));
}
}
@ -6812,7 +6811,7 @@ SMESH_MeshEditor::PGroupIDs SMESH_MeshEditor::Offset( TIDSortedElemSet & theElem
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 );
@ -8501,6 +8500,7 @@ SMESH_MeshEditor::SewFreeBorder (const SMDS_MeshNode* theBordFirstNode,
{
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();
@ -11750,12 +11750,11 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
//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();
@ -11783,7 +11782,7 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
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());
@ -11816,10 +11815,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
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());
@ -11845,10 +11843,9 @@ bool SMESH_MeshEditor::DoubleNodesOnGroupBoundaries( const std::vector<TIDSorted
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());
@ -12106,10 +12103,9 @@ bool SMESH_MeshEditor::CreateFlatElementsOnFacesGroups(const std::vector<TIDSort
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());
@ -12180,10 +12176,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
// --- 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);
@ -12191,10 +12187,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
}
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);
@ -12202,10 +12198,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
}
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);
@ -12213,10 +12209,10 @@ void SMESH_MeshEditor::CreateHoleSkin(double radius,
}
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);
@ -13040,565 +13036,3 @@ void SMESH_MeshEditor::copyPosition( const SMDS_MeshNode* from,
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;
}

View File

@ -717,49 +717,6 @@ public:
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:
/*!

View File

@ -65,6 +65,8 @@
#define SPACING 6
#define MARGIN 11
enum { NEW_MESH_ID, APPEND_TO_ID };
//=================================================================================
// name : SMESHGUI_BuildCompoundDlg
// Purpose :
@ -103,16 +105,28 @@ SMESHGUI_BuildCompoundDlg::SMESHGUI_BuildCompoundDlg( SMESHGUI* theModule )
ButtonGroup->addButton(Constructor1, 0);
/***************************************************************/
GroupName = new QGroupBox(tr("RESULT_NAME"), this);
QHBoxLayout* GroupNameLayout = new QHBoxLayout(GroupName);
GroupNameLayout->setSpacing(SPACING);
GroupNameLayout->setMargin(MARGIN);
GroupResult = new QGroupBox(tr("RESULT_NAME"), this);
QGridLayout* GroupResultLayout = new QGridLayout(GroupResult);
GroupResultLayout->setSpacing(SPACING);
GroupResultLayout->setMargin(MARGIN);
TextLabelName = new QLabel(tr("SMESH_NAME"), GroupName);
LineEditName = new QLineEdit(GroupName);
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 );
GroupNameLayout->addWidget(TextLabelName);
GroupNameLayout->addWidget(LineEditName);
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);
@ -175,7 +189,7 @@ SMESHGUI_BuildCompoundDlg::SMESHGUI_BuildCompoundDlg( SMESHGUI* theModule )
/***************************************************************/
aTopLayout->addWidget(GroupConstructors);
aTopLayout->addWidget(GroupName);
aTopLayout->addWidget(GroupResult);
aTopLayout->addWidget(GroupArgs);
aTopLayout->addWidget(GroupButtons);
@ -200,11 +214,11 @@ void SMESHGUI_BuildCompoundDlg::Init()
{
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()));
@ -212,7 +226,10 @@ void SMESHGUI_BuildCompoundDlg::Init()
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)));
@ -221,8 +238,7 @@ void SMESHGUI_BuildCompoundDlg::Init()
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"));
@ -235,10 +251,9 @@ void SMESHGUI_BuildCompoundDlg::Init()
SpinBoxTol->setEnabled(CheckBoxMerge->isChecked());
mySelectionMgr->clearFilters();
mySelectionMgr->installFilter(myMeshFilter);
onResultTypeChange( ResultButtonGroup->checkedId() );
SelectionIntoArgument();
onSelectionButton();
}
//=================================================================================
@ -290,7 +305,9 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply()
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(" "));
@ -307,16 +324,19 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply()
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();
@ -324,7 +344,7 @@ bool SMESHGUI_BuildCompoundDlg::ClickOnApply()
return false;
}
LineEditName->setText(GetDefaultName(tr("COMPOUND_MESH")));
LineEditNewName->setText(GetDefaultName(tr("COMPOUND_MESH")));
// IPAL21468 Compound is hidden after creation.
if ( SMESHGUI::automaticUpdate() ) {
@ -401,30 +421,41 @@ void SMESHGUI_BuildCompoundDlg::SelectionIntoArgument()
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 = "";
}
CurrentLineEdit->setText(aString);
LineEditMeshes->setText(aString);
bool isEnabled = (!myMesh->_is_nil());
buttonOk->setEnabled(isEnabled);
buttonApply->setEnabled(isEnabled);
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 );
}
//=================================================================================
@ -435,7 +466,7 @@ void SMESHGUI_BuildCompoundDlg::DeactivateActiveDialog()
{
if (GroupConstructors->isEnabled()) {
GroupConstructors->setEnabled(false);
GroupName->setEnabled(false);
GroupResult->setEnabled(false);
GroupArgs->setEnabled(false);
GroupButtons->setEnabled(false);
mySMESHGUI->ResetState();
@ -452,7 +483,7 @@ void SMESHGUI_BuildCompoundDlg::ActivateThisDialog()
/* 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);
@ -500,6 +531,56 @@ void SMESHGUI_BuildCompoundDlg::onSelectMerge(bool toMerge)
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 :

View File

@ -38,16 +38,17 @@
#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;
//=================================================================================
@ -80,9 +81,10 @@ private:
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;
@ -94,9 +96,11 @@ private:
QPushButton* buttonApply;
QPushButton* buttonHelp;
QGroupBox* GroupName;
QLabel* TextLabelName;
QLineEdit* LineEditName;
QGroupBox* GroupResult;
QButtonGroup* ResultButtonGroup;
QLineEdit* LineEditNewName;
QPushButton* SelectButtonAppendTo;
QLineEdit* LineEditAppendTo;
QGroupBox* GroupArgs;
QLabel* TextLabelMeshes;
@ -109,6 +113,8 @@ private:
QLabel* TextLabelTol;
SMESHGUI_SpinBox* SpinBoxTol;
QLineEdit* CurrentLineEdit;
QString myHelpFileName;
bool myIsApplyAndClose;
@ -124,6 +130,8 @@ private slots:
void DeactivateActiveDialog();
void ActivateThisDialog();
void onSelectMerge( bool );
void onResultTypeChange( int );
void onSelectionButton();
};
#endif // SMESHGUI_BUILDCOMPOUNDDLG_H

View File

@ -173,11 +173,11 @@ SMESHGUI_MinDistance::SMESHGUI_MinDistance( QWidget* parent )
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 );
@ -595,10 +595,14 @@ void SMESHGUI_MinDistance::compute()
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();
}

View File

@ -5118,6 +5118,14 @@ Please, create VTK viewer and try again</translation>
<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>
@ -5128,7 +5136,7 @@ Please, create VTK viewer and try again</translation>
</message>
<message>
<source>RESULT_NAME</source>
<translation>Result name</translation>
<translation>Result</translation>
</message>
<message>
<source>UNITE</source>

View File

@ -82,6 +82,8 @@ SET(SMESHUtils_SOURCES
SMESH_FillHole.cxx
SMESH_Triangulate.cxx
SMESH_Offset.cxx
SMESH_Slot.cxx
SMESH_PolyLine.cxx
)
# --- rules ---

View File

@ -23,7 +23,7 @@
// 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"
@ -285,6 +285,11 @@ namespace // Utils used in SMESH_ElementSearcherImpl::FindElementsByPoint()
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() )
{
@ -874,7 +879,7 @@ SMESH_ElementSearcherImpl::FindClosestTo( const gp_Pnt& point,
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;
@ -1253,7 +1258,7 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt& point,
ElementBndBoxTree::TElemSeq elems;
ebbTree->getElementsInSphere( p, radius, elems );
while ( elems.empty() )
while ( elems.empty() && radius < 1e100 )
{
radius *= 1.5;
ebbTree->getElementsInSphere( p, radius, elems );
@ -1264,7 +1269,7 @@ gp_XYZ SMESH_ElementSearcherImpl::Project(const gp_Pnt& point,
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;
@ -1460,7 +1465,8 @@ namespace
// . 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;
@ -1558,10 +1564,35 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
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.
@ -1585,7 +1616,7 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
// 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 );
@ -1600,71 +1631,63 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
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];
case POS_RIGHT: // point is inside the face
{
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;
}
}
return distToFacePlane;
}
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_VERTEX: // point is most close to a node
else if ( pntPosByType[ POS_RIGHT ].size() >= 2 ) // point is inside the face
{
dist = Abs( tmpPnt.Y() );
if ( closestPnt )
{
double dist2 = point.SquareDistance( xyz[ pos._index ]);
if ( dist2 < minDist2 )
{
if ( closestPnt ) *closestPnt = xyz[ pos._index ];
minDist2 = dist2;
if ( dist < std::numeric_limits<double>::min() ) {
*closestPnt = point.XYZ();
}
else {
tmpPnt.SetY( 0 );
trsf.Inverted().Transforms( tmpPnt );
*closestPnt = tmpPnt;
}
break;
}
default:;
return badDistance;
}
}
return Sqrt( minDist2 );
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 )
{
PointPos& pos = pntPosByType[ POS_VERTEX ][i];
double d2 = point.SquareDistance( xyz[ pos._index ]);
if ( minDist2 > d2 )
{
if ( closestPnt ) *closestPnt = xyz[ pos._index ];
minDist2 = d2;
}
}
dist = Sqrt( minDist2 );
}
return dist;
}
//=======================================================================
@ -2166,6 +2189,207 @@ bool SMESH_MeshAlgos::IsRightOrder( const SMDS_MeshElement* face,
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

View File

@ -23,7 +23,7 @@
// 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
@ -37,14 +37,17 @@
#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;
//=======================================================================
/*!
@ -198,6 +201,22 @@ namespace SMESH_MeshAlgos
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
*/
@ -320,7 +339,6 @@ namespace SMESH_MeshAlgos
std::vector<const SMDS_MeshElement*>& newFaces);
// Implemented in ./SMESH_FillHole.cxx
/*!
* \brief Find nodes whose merge makes the element invalid
*/
@ -331,8 +349,8 @@ namespace SMESH_MeshAlgos
// 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
@ -346,20 +364,77 @@ namespace SMESH_MeshAlgos
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,
@ -374,19 +449,81 @@ namespace SMESH_MeshAlgos
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

View File

@ -42,8 +42,8 @@ namespace
{
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;
//--------------------------------------------------------------------------------
/*!
@ -53,7 +53,7 @@ namespace
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
@ -694,11 +694,15 @@ namespace
return useOneNormal;
}
} // namespace
namespace SMESH_MeshAlgos
{
//--------------------------------------------------------------------------------
/*!
* \brief Intersect faces of a mesh
*/
struct Intersector
struct Intersector::Algo
{
SMDS_Mesh* myMesh;
double myTol, myEps;
@ -716,7 +720,7 @@ namespace
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 ),
@ -727,9 +731,20 @@ namespace
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:
@ -805,7 +820,7 @@ namespace
*/
//================================================================================
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
@ -818,7 +833,7 @@ namespace
*/
//================================================================================
void Intersector::addLink( CutLink& link )
void Intersector::Algo::addLink( CutLink& link )
{
link.myIndex = 0;
const CutLink* added = & myCutLinks.Added( link );
@ -844,7 +859,7 @@ namespace
*/
//================================================================================
bool Intersector::findLink( CutLink& link )
bool Intersector::Algo::findLink( CutLink& link )
{
link.myIndex = 0;
while ( myCutLinks.Contains( link ))
@ -872,12 +887,12 @@ namespace
*/
//================================================================================
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() );
@ -915,12 +930,12 @@ namespace
*/
//================================================================================
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 )
{
@ -961,9 +976,9 @@ namespace
*/
//================================================================================
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;
@ -978,11 +993,11 @@ namespace
*/
//================================================================================
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 ];
@ -1028,15 +1043,15 @@ namespace
*/
//================================================================================
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 );
}
//================================================================================
@ -1053,13 +1068,13 @@ namespace
*/
//================================================================================
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 )
{
@ -1100,11 +1115,11 @@ namespace
*/
//================================================================================
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;
@ -1128,7 +1143,7 @@ namespace
*/
//================================================================================
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;
@ -1143,9 +1158,9 @@ namespace
*/
//================================================================================
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;
@ -1241,16 +1256,83 @@ namespace
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;
@ -1306,7 +1388,7 @@ namespace
*/
//================================================================================
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;
@ -1422,7 +1504,7 @@ namespace
*/
//================================================================================
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 ),
@ -1437,7 +1519,7 @@ namespace
*/
//================================================================================
void Intersector::cutCoplanar()
void Intersector::Algo::cutCoplanar()
{
// find intersections of edges
@ -1554,7 +1636,7 @@ namespace
}
return;
} // Intersector::cutCoplanar()
} // Intersector::Algo::cutCoplanar()
//================================================================================
/*!
@ -1562,13 +1644,19 @@ namespace
*/
//================================================================================
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
@ -1753,7 +1841,7 @@ namespace
}
}
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
}
@ -1766,10 +1854,23 @@ namespace
*/
//================================================================================
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(); )
@ -1790,8 +1891,7 @@ namespace
// 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 );
@ -1801,11 +1901,11 @@ namespace
// 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;
@ -1877,13 +1977,14 @@ namespace
// 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 )
@ -1954,8 +2055,8 @@ namespace
// 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;
@ -1969,6 +2070,185 @@ namespace
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
@ -2190,11 +2470,11 @@ namespace
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
@ -2615,7 +2895,7 @@ namespace
//================================================================================
/*!
* \brief Replace _COPLANAR cut edge by _INTERNAL oe vice versa
* \brief Replace _COPLANAR cut edge by _INTERNAL or vice versa
*/
//================================================================================
@ -2643,8 +2923,8 @@ namespace
/*!
* \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
*/
//================================================================================
@ -2653,8 +2933,8 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
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" );
@ -2665,8 +2945,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
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
@ -2687,7 +2966,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
{
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;
}
}
@ -2725,7 +3004,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
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 )
@ -2743,7 +3022,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
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
}
@ -2792,7 +3071,7 @@ SMDS_Mesh* SMESH_MeshAlgos::MakeOffset( SMDS_ElemIteratorPtr theFaceIt,
{
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 );
}
}

View File

@ -0,0 +1,595 @@
// 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;
}

View File

@ -0,0 +1,720 @@
// 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;
}

View File

@ -31,8 +31,183 @@
#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
@ -40,11 +215,13 @@ using namespace SMESH_MeshAlgos;
//================================================================================
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;
}
//================================================================================
/*!
@ -65,11 +242,15 @@ Triangulate::PolyVertex* Triangulate::PolyVertex::Delete()
*/
//================================================================================
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;
}
//================================================================================
@ -112,7 +293,7 @@ bool Triangulate::PolyVertex::IsInsideTria( const PolyVertex* v )
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 );
@ -128,13 +309,13 @@ bool Triangulate::PolyVertex::IsInsideTria( const PolyVertex* v )
//================================================================================
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;
@ -163,7 +344,8 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
// 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;
@ -182,13 +364,15 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
}
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;
@ -207,13 +391,13 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
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;
@ -228,7 +412,7 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
// add all the rest triangles
while ( nbVertices >= 3 )
{
v->GetTriaNodes( &nodes[ iN ] );
v->GetTriaNodes( &nodes[ iN ], &_nodeIndex[ iN ] );
iN += 3;
v = v->Delete();
--nbVertices;
@ -238,6 +422,30 @@ bool Triangulate::triangulate( std::vector< const SMDS_MeshNode*>& nodes,
} // 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

View File

@ -1,51 +0,0 @@
// 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

View File

@ -185,6 +185,21 @@ struct SMESH_TNodeXYZ : public gp_XYZ
};
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

View File

@ -2577,6 +2577,36 @@ GetElementsId( SMESH_Mesh_ptr theMesh )
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

View File

@ -996,7 +996,11 @@ namespace SMESH
GetElementsId( SMESH_Mesh_ptr );
virtual
ElementType
long_array*
GetElementsIdFromParts( const ListOfIDSources& theParts );
virtual
ElementType
GetElementType();
virtual

View File

@ -2431,14 +2431,16 @@ SMESH::SMESH_Mesh_ptr
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);
}
//================================================================================
@ -2454,14 +2456,16 @@ SMESH::SMESH_Mesh_ptr
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);
}
//================================================================================
@ -2477,16 +2481,22 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray,
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();
@ -2507,6 +2517,8 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray,
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
@ -2693,11 +2705,12 @@ SMESH_Gen_i::ConcatenateCommon(const SMESH::ListOfIDSources& theMeshesArray,
// 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()
@ -4011,7 +4024,7 @@ SALOMEDS::TMPFile* SMESH_Gen_i::Save( SALOMEDS::SComponent_ptr theComponent,
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 );
}
@ -5334,7 +5347,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
// 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" ) ) {
@ -5346,10 +5359,6 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
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;
@ -5616,9 +5625,13 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
// 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();
@ -5675,7 +5688,7 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
// 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() )
@ -5724,10 +5737,10 @@ bool SMESH_Gen_i::Load( SALOMEDS::SComponent_ptr theComponent,
} // 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 );
}

View File

@ -307,7 +307,7 @@ public:
// 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,
@ -341,14 +341,16 @@ public:
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
@ -356,7 +358,8 @@ public:
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.

View File

@ -120,6 +120,33 @@ static bool getNodeNodeDistance (SMESH::Measure& theMeasure,
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 ))
@ -183,7 +210,6 @@ SMESH::Measure Measurements_i::MinDistance
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
@ -196,10 +222,25 @@ SMESH::Measure Measurements_i::MinDistance
// 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

View File

@ -383,6 +383,8 @@ namespace MeshEditor_I {
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
@ -2066,9 +2068,10 @@ void SMESH_MeshEditor_i::SplitVolumesIntoTetra (SMESH::SMESH_IDSource_ptr elems,
::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()
@ -2109,6 +2112,7 @@ void SMESH_MeshEditor_i::SplitHexahedraIntoPrisms( SMESH::SMESH_IDSource_ptr el
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 );
@ -2423,8 +2427,8 @@ SMESH_MeshEditor_i::RotationSweepObjects(const SMESH::ListOfIDSources & theNodes
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 );
@ -2621,8 +2625,8 @@ SMESH_MeshEditor_i::ExtrusionSweepObjects(const SMESH::ListOfIDSources & theNode
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 );
@ -2900,8 +2904,8 @@ SMESH_MeshEditor_i::ExtrusionAlongPathObjects(const SMESH::ListOfIDSources & the
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 );
@ -4180,6 +4184,7 @@ FindCoincidentNodesOnPart(SMESH::SMESH_IDSource_ptr theObject,
initData();
TIDSortedNodeSet nodes;
prepareIdSource( theObject );
idSourceToNodeSet( theObject, getMeshDS(), nodes );
findCoincidentNodes( nodes, Tolerance, GroupsOfNodes, SeparateCornersAndMedium );
@ -4211,14 +4216,15 @@ FindCoincidentNodesOnPartBut(SMESH::SMESH_IDSource_ptr theObject,
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 );
@ -4253,9 +4259,9 @@ void SMESH_MeshEditor_i::MergeNodes (const SMESH::array_of_long_array& GroupsOfN
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;
@ -4304,7 +4310,7 @@ void SMESH_MeshEditor_i::FindEqualElements(SMESH::SMESH_IDSource_ptr theObj
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);
@ -4606,6 +4612,7 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
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();
@ -4614,6 +4621,16 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
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 );
@ -4623,18 +4640,15 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
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;
@ -4663,8 +4677,8 @@ SMESH_MeshEditor_i::FindAmongElementsByPoint(SMESH::SMESH_IDSource_ptr elementID
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)
{
@ -4679,19 +4693,23 @@ CORBA::Long SMESH_MeshEditor_i::ProjectPoint(CORBA::Double x,
{
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 );
}
@ -4779,6 +4797,59 @@ CORBA::Boolean SMESH_MeshEditor_i::IsCoherentOrientation2D()
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.
@ -5525,8 +5596,8 @@ void SMESH_MeshEditor_i::convertToQuadratic(CORBA::Boolean theForce3d
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 )
{
@ -7087,7 +7158,7 @@ CORBA::Long SMESH_MeshEditor_i::MakeBoundaryElements(SMESH::Bnd_Dimension dim,
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];
@ -7267,11 +7338,11 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
}
// 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 );
@ -7294,15 +7365,24 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
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();
@ -7330,3 +7410,49 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
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();
}

View File

@ -560,8 +560,8 @@ public:
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);
@ -584,6 +584,18 @@ public:
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.
*/
@ -920,7 +932,17 @@ public:
* 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);

View File

@ -1020,7 +1020,7 @@ SMESH_Mesh_i::CreateGroupFromGEOM (SMESH::ElementType theElemType,
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 ) )
{
@ -1064,7 +1064,7 @@ SMESH_Mesh_i::CreateGroupFromFilter(SMESH::ElementType theElemType,
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() )
@ -2429,10 +2429,10 @@ void SMESH_Mesh_i::CheckGeomGroupModif()
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
@ -2685,6 +2685,7 @@ bool SMESH_Mesh_i::removeSubMesh (SMESH::SMESH_subMesh_ptr theSubMesh,
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 )
{
@ -2703,10 +2704,11 @@ SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType
} 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 );
@ -2722,7 +2724,7 @@ SMESH::SMESH_GroupBase_ptr SMESH_Mesh_i::createGroup (SMESH::ElementType
// 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() ) {
@ -4475,7 +4477,8 @@ SMESH::double_array* SMESH_Mesh_i::GetNodeXYZ(const CORBA::Long id)
*/
//=============================================================================
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();
@ -4486,13 +4489,14 @@ SMESH::long_array* SMESH_Mesh_i::GetNodeInverseElements(const CORBA::Long id)
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();
@ -5513,10 +5517,12 @@ namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_v
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();
}
@ -5530,8 +5536,9 @@ namespace /* Iterators used in SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_v
_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;
@ -5685,6 +5692,7 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
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)
{
@ -5693,8 +5701,10 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
{
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() );
}
}
}
@ -5704,16 +5714,17 @@ SMDS_ElemIteratorPtr SMESH_Mesh_i::GetElements(SMESH::SMESH_IDSource_ptr theObje
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 );
}

View File

@ -440,6 +440,7 @@ public:
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());
@ -501,7 +502,8 @@ public:
* 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

View File

@ -733,10 +733,10 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
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
@ -745,6 +745,7 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
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`
@ -755,13 +756,21 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
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
@ -1428,13 +1437,16 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ):
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()
@ -1618,6 +1630,18 @@ class Mesh(metaclass = MeshMeta):
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
@ -2881,7 +2905,7 @@ class Mesh(metaclass = MeshMeta):
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.
@ -3532,16 +3556,20 @@ class Mesh(metaclass = MeshMeta):
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):
"""
@ -3715,26 +3743,40 @@ class Mesh(metaclass = MeshMeta):
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:
# ------------------------------------
@ -4256,8 +4298,6 @@ class Mesh(metaclass = MeshMeta):
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):
@ -4278,16 +4318,18 @@ class Mesh(metaclass = MeshMeta):
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):
"""
@ -4312,6 +4354,25 @@ class Mesh(metaclass = MeshMeta):
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.
@ -5102,7 +5163,7 @@ class Mesh(metaclass = MeshMeta):
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
@ -6178,7 +6239,7 @@ class Mesh(metaclass = MeshMeta):
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
@ -6191,11 +6252,16 @@ class Mesh(metaclass = MeshMeta):
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)
@ -6755,7 +6821,18 @@ class Mesh(metaclass = MeshMeta):
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 ):
"""
@ -6856,11 +6933,15 @@ class Mesh(metaclass = MeshMeta):
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):
"""

View File

@ -911,7 +911,7 @@ void StdMeshers_Import_1D::importMesh(const SMESH_Mesh* srcMesh,
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 );