PAL0023627: [IMACS] ASERIS: project point to the mesh

Algorithm of poly-line construction modified to enable specifying
   arbitrary points serving as end points of the poly-line segment.
This commit is contained in:
eap 2018-11-09 13:28:18 +03:00
parent 858b4bff64
commit 441a2df90c
7 changed files with 186 additions and 79 deletions

View File

@ -618,7 +618,7 @@ SMESH_MeshEditor
.. py:class:: SMESH_MeshEditor.Sew_Error .. py:class:: SMESH_MeshEditor.Sew_Error
Enumeration of errors SMESH_MeshEditor.Sewing... methods Enumeration of errors of SMESH_MeshEditor.Sewing... methods
.. py:attribute:: .. py:attribute::
SEW_OK SEW_OK

View File

@ -60,17 +60,23 @@ module SMESH
// structure used in MakePolyLine() to define a cutting plane // structure used in MakePolyLine() to define a cutting plane
struct PolySegment struct PolySegment
{ {
// point 1: if node1ID2 > 0, then the point is in the middle of a face edge defined // a point is defined as follows:
// by two nodes, else it is at node1ID1 // ( node*ID1 > 0 && node*ID2 > 0 ) ==> point is in the middle of an edge defined by two nodes
// ( node*ID1 > 0 && node*ID2 <=0 ) ==> point is at node*ID1
// else ==> point is at xyz*
// point 1
long node1ID1; long node1ID1;
long node1ID2; long node1ID2;
PointStruct xyz1;
// point 2: if node2ID2 > 0, then the point is in the middle of a face edge defined // point 2
// by two nodes, else it is at node2ID1
long node2ID1; long node2ID1;
long node2ID2; long node2ID2;
PointStruct xyz2;
DirStruct vector; // vector on the plane; to use a default plane set vector = (0,0,0) // vector on the plane; to use a default plane set vector = (0,0,0)
DirStruct vector;
}; };
typedef sequence<PolySegment> ListOfPolySegments; typedef sequence<PolySegment> ListOfPolySegments;
@ -1255,8 +1261,8 @@ module SMESH
/*! /*!
* \brief Create a polyline consisting of 1D mesh elements each lying on a 2D element of * \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 * the initial triangle mesh. Positions of new nodes are found by cutting the mesh by
* plane passing through pairs of points specified by each PolySegment structure. * 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 * 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 * 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. * points and an optional vector lying on the plane specified by a PolySegment.

View File

@ -13050,14 +13050,15 @@ namespace // utils for MakePolyLine
std::vector< gp_XYZ > myPoints; std::vector< gp_XYZ > myPoints;
double myLength; double myLength;
int mySrcPntInd; //!< start point index
const SMDS_MeshElement* myFace; const SMDS_MeshElement* myFace;
SMESH_NodeXYZ myNode1; SMESH_NodeXYZ myNode1; // nodes of the edge the path entered myFace
SMESH_NodeXYZ myNode2; SMESH_NodeXYZ myNode2;
int myNodeInd1; int myNodeInd1;
int myNodeInd2; int myNodeInd2;
double myDot1; double myDot1;
double myDot2; double myDot2;
int mySrcPntInd; //!< start point index
TIDSortedElemSet myElemSet, myAvoidSet; TIDSortedElemSet myElemSet, myAvoidSet;
Path(): myLength(0.0), myFace(0) {} Path(): myLength(0.0), myFace(0) {}
@ -13250,6 +13251,7 @@ namespace // utils for MakePolyLine
myErrors( theSegments.size() ) myErrors( theSegments.size() )
{ {
} }
#undef SMESH_CAUGHT #undef SMESH_CAUGHT
#define SMESH_CAUGHT myErrors[i] = #define SMESH_CAUGHT myErrors[i] =
void operator() ( const int i ) const void operator() ( const int i ) const
@ -13259,6 +13261,7 @@ namespace // utils for MakePolyLine
SMESH_CATCH( SMESH::returnError ); SMESH_CATCH( SMESH::returnError );
} }
#undef SMESH_CAUGHT #undef SMESH_CAUGHT
//================================================================================ //================================================================================
/*! /*!
* \brief Compute a path of a given segment * \brief Compute a path of a given segment
@ -13269,21 +13272,15 @@ namespace // utils for MakePolyLine
{ {
SMESH_MeshEditor::PolySegment& polySeg = mySegments[ iSeg ]; SMESH_MeshEditor::PolySegment& polySeg = mySegments[ iSeg ];
// get a cutting plane // the cutting plane
gp_XYZ plnNorm = ( polySeg.myXYZ[0] - polySeg.myXYZ[1] ) ^ polySeg.myVector.XYZ();
gp_XYZ plnOrig = polySeg.myXYZ[1];
gp_XYZ p1 = SMESH_NodeXYZ( polySeg.myNode1[0] ); // Find paths connecting the 2 end points of polySeg
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] ));
gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
gp_XYZ plnOrig = p2;
// find paths connecting the 2 end points of polySeg
std::vector< Path > paths; paths.reserve(10); std::vector< Path > paths; paths.reserve(10);
// initialize paths // 1) initialize paths; two paths starts at each end point
for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points for ( int iP = 0; iP < 2; ++iP ) // loop on the polySeg end points
{ {
@ -13291,8 +13288,76 @@ namespace // utils for MakePolyLine
path.mySrcPntInd = iP; path.mySrcPntInd = iP;
size_t nbPaths = paths.size(); 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 ] ) 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 ], while (( path.myFace = SMESH_MeshAlgos::FindFaceInSet( polySeg.myNode1[ iP ],
polySeg.myNode2[ iP ], polySeg.myNode2[ iP ],
path.myElemSet, path.myElemSet,
@ -13305,7 +13370,7 @@ namespace // utils for MakePolyLine
path.myDot1 = plnNorm * ( path.myNode1 - plnOrig ); path.myDot1 = plnNorm * ( path.myNode1 - plnOrig );
path.myDot2 = plnNorm * ( path.myNode2 - plnOrig ); path.myDot2 = plnNorm * ( path.myNode2 - plnOrig );
path.myPoints.clear(); path.myPoints.clear();
path.AddPoint( 0.5 * ( path.myNode1 + path.myNode2 )); path.AddPoint( polySeg.myXYZ[ iP ]);
path.myAvoidSet.insert( path.myFace ); path.myAvoidSet.insert( path.myFace );
paths.push_back( path ); paths.push_back( path );
} }
@ -13313,7 +13378,7 @@ namespace // utils for MakePolyLine
throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1 throw SALOME_Exception ( SMESH_Comment("No face edge found by point ") << iP+1
<< " in a PolySegment " << iSeg ); << " in a PolySegment " << iSeg );
} }
else // an end point is at node else if ( polySeg.myNode1[ iP ] ) // the end point is at a node
{ {
std::set<const SMDS_MeshNode* > nodes; std::set<const SMDS_MeshNode* > nodes;
SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face); SMDS_ElemIteratorPtr fIt = polySeg.myNode1[ iP ]->GetInverseElementIterator(SMDSAbs_Face);
@ -13340,7 +13405,7 @@ namespace // utils for MakePolyLine
} }
} }
// extend paths // 2) extend paths and compose the shortest one connecting the two points
myPaths[ iSeg ].myLength = 1e100; myPaths[ iSeg ].myLength = 1e100;
@ -13424,6 +13489,18 @@ void SMESH_MeshEditor::MakePolyLine( TListOfPolySegments& theSegments,
if ( polySeg.myNode2[0] ) p1 = 0.5 * ( p1 + SMESH_NodeXYZ( polySeg.myNode2[0] )); 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] )); 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(); gp_XYZ plnNorm = ( p1 - p2 ) ^ polySeg.myVector.XYZ();
isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits<double>::min() ); isVectorOK[ iSeg ] = ( plnNorm.Modulus() > std::numeric_limits<double>::min() );

View File

@ -721,12 +721,19 @@ public:
// structure used in MakePolyLine() to define a cutting plane // structure used in MakePolyLine() to define a cutting plane
struct PolySegment struct PolySegment
{ {
// 2 points: if myNode2 != 0, then the point is the middle of a face edge defined // 2 points, each defined as follows:
// by two nodes, else it is at myNode1 // ( 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* myNode1[2];
const SMDS_MeshNode* myNode2[2]; const SMDS_MeshNode* myNode2[2];
gp_XYZ myXYZ [2];
gp_Vec myVector; // vector on the plane; to use a default plane set vector = (0,0,0) // 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 // point to return coordinates of a middle of the two points, projected to mesh
gp_Pnt myMidProjPoint; gp_Pnt myMidProjPoint;

View File

@ -1476,9 +1476,9 @@ namespace
//================================================================================ //================================================================================
/*! /*!
* \brief Return of a point relative to a segment * \brief Return position of a point relative to a segment
* \param point2D - the point to analyze position of * \param point2D - the point to analyze position of
* \param xyVec - end points of segments * \param segEnds - end points of segments
* \param index0 - 0-based index of the first point of segment * \param index0 - 0-based index of the first point of segment
* \param posToFindOut - flags of positions to detect * \param posToFindOut - flags of positions to detect
* \retval PointPos - point position * \retval PointPos - point position
@ -1607,23 +1607,33 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
} }
// compute distance // compute distance
PointPos pos = *pntPosSet.begin();
double minDist2 = Precision::Infinite();
for ( std::set< PointPos >::iterator posIt = pntPosSet.begin(); posIt != pntPosSet.end(); ++posIt)
{
PointPos pos = *posIt;
if ( pos._name != pntPosSet.begin()->_name )
break;
switch ( pos._name ) switch ( pos._name )
{ {
case POS_LEFT: case POS_LEFT: // point is most close to an edge
{ {
// point is most close to an edge
gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]); gp_Vec edge( xyz[ pos._index ], xyz[ pos._index+1 ]);
gp_Vec n1p ( xyz[ pos._index ], point ); gp_Vec n1p ( xyz[ pos._index ], point );
double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge
// projection of the point on the edge // projection of the point on the edge
gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ(); gp_XYZ proj = xyz[ pos._index ] + u * edge.XYZ();
if ( closestPnt ) *closestPnt = proj; double dist2 = point.SquareDistance( proj );
return point.Distance( proj ); if ( dist2 < minDist2 )
} {
case POS_RIGHT: if ( closestPnt ) *closestPnt = proj;
minDist2 = dist2;
}
break;
}
case POS_RIGHT: // point is inside the face
{ {
// point is inside the face
double distToFacePlane = Abs( tmpPnt.Y() ); double distToFacePlane = Abs( tmpPnt.Y() );
if ( closestPnt ) if ( closestPnt )
{ {
@ -1638,16 +1648,23 @@ double SMESH_MeshAlgos::GetDistance( const SMDS_MeshFace* face,
} }
return distToFacePlane; return distToFacePlane;
} }
case POS_VERTEX:
case POS_VERTEX: // point is most close to a node
{ {
// point is most close to a node double dist2 = point.SquareDistance( xyz[ pos._index ]);
gp_Vec distVec( point, xyz[ pos._index ]); if ( dist2 < minDist2 )
return distVec.Magnitude(); {
if ( closestPnt ) *closestPnt = xyz[ pos._index ];
minDist2 = dist2;
}
break;
} }
default:; default:;
}
return badDistance; return badDistance;
} }
}
return Sqrt( minDist2 );
}
//======================================================================= //=======================================================================
/*! /*!

View File

@ -7224,15 +7224,15 @@ void SMESH_MeshEditor_i::MakePolyLine(SMESH::ListOfPolySegments& theSegments,
segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 ); segOut.myNode2[0] = meshDS->FindNode( segIn.node1ID2 );
segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 ); segOut.myNode1[1] = meshDS->FindNode( segIn.node2ID1 );
segOut.myNode2[1] = meshDS->FindNode( segIn.node2ID2 ); segOut.myNode2[1] = meshDS->FindNode( segIn.node2ID2 );
segOut.myXYZ[0].SetCoord( segIn.xyz1.x,
segIn.xyz1.y,
segIn.xyz1.z);
segOut.myXYZ[1].SetCoord( segIn.xyz2.x,
segIn.xyz2.y,
segIn.xyz2.z);
segOut.myVector.SetCoord( segIn.vector.PS.x, segOut.myVector.SetCoord( segIn.vector.PS.x,
segIn.vector.PS.y, segIn.vector.PS.y,
segIn.vector.PS.z ); segIn.vector.PS.z );
if ( !segOut.myNode1[0] )
THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node1ID1,
SALOME::BAD_PARAM );
if ( !segOut.myNode1[1] )
THROW_SALOME_CORBA_EXCEPTION( SMESH_Comment( "Invalid node ID: ") << segIn.node2ID1,
SALOME::BAD_PARAM );
} }
// get a static ElementSearcher // get a static ElementSearcher

View File

@ -4536,7 +4536,7 @@ class Mesh(metaclass = MeshMeta):
Parameters: Parameters:
IDsOfElements: the faces to be splitted IDsOfElements: the faces to be splitted
Diag13: is used to choose a diagonal for splitting. Diag13 (boolean): is used to choose a diagonal for splitting.
Returns: Returns:
True in case of success, False otherwise. True in case of success, False otherwise.
@ -4552,7 +4552,7 @@ class Mesh(metaclass = MeshMeta):
Parameters: Parameters:
theObject: the object from which the list of elements is taken, theObject: the object from which the list of elements is taken,
this is :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>` this is :class:`mesh, sub-mesh, group or filter <SMESH.SMESH_IDSource>`
Diag13: is used to choose a diagonal for splitting. Diag13 (boolean): is used to choose a diagonal for splitting.
Returns: Returns:
True in case of success, False otherwise. True in case of success, False otherwise.
@ -6665,7 +6665,7 @@ class Mesh(metaclass = MeshMeta):
def MakePolyLine(self, segments, groupName='', isPreview=False ): def MakePolyLine(self, segments, groupName='', isPreview=False ):
""" """
Create a polyline consisting of 1D mesh elements each lying on a 2D element of 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 the initial triangle mesh. Positions of new nodes are found by cutting the mesh by the
plane passing through pairs of points specified by each :class:`SMESH.PolySegment` structure. plane passing through pairs of points specified by each :class:`SMESH.PolySegment` structure.
If there are several paths connecting a pair of points, the shortest path is 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 selected by the module. Position of the cutting plane is defined by the two
@ -6675,7 +6675,7 @@ class Mesh(metaclass = MeshMeta):
The vector goes from the middle point to the projection point. In case of planar The vector goes from the middle point to the projection point. In case of planar
mesh, the vector is normal to the mesh. mesh, the vector is normal to the mesh.
*segments* [i].vector returns the used vector which goes from the middle point to its projection. In preview mode, *segments* [i].vector returns the used vector which goes from the middle point to its projection.
Parameters: Parameters:
segments: list of :class:`SMESH.PolySegment` defining positions of cutting planes. segments: list of :class:`SMESH.PolySegment` defining positions of cutting planes.