mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2025-01-19 00:30:36 +05:00
0020725: EDF 1242 SMESH : Crash avec Convert lin--> quad avec BLSURF/GHS3D on 64bits
0020721: EDF 1233 SMESH : Crash/bad behavior of 'Convert linear Quadratic with Medium Nodes on Geometry' feature with BLSurf/Ghs3D * Fix GetNodeUV() for the case of surface both U and V periodic. * Protect QFace::GetBoundaryLink() from infinite recursion. * Protect QFace::GetLinkChain() from stack overflow.
This commit is contained in:
parent
d5df7d3273
commit
f01d6dacd5
@ -63,6 +63,7 @@ namespace {
|
|||||||
|
|
||||||
gp_XYZ XYZ(const SMDS_MeshNode* n) { return gp_XYZ(n->X(), n->Y(), n->Z()); }
|
gp_XYZ XYZ(const SMDS_MeshNode* n) { return gp_XYZ(n->X(), n->Y(), n->Z()); }
|
||||||
|
|
||||||
|
enum { U_periodic = 1, V_periodic = 2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
//================================================================================
|
//================================================================================
|
||||||
@ -72,8 +73,9 @@ namespace {
|
|||||||
//================================================================================
|
//================================================================================
|
||||||
|
|
||||||
SMESH_MesherHelper::SMESH_MesherHelper(SMESH_Mesh& theMesh)
|
SMESH_MesherHelper::SMESH_MesherHelper(SMESH_Mesh& theMesh)
|
||||||
: myPar1(0), myPar2(0), myParIndex(0), myMesh(&theMesh), myShapeID(0), myCreateQuadratic(false)
|
: myParIndex(0), myMesh(&theMesh), myShapeID(0), myCreateQuadratic(false)
|
||||||
{
|
{
|
||||||
|
myPar1[0] = myPar2[0] = myPar1[1] = myPar2[1] = 0;
|
||||||
mySetElemOnShape = ( ! myMesh->HasShapeToMesh() );
|
mySetElemOnShape = ( ! myMesh->HasShapeToMesh() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +181,7 @@ void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh)
|
|||||||
}
|
}
|
||||||
SMESHDS_Mesh* meshDS = GetMeshDS();
|
SMESHDS_Mesh* meshDS = GetMeshDS();
|
||||||
myShapeID = meshDS->ShapeToIndex(aSh);
|
myShapeID = meshDS->ShapeToIndex(aSh);
|
||||||
|
myParIndex = 0;
|
||||||
|
|
||||||
// treatment of periodic faces
|
// treatment of periodic faces
|
||||||
for ( TopExp_Explorer eF( aSh, TopAbs_FACE ); eF.More(); eF.Next() )
|
for ( TopExp_Explorer eF( aSh, TopAbs_FACE ); eF.More(); eF.Next() )
|
||||||
@ -193,20 +196,18 @@ void SMESH_MesherHelper::SetSubShape(const TopoDS_Shape& aSh)
|
|||||||
const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
|
const TopoDS_Edge& edge = TopoDS::Edge( exp.Current() );
|
||||||
if ( BRep_Tool::IsClosed( edge, face )) {
|
if ( BRep_Tool::IsClosed( edge, face )) {
|
||||||
// initialize myPar1, myPar2 and myParIndex
|
// initialize myPar1, myPar2 and myParIndex
|
||||||
if ( mySeamShapeIds.empty() ) {
|
gp_Pnt2d uv1, uv2;
|
||||||
gp_Pnt2d uv1, uv2;
|
BRep_Tool::UVPoints( edge, face, uv1, uv2 );
|
||||||
BRep_Tool::UVPoints( edge, face, uv1, uv2 );
|
if ( Abs( uv1.Coord(1) - uv2.Coord(1) ) < Abs( uv1.Coord(2) - uv2.Coord(2) ))
|
||||||
if ( Abs( uv1.Coord(1) - uv2.Coord(1) ) < Abs( uv1.Coord(2) - uv2.Coord(2) ))
|
{
|
||||||
{
|
myParIndex |= U_periodic;
|
||||||
myParIndex = 1; // U periodic
|
myPar1[0] = surface.FirstUParameter();
|
||||||
myPar1 = surface.FirstUParameter();
|
myPar2[0] = surface.LastUParameter();
|
||||||
myPar2 = surface.LastUParameter();
|
}
|
||||||
}
|
else {
|
||||||
else {
|
myParIndex |= V_periodic;
|
||||||
myParIndex = 2; // V periodic
|
myPar1[1] = surface.FirstVParameter();
|
||||||
myPar1 = surface.FirstVParameter();
|
myPar2[1] = surface.LastVParameter();
|
||||||
myPar2 = surface.LastVParameter();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// store seam shape indices, negative if shape encounters twice
|
// store seam shape indices, negative if shape encounters twice
|
||||||
int edgeID = meshDS->ShapeToIndex( edge );
|
int edgeID = meshDS->ShapeToIndex( edge );
|
||||||
@ -299,13 +300,24 @@ void SMESH_MesherHelper::AddTLinkNode(const SMDS_MeshNode* n1,
|
|||||||
|
|
||||||
gp_Pnt2d SMESH_MesherHelper::GetUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const
|
gp_Pnt2d SMESH_MesherHelper::GetUVOnSeam( const gp_Pnt2d& uv1, const gp_Pnt2d& uv2 ) const
|
||||||
{
|
{
|
||||||
double p1 = uv1.Coord( myParIndex );
|
|
||||||
double p2 = uv2.Coord( myParIndex );
|
|
||||||
double p3 = ( Abs( p1 - myPar1 ) < Abs( p1 - myPar2 )) ? myPar2 : myPar1;
|
|
||||||
if ( Abs( p2 - p1 ) > Abs( p2 - p3 ))
|
|
||||||
p1 = p3;
|
|
||||||
gp_Pnt2d result = uv1;
|
gp_Pnt2d result = uv1;
|
||||||
result.SetCoord( myParIndex, p1 );
|
for ( int i = U_periodic; i <= V_periodic ; ++i )
|
||||||
|
{
|
||||||
|
if ( myParIndex & i )
|
||||||
|
{
|
||||||
|
double p1 = uv1.Coord( i );
|
||||||
|
double dp1 = Abs( p1-myPar1[i-1]), dp2 = Abs( p1-myPar2[i-1]);
|
||||||
|
if ( myParIndex == i ||
|
||||||
|
dp1 < ( myPar2[i-1] - myPar2[i-1] ) / 100. ||
|
||||||
|
dp2 < ( myPar2[i-1] - myPar2[i-1] ) / 100. )
|
||||||
|
{
|
||||||
|
double p2 = uv2.Coord( i );
|
||||||
|
double p1Alt = ( dp1 < dp2 ) ? myPar2[i-1] : myPar1[i-1];
|
||||||
|
if ( Abs( p2 - p1 ) > Abs( p2 - p1Alt ))
|
||||||
|
result.SetCoord( i, p1Alt );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,9 +686,11 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetMediumNode(const SMDS_MeshNode* n1,
|
|||||||
if ( uvOK[0] && uvOK[1] )
|
if ( uvOK[0] && uvOK[1] )
|
||||||
{
|
{
|
||||||
if ( IsDegenShape( Pos1->GetShapeId() ))
|
if ( IsDegenShape( Pos1->GetShapeId() ))
|
||||||
uv[0].SetCoord( myParIndex, uv[1].Coord( myParIndex ));
|
if ( myParIndex & U_periodic ) uv[0].SetCoord( 1, uv[1].Coord( 1 ));
|
||||||
|
else uv[0].SetCoord( 2, uv[1].Coord( 2 ));
|
||||||
else if ( IsDegenShape( Pos2->GetShapeId() ))
|
else if ( IsDegenShape( Pos2->GetShapeId() ))
|
||||||
uv[1].SetCoord( myParIndex, uv[0].Coord( myParIndex ));
|
if ( myParIndex & U_periodic ) uv[1].SetCoord( 1, uv[0].Coord( 1 ));
|
||||||
|
else uv[1].SetCoord( 2, uv[0].Coord( 2 ));
|
||||||
|
|
||||||
TopLoc_Location loc;
|
TopLoc_Location loc;
|
||||||
Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
|
Handle(Geom_Surface) S = BRep_Tool::Surface(F,loc);
|
||||||
@ -1393,7 +1407,8 @@ SMESH_MesherHelper:: MType SMESH_MesherHelper::IsQuadraticMesh()
|
|||||||
|
|
||||||
double SMESH_MesherHelper::GetOtherParam(const double param) const
|
double SMESH_MesherHelper::GetOtherParam(const double param) const
|
||||||
{
|
{
|
||||||
return fabs(param-myPar1) < fabs(param-myPar2) ? myPar2 : myPar1;
|
int i = myParIndex & U_periodic ? 0 : 1;
|
||||||
|
return fabs(param-myPar1[i]) < fabs(param-myPar2[i]) ? myPar2[i] : myPar1[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
@ -1504,8 +1519,11 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
mutable vector< const QLink* > _sides;
|
mutable vector< const QLink* > _sides;
|
||||||
mutable bool _sideIsAdded[4]; // added in chain of links
|
mutable bool _sideIsAdded[4]; // added in chain of links
|
||||||
gp_Vec _normal;
|
gp_Vec _normal;
|
||||||
|
#ifdef _DEBUG_
|
||||||
|
mutable const SMDS_MeshElement* _face;
|
||||||
|
#endif
|
||||||
|
|
||||||
QFace( const vector< const QLink*>& links );
|
QFace( const vector< const QLink*>& links, const SMDS_MeshElement* face=0 );
|
||||||
|
|
||||||
void SetVolume(const SMDS_MeshElement* v) const { _volumes[ _volumes[0] ? 1 : 0 ] = v; }
|
void SetVolume(const SMDS_MeshElement* v) const { _volumes[ _volumes[0] ? 1 : 0 ] = v; }
|
||||||
|
|
||||||
@ -1519,16 +1537,16 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
for (int i=0; i<_sides.size(); ++i ) if ( _sides[i] == side ) return i;
|
for (int i=0; i<_sides.size(); ++i ) if ( _sides[i] == side ) return i;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
bool GetLinkChain( int iSide, TChain& chain, SMDS_TypeOfPosition pos, int& error) const;
|
bool GetLinkChain( int iSide, TChain& chain, SMDS_TypeOfPosition pos, int& err) const;
|
||||||
|
|
||||||
bool GetLinkChain( TChainLink& link, TChain& chain, SMDS_TypeOfPosition pos, int& error) const
|
bool GetLinkChain( TChainLink& link, TChain& chain, SMDS_TypeOfPosition pos, int& err) const
|
||||||
{
|
{
|
||||||
int i = LinkIndex( link._qlink );
|
int i = LinkIndex( link._qlink );
|
||||||
if ( i < 0 ) return true;
|
if ( i < 0 ) return true;
|
||||||
_sideIsAdded[i] = true;
|
_sideIsAdded[i] = true;
|
||||||
link.SetFace( this );
|
link.SetFace( this );
|
||||||
// continue from opposite link
|
// continue from opposite link
|
||||||
return GetLinkChain( (i+2)%_sides.size(), chain, pos, error );
|
return GetLinkChain( (i+2)%_sides.size(), chain, pos, err );
|
||||||
}
|
}
|
||||||
bool IsBoundary() const { return !_volumes[1]; }
|
bool IsBoundary() const { return !_volumes[1]; }
|
||||||
|
|
||||||
@ -1538,7 +1556,8 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
const TChainLink& avoidLink,
|
const TChainLink& avoidLink,
|
||||||
TLinkInSet * notBoundaryLink = 0,
|
TLinkInSet * notBoundaryLink = 0,
|
||||||
const SMDS_MeshNode* nodeToContain = 0,
|
const SMDS_MeshNode* nodeToContain = 0,
|
||||||
bool * isAdjacentUsed = 0) const;
|
bool * isAdjacentUsed = 0,
|
||||||
|
int nbRecursionsLeft = -1) const;
|
||||||
|
|
||||||
TLinkInSet GetLinkByNode( const TLinkSet& links,
|
TLinkInSet GetLinkByNode( const TLinkSet& links,
|
||||||
const TChainLink& avoidLink,
|
const TChainLink& avoidLink,
|
||||||
@ -1592,7 +1611,7 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
*/
|
*/
|
||||||
//================================================================================
|
//================================================================================
|
||||||
|
|
||||||
QFace::QFace( const vector< const QLink*>& links )
|
QFace::QFace( const vector< const QLink*>& links, const SMDS_MeshElement* face )
|
||||||
{
|
{
|
||||||
_volumes[0] = _volumes[1] = 0;
|
_volumes[0] = _volumes[1] = 0;
|
||||||
_sides = links;
|
_sides = links;
|
||||||
@ -1613,6 +1632,10 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
_normal /= sqrt( normSqSize );
|
_normal /= sqrt( normSqSize );
|
||||||
else
|
else
|
||||||
_normal.SetCoord(1e-33,0,0);
|
_normal.SetCoord(1e-33,0,0);
|
||||||
|
|
||||||
|
#ifdef _DEBUG_
|
||||||
|
_face = face;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
//================================================================================
|
//================================================================================
|
||||||
/*!
|
/*!
|
||||||
@ -1635,14 +1658,18 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
|
|
||||||
if ( _sides.size() != 4 ) { // triangle - visit all my continous faces
|
if ( _sides.size() != 4 ) { // triangle - visit all my continous faces
|
||||||
MSGBEG( *this );
|
MSGBEG( *this );
|
||||||
for ( int i = 0; i < _sides.size(); ++i ) {
|
list< const QFace* > faces( 1, this );
|
||||||
if ( !_sideIsAdded[i] && _sides[i] ) {
|
for (list< const QFace* >::iterator fIt = faces.begin(); fIt != faces.end(); ++fIt ) {
|
||||||
_sideIsAdded[i]=true;
|
const QFace* face = *fIt;
|
||||||
TChain::iterator chLink = chain.insert( chain.begin(), TChainLink(_sides[i]));
|
for ( int i = 0; i < face->_sides.size(); ++i ) {
|
||||||
chLink->SetFace( this );
|
if ( !face->_sideIsAdded[i] && face->_sides[i] ) {
|
||||||
if ( _sides[i]->MediumPos() >= pos )
|
face->_sideIsAdded[i] = true;
|
||||||
if ( const QFace* f = _sides[i]->GetContinuesFace( this ))
|
TChain::iterator chLink = chain.insert( chain.begin(), TChainLink(face->_sides[i]));
|
||||||
f->GetLinkChain( *chLink, chain, pos, error );
|
chLink->SetFace( face );
|
||||||
|
if ( face->_sides[i]->MediumPos() >= pos )
|
||||||
|
if ( const QFace* contFace = face->_sides[i]->GetContinuesFace( face ))
|
||||||
|
faces.push_back( contFace );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( error < ERR_TRI )
|
if ( error < ERR_TRI )
|
||||||
@ -1659,7 +1686,7 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
chLink->SetFace( this );
|
chLink->SetFace( this );
|
||||||
MSGBEG( *this );
|
MSGBEG( *this );
|
||||||
|
|
||||||
// propagate from rectangle to neighbour faces
|
// propagate from quadrangle to neighbour faces
|
||||||
if ( link->MediumPos() >= pos ) {
|
if ( link->MediumPos() >= pos ) {
|
||||||
int nbLinkFaces = link->_faces.size();
|
int nbLinkFaces = link->_faces.size();
|
||||||
if ( nbLinkFaces == 4 || nbLinkFaces < 4 && link->OnBoundary()) {
|
if ( nbLinkFaces == 4 || nbLinkFaces < 4 && link->OnBoundary()) {
|
||||||
@ -1689,6 +1716,7 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
* \param nodeToContain - node the returned link must contain; if provided, search
|
* \param nodeToContain - node the returned link must contain; if provided, search
|
||||||
* also performed on adjacent faces
|
* also performed on adjacent faces
|
||||||
* \param isAdjacentUsed - returns true if link is found in adjacent faces
|
* \param isAdjacentUsed - returns true if link is found in adjacent faces
|
||||||
|
* \param nbRecursionsLeft - to limit recursion
|
||||||
*/
|
*/
|
||||||
//================================================================================
|
//================================================================================
|
||||||
|
|
||||||
@ -1696,7 +1724,8 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
const TChainLink& avoidLink,
|
const TChainLink& avoidLink,
|
||||||
TLinkInSet * notBoundaryLink,
|
TLinkInSet * notBoundaryLink,
|
||||||
const SMDS_MeshNode* nodeToContain,
|
const SMDS_MeshNode* nodeToContain,
|
||||||
bool * isAdjacentUsed) const
|
bool * isAdjacentUsed,
|
||||||
|
int nbRecursionsLeft) const
|
||||||
{
|
{
|
||||||
TLinkInSet linksEnd = links.end(), boundaryLink = linksEnd;
|
TLinkInSet linksEnd = links.end(), boundaryLink = linksEnd;
|
||||||
|
|
||||||
@ -1709,6 +1738,8 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
continue;
|
continue;
|
||||||
TLinkInSet link = links.find( _sides[iL] );
|
TLinkInSet link = links.find( _sides[iL] );
|
||||||
if ( link == linksEnd ) continue;
|
if ( link == linksEnd ) continue;
|
||||||
|
if ( (*link)->MediumPos() > SMDS_TOP_FACE )
|
||||||
|
continue; // We work on faces here, don't go into a volume
|
||||||
|
|
||||||
// check link
|
// check link
|
||||||
if ( link->IsBoundary() ) {
|
if ( link->IsBoundary() ) {
|
||||||
@ -1725,19 +1756,21 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
if ( boundaryLink != linksEnd ) break;
|
if ( boundaryLink != linksEnd ) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( boundaryLink == linksEnd && nodeToContain ) // cellect adjacent faces
|
if ( boundaryLink == linksEnd && nodeToContain ) // collect adjacent faces
|
||||||
if ( const QFace* adj = link->NextFace( this ))
|
if ( const QFace* adj = link->NextFace( this ))
|
||||||
if ( adj->Contains( nodeToContain ))
|
if ( adj->Contains( nodeToContain ))
|
||||||
adjacentFaces.push_back( make_pair( adj, link ));
|
adjacentFaces.push_back( make_pair( adj, link ));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isAdjacentUsed ) *isAdjacentUsed = false;
|
if ( isAdjacentUsed ) *isAdjacentUsed = false;
|
||||||
if ( boundaryLink == linksEnd && nodeToContain ) // check adjacent faces
|
if ( boundaryLink == linksEnd && nodeToContain && nbRecursionsLeft) // check adjacent faces
|
||||||
{
|
{
|
||||||
|
if ( nbRecursionsLeft < 0 )
|
||||||
|
nbRecursionsLeft = nodeToContain->NbInverseElements();
|
||||||
TFaceLinkList::iterator adj = adjacentFaces.begin();
|
TFaceLinkList::iterator adj = adjacentFaces.begin();
|
||||||
for ( ; boundaryLink == linksEnd && adj != adjacentFaces.end(); ++adj )
|
for ( ; boundaryLink == linksEnd && adj != adjacentFaces.end(); ++adj )
|
||||||
boundaryLink = adj->first->GetBoundaryLink( links, *(adj->second),
|
boundaryLink = adj->first->GetBoundaryLink( links, *(adj->second), 0, nodeToContain,
|
||||||
0, nodeToContain, isAdjacentUsed);
|
isAdjacentUsed, nbRecursionsLeft-1);
|
||||||
if ( isAdjacentUsed ) *isAdjacentUsed = true;
|
if ( isAdjacentUsed ) *isAdjacentUsed = true;
|
||||||
}
|
}
|
||||||
return boundaryLink;
|
return boundaryLink;
|
||||||
@ -1841,6 +1874,8 @@ namespace { // Structures used by FixQuadraticElements()
|
|||||||
int iL1 = (iL + 1) % 3, iL2 = (iL + 2) % 3; // indices of the two other links of triangle
|
int iL1 = (iL + 1) % 3, iL2 = (iL + 2) % 3; // indices of the two other links of triangle
|
||||||
TLinkInSet link1 = theLinks.find( _sides[iL1] );
|
TLinkInSet link1 = theLinks.find( _sides[iL1] );
|
||||||
TLinkInSet link2 = theLinks.find( _sides[iL2] );
|
TLinkInSet link2 = theLinks.find( _sides[iL2] );
|
||||||
|
if ( link1 == theLinks.end() || link2 == theLinks.end() )
|
||||||
|
return thePrevLen;
|
||||||
const QFace* f1 = link1->NextFace( this ); // adjacent faces
|
const QFace* f1 = link1->NextFace( this ); // adjacent faces
|
||||||
const QFace* f2 = link2->NextFace( this );
|
const QFace* f2 = link2->NextFace( this );
|
||||||
|
|
||||||
@ -2360,6 +2395,13 @@ void SMESH_MesherHelper::FixQuadraticElements(bool volumeOnly)
|
|||||||
hasRectFaces = hasRectFaces ||
|
hasRectFaces = hasRectFaces ||
|
||||||
( volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_HEXA ||
|
( volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_HEXA ||
|
||||||
volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_PENTA );
|
volTool.GetVolumeType() == SMDS_VolumeTool::QUAD_PENTA );
|
||||||
|
#ifdef _DEBUG_
|
||||||
|
if ( nbN == 6 )
|
||||||
|
pFace->_face = GetMeshDS()->FindFace(faceNodes[0],faceNodes[2],faceNodes[4]);
|
||||||
|
else
|
||||||
|
pFace->_face = GetMeshDS()->FindFace(faceNodes[0],faceNodes[2],
|
||||||
|
faceNodes[4],faceNodes[6] );
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set< QLink >::iterator pLink = links.begin();
|
set< QLink >::iterator pLink = links.begin();
|
||||||
|
@ -404,8 +404,8 @@ protected:
|
|||||||
|
|
||||||
std::set< int > myDegenShapeIds;
|
std::set< int > myDegenShapeIds;
|
||||||
std::set< int > mySeamShapeIds;
|
std::set< int > mySeamShapeIds;
|
||||||
double myPar1, myPar2; // bounds of a closed periodic surface
|
double myPar1[2], myPar2[2]; // U and V bounds of a closed periodic surface
|
||||||
int myParIndex; // bounds' index (1-U, 2-V)
|
int myParIndex; // bounds' index (1-U, 2-V, 3-both)
|
||||||
|
|
||||||
TopoDS_Shape myShape;
|
TopoDS_Shape myShape;
|
||||||
SMESH_Mesh* myMesh;
|
SMESH_Mesh* myMesh;
|
||||||
|
Loading…
Reference in New Issue
Block a user