mirror of
https://git.salome-platform.org/gitpub/modules/smesh.git
synced 2025-01-14 02:30:33 +05:00
Allow to create polyedres near sewed faces; improve nodes merging to save polyedres; implement polyedres by faces creation.
This commit is contained in:
parent
ee33969d5b
commit
b6545f068b
@ -658,7 +658,8 @@ module SMESH
|
||||
in long FirstNodeID2,
|
||||
in long SecondNodeID2,
|
||||
in long LastNodeID2,
|
||||
in boolean CreatePoly);
|
||||
in boolean CreatePolygons,
|
||||
in boolean CreatePolyedrs);
|
||||
|
||||
Sew_Error SewConformFreeBorders (in long FirstNodeID1,
|
||||
in long SecondNodeID1,
|
||||
@ -671,7 +672,8 @@ module SMESH
|
||||
in long LastNodeIDOnFreeBorder,
|
||||
in long FirstNodeIDOnSide,
|
||||
in long LastNodeIDOnSide,
|
||||
in boolean CreatePoly);
|
||||
in boolean CreatePolygons,
|
||||
in boolean CreatePolyedrs);
|
||||
|
||||
Sew_Error SewSideElements (in long_array IDsOfSide1Elements,
|
||||
in long_array IDsOfSide2Elements,
|
||||
|
@ -104,11 +104,14 @@ module SMESH
|
||||
/*!
|
||||
* Create nodes and elements in <theMesh> using nodes
|
||||
* coordinates computed by either of Apply...() methods.
|
||||
* If CreatePoly is TRUE, replace adjacent faces by polygons,
|
||||
* inserting new nodes in common links.
|
||||
* If CreatePolygons is TRUE, replace adjacent faces by polygons
|
||||
* to keep mesh conformity.
|
||||
* If CreatePolyedrs is TRUE, replace adjacent volumes by polyedrs
|
||||
* to keep mesh conformity.
|
||||
*/
|
||||
boolean MakeMesh (in SMESH_Mesh theMesh,
|
||||
in boolean CreatePoly);
|
||||
in boolean CreatePolygons,
|
||||
in boolean CreatePolyedrs);
|
||||
|
||||
/*!
|
||||
* Return the loaded pattern in the string form to be saved in file
|
||||
|
@ -833,8 +833,8 @@ void SMESH_MeshObj::Update( int theIsClear )
|
||||
// nb nodes
|
||||
int nbNodes = anIndexes[i++];
|
||||
// nodes
|
||||
ASSERT( nbNodes < 9 );
|
||||
const SMDS_MeshNode* aNodes[ 8 ];
|
||||
//ASSERT( nbNodes < 9 );
|
||||
const SMDS_MeshNode* aNodes[ nbNodes ];
|
||||
for ( int iNode = 0; iNode < nbNodes; iNode++ )
|
||||
aNodes[ iNode ] = FindNode( myMesh, anIndexes[i++] );
|
||||
// change
|
||||
|
@ -1985,7 +1985,8 @@ void SMDS_Mesh::RemoveElement(const SMDS_MeshElement * elem,
|
||||
// get finite elements built on elem
|
||||
set<const SMDS_MeshElement*> * s1;
|
||||
if (!hasConstructionEdges() && elem->GetType() == SMDSAbs_Edge ||
|
||||
!hasConstructionFaces() && elem->GetType() == SMDSAbs_Face)
|
||||
!hasConstructionFaces() && elem->GetType() == SMDSAbs_Face ||
|
||||
elem->GetType() == SMDSAbs_Volume)
|
||||
{
|
||||
s1 = new set<const SMDS_MeshElement*>();
|
||||
s1->insert(elem);
|
||||
|
@ -492,11 +492,38 @@ bool SMESH_MeshEditor::Reorient (const SMDS_MeshElement * theElem)
|
||||
}
|
||||
case SMDSAbs_Volume:
|
||||
{
|
||||
SMDS_VolumeTool vTool;
|
||||
if ( !vTool.Set( theElem ))
|
||||
return false;
|
||||
vTool.Inverse();
|
||||
return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
|
||||
if (theElem->IsPoly()) {
|
||||
const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
|
||||
static_cast<const SMDS_PolyhedralVolumeOfNodes*>( theElem );
|
||||
if (!aPolyedre) {
|
||||
MESSAGE("Warning: bad volumic element");
|
||||
return false;
|
||||
}
|
||||
|
||||
int nbFaces = aPolyedre->NbFaces();
|
||||
vector<const SMDS_MeshNode *> poly_nodes;
|
||||
vector<int> quantities (nbFaces);
|
||||
|
||||
// reverse each face of the polyedre
|
||||
for (int iface = 1; iface <= nbFaces; iface++) {
|
||||
int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
|
||||
quantities[iface - 1] = nbFaceNodes;
|
||||
|
||||
for (inode = nbFaceNodes; inode >= 1; inode--) {
|
||||
const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
|
||||
poly_nodes.push_back(curNode);
|
||||
}
|
||||
}
|
||||
|
||||
return GetMeshDS()->ChangePolyhedronNodes( theElem, poly_nodes, quantities );
|
||||
|
||||
} else {
|
||||
SMDS_VolumeTool vTool;
|
||||
if ( !vTool.Set( theElem ))
|
||||
return false;
|
||||
vTool.Inverse();
|
||||
return GetMeshDS()->ChangeElementNodes( theElem, vTool.GetNodes(), vTool.NbNodes() );
|
||||
}
|
||||
}
|
||||
default:;
|
||||
}
|
||||
@ -2620,6 +2647,88 @@ void SMESH_MeshEditor::FindCoincidentNodes (set<const SMDS_MeshNode*> & theNodes
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : SimplifyFace
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
int SMESH_MeshEditor::SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
|
||||
vector<const SMDS_MeshNode *>& poly_nodes,
|
||||
vector<int>& quantities) const
|
||||
{
|
||||
int nbNodes = faceNodes.size();
|
||||
|
||||
if (nbNodes < 3)
|
||||
return 0;
|
||||
|
||||
set<const SMDS_MeshNode*> nodeSet;
|
||||
|
||||
// get simple seq of nodes
|
||||
const SMDS_MeshNode* simpleNodes[ nbNodes ];
|
||||
int iSimple = 0, nbUnique = 0;
|
||||
|
||||
simpleNodes[iSimple++] = faceNodes[0];
|
||||
nbUnique++;
|
||||
for (int iCur = 1; iCur < nbNodes; iCur++) {
|
||||
if (faceNodes[iCur] != simpleNodes[iSimple - 1]) {
|
||||
simpleNodes[iSimple++] = faceNodes[iCur];
|
||||
if (nodeSet.insert( faceNodes[iCur] ).second)
|
||||
nbUnique++;
|
||||
}
|
||||
}
|
||||
int nbSimple = iSimple;
|
||||
if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
|
||||
nbSimple--;
|
||||
iSimple--;
|
||||
}
|
||||
|
||||
if (nbUnique < 3)
|
||||
return 0;
|
||||
|
||||
// separate loops
|
||||
int nbNew = 0;
|
||||
bool foundLoop = (nbSimple > nbUnique);
|
||||
while (foundLoop) {
|
||||
foundLoop = false;
|
||||
set<const SMDS_MeshNode*> loopSet;
|
||||
for (iSimple = 0; iSimple < nbSimple && !foundLoop; iSimple++) {
|
||||
const SMDS_MeshNode* n = simpleNodes[iSimple];
|
||||
if (!loopSet.insert( n ).second) {
|
||||
foundLoop = true;
|
||||
|
||||
// separate loop
|
||||
int iC = 0, curLast = iSimple;
|
||||
for (; iC < curLast; iC++) {
|
||||
if (simpleNodes[iC] == n) break;
|
||||
}
|
||||
int loopLen = curLast - iC;
|
||||
if (loopLen > 2) {
|
||||
// create sub-element
|
||||
nbNew++;
|
||||
quantities.push_back(loopLen);
|
||||
for (; iC < curLast; iC++) {
|
||||
poly_nodes.push_back(simpleNodes[iC]);
|
||||
}
|
||||
}
|
||||
// shift the rest nodes (place from the first loop position)
|
||||
for (iC = curLast + 1; iC < nbSimple; iC++) {
|
||||
simpleNodes[iC - loopLen] = simpleNodes[iC];
|
||||
}
|
||||
nbSimple -= loopLen;
|
||||
iSimple -= loopLen;
|
||||
}
|
||||
} // for (iSimple = 0; iSimple < nbSimple; iSimple++)
|
||||
} // while (foundLoop)
|
||||
|
||||
if (iSimple > 2) {
|
||||
nbNew++;
|
||||
quantities.push_back(iSimple);
|
||||
for (int i = 0; i < iSimple; i++)
|
||||
poly_nodes.push_back(simpleNodes[i]);
|
||||
}
|
||||
|
||||
return nbNew;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : MergeNodes
|
||||
//purpose : In each group, the cdr of nodes are substituted by the first one
|
||||
@ -2699,83 +2808,79 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
|
||||
|
||||
if (elem->GetType() == SMDSAbs_Face) {
|
||||
// Polygon
|
||||
if (nbUniqueNodes < 3) {
|
||||
isOk = false;
|
||||
} else {
|
||||
// get simple seq of nodes
|
||||
const SMDS_MeshNode* simpleNodes[ nbNodes ];
|
||||
int iSimple = 0;
|
||||
vector<const SMDS_MeshNode *> face_nodes (nbNodes);
|
||||
int inode = 0;
|
||||
for (; inode < nbNodes; inode++) {
|
||||
face_nodes[inode] = curNodes[inode];
|
||||
}
|
||||
|
||||
simpleNodes[iSimple++] = curNodes[0];
|
||||
for (iCur = 1; iCur < nbNodes; iCur++) {
|
||||
if (curNodes[iCur] != simpleNodes[iSimple - 1]) {
|
||||
simpleNodes[iSimple++] = curNodes[iCur];
|
||||
vector<const SMDS_MeshNode *> polygons_nodes;
|
||||
vector<int> quantities;
|
||||
int nbNew = SimplifyFace(face_nodes, polygons_nodes, quantities);
|
||||
|
||||
if (nbNew > 0) {
|
||||
inode = 0;
|
||||
for (int iface = 0; iface < nbNew - 1; iface++) {
|
||||
int nbNodes = quantities[iface];
|
||||
vector<const SMDS_MeshNode *> poly_nodes (nbNodes);
|
||||
for (int ii = 0; ii < nbNodes; ii++, inode++) {
|
||||
poly_nodes[ii] = polygons_nodes[inode];
|
||||
}
|
||||
SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
|
||||
if (aShapeId)
|
||||
aMesh->SetMeshElementOnShape(newElem, aShapeId);
|
||||
}
|
||||
int nbSimple = iSimple;
|
||||
if (simpleNodes[nbSimple - 1] == simpleNodes[0]) {
|
||||
nbSimple--;
|
||||
}
|
||||
|
||||
// separate cycles
|
||||
bool foundCycle = (nbSimple > nbUniqueNodes);
|
||||
while (foundCycle) {
|
||||
foundCycle = false;
|
||||
set<const SMDS_MeshNode*> cycleSet;
|
||||
for (iSimple = 0; iSimple < nbSimple && !foundCycle; iSimple++) {
|
||||
const SMDS_MeshNode* n = simpleNodes[iSimple];
|
||||
if (!cycleSet.insert( n ).second) {
|
||||
foundCycle = true;
|
||||
|
||||
// separate cycle
|
||||
int iC = 0, curLast = iSimple;
|
||||
for (; iC < curLast; iC++) {
|
||||
if (simpleNodes[iC] == n) break;
|
||||
}
|
||||
int cycleLen = curLast - iC;
|
||||
if (cycleLen > 2) {
|
||||
// create sub-element
|
||||
vector<const SMDS_MeshNode *> poly_nodes (cycleLen);
|
||||
for (int ii = 0; iC < curLast; iC++) {
|
||||
poly_nodes[ii++] = simpleNodes[iC];
|
||||
}
|
||||
SMDS_MeshElement* newElem = aMesh->AddPolygonalFace(poly_nodes);
|
||||
if (aShapeId)
|
||||
aMesh->SetMeshElementOnShape(newElem, aShapeId);
|
||||
}
|
||||
// put the rest nodes from the first cycle position
|
||||
for (iC = curLast + 1; iC < nbSimple; iC++) {
|
||||
simpleNodes[iC - cycleLen] = simpleNodes[iC];
|
||||
}
|
||||
nbSimple -= cycleLen;
|
||||
}
|
||||
} // for (iSimple = 0; iSimple < nbSimple; iSimple++)
|
||||
} // while (foundCycle)
|
||||
|
||||
if (iSimple > 2) {
|
||||
aMesh->ChangeElementNodes(elem, simpleNodes, nbSimple);
|
||||
} else {
|
||||
isOk = false;
|
||||
}
|
||||
aMesh->ChangeElementNodes(elem, &polygons_nodes[inode], quantities[nbNew - 1]);
|
||||
} else {
|
||||
rmElemIds.push_back(elem->GetID());
|
||||
}
|
||||
|
||||
} else if (elem->GetType() == SMDSAbs_Volume) {
|
||||
// Polyhedral volume
|
||||
if (nbUniqueNodes < 4) {
|
||||
isOk = false;
|
||||
rmElemIds.push_back(elem->GetID());
|
||||
} else {
|
||||
// each face has to be analized in order to check volume validity
|
||||
//aMesh->ChangeElementNodes(elem, uniqueNodes, nbUniqueNodes);
|
||||
isOk = false;
|
||||
const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
|
||||
static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
|
||||
if (aPolyedre) {
|
||||
int nbFaces = aPolyedre->NbFaces();
|
||||
|
||||
vector<const SMDS_MeshNode *> poly_nodes;
|
||||
vector<int> quantities;
|
||||
|
||||
for (int iface = 1; iface <= nbFaces; iface++) {
|
||||
int nbFaceNodes = aPolyedre->NbFaceNodes(iface);
|
||||
vector<const SMDS_MeshNode *> faceNodes (nbFaceNodes);
|
||||
|
||||
for (int inode = 1; inode <= nbFaceNodes; inode++) {
|
||||
const SMDS_MeshNode * faceNode = aPolyedre->GetFaceNode(iface, inode);
|
||||
TNodeNodeMap::iterator nnIt = nodeNodeMap.find(faceNode);
|
||||
if (nnIt != nodeNodeMap.end()) { // faceNode sticks
|
||||
faceNode = (*nnIt).second;
|
||||
}
|
||||
faceNodes[inode - 1] = faceNode;
|
||||
}
|
||||
|
||||
SimplifyFace(faceNodes, poly_nodes, quantities);
|
||||
}
|
||||
|
||||
if (quantities.size() > 3) {
|
||||
// to be done: remove coincident faces
|
||||
}
|
||||
|
||||
if (quantities.size() > 3)
|
||||
aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
|
||||
else
|
||||
rmElemIds.push_back(elem->GetID());
|
||||
|
||||
} else {
|
||||
rmElemIds.push_back(elem->GetID());
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
isOk = false;
|
||||
}
|
||||
|
||||
if (!isOk)
|
||||
rmElemIds.push_back(elem->GetID());
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3021,10 +3126,41 @@ void SMESH_MeshEditor::MergeNodes (TListOfListOfNodes & theGroupsOfNodes)
|
||||
|
||||
} // if ( nbNodes != nbUniqueNodes ) // some nodes stick
|
||||
|
||||
if ( isOk )
|
||||
aMesh->ChangeElementNodes( elem, uniqueNodes, nbUniqueNodes );
|
||||
else
|
||||
if ( isOk ) {
|
||||
if (elem->IsPoly() && elem->GetType() == SMDSAbs_Volume) {
|
||||
// Change nodes of polyedre
|
||||
const SMDS_PolyhedralVolumeOfNodes* aPolyedre =
|
||||
static_cast<const SMDS_PolyhedralVolumeOfNodes*>( elem );
|
||||
if (aPolyedre) {
|
||||
int nbFaces = aPolyedre->NbFaces();
|
||||
|
||||
vector<const SMDS_MeshNode *> poly_nodes;
|
||||
vector<int> quantities (nbFaces);
|
||||
|
||||
for (int iface = 1; iface <= nbFaces; iface++) {
|
||||
int inode, nbFaceNodes = aPolyedre->NbFaceNodes(iface);
|
||||
quantities[iface - 1] = nbFaceNodes;
|
||||
|
||||
for (inode = 1; inode <= nbFaceNodes; inode++) {
|
||||
const SMDS_MeshNode* curNode = aPolyedre->GetFaceNode(iface, inode);
|
||||
|
||||
TNodeNodeMap::iterator nnIt = nodeNodeMap.find( curNode );
|
||||
if (nnIt != nodeNodeMap.end()) { // curNode sticks
|
||||
curNode = (*nnIt).second;
|
||||
}
|
||||
poly_nodes.push_back(curNode);
|
||||
}
|
||||
}
|
||||
aMesh->ChangePolyhedronNodes( elem, poly_nodes, quantities );
|
||||
}
|
||||
} else {
|
||||
// Change regular element or polygon
|
||||
aMesh->ChangeElementNodes( elem, uniqueNodes, nbUniqueNodes );
|
||||
}
|
||||
} else {
|
||||
// Remove invalid regular element or invalid polygon
|
||||
rmElemIds.push_back( elem->GetID() );
|
||||
}
|
||||
|
||||
} // loop on elements
|
||||
|
||||
@ -3300,7 +3436,8 @@ SMESH_MeshEditor::Sew_Error
|
||||
const SMDS_MeshNode* theSideSecondNode,
|
||||
const SMDS_MeshNode* theSideThirdNode,
|
||||
const bool theSideIsFreeBorder,
|
||||
const bool toCreatePoly)
|
||||
const bool toCreatePolygons,
|
||||
const bool toCreatePolyedrs)
|
||||
{
|
||||
MESSAGE("::SewFreeBorder()");
|
||||
Sew_Error aResult = SEW_OK;
|
||||
@ -3523,7 +3660,7 @@ SMESH_MeshEditor::Sew_Error
|
||||
}
|
||||
while ( sideNode != theSideSecondNode );
|
||||
|
||||
if ( hasVolumes && sideNodes.size () != bordNodes.size() ) {
|
||||
if ( hasVolumes && sideNodes.size () != bordNodes.size() && !toCreatePolyedrs) {
|
||||
MESSAGE("VOLUME SPLITTING IS FORBIDDEN");
|
||||
return SEW_VOLUMES_TO_SPLIT; // volume splitting is forbidden
|
||||
}
|
||||
@ -3647,15 +3784,19 @@ SMESH_MeshEditor::Sew_Error
|
||||
list<const SMDS_MeshNode*> & nodeList = (*insertMapIt).second;
|
||||
const SMDS_MeshNode* n12 = nodeList.front(); nodeList.pop_front();
|
||||
const SMDS_MeshNode* n22 = nodeList.front(); nodeList.pop_front();
|
||||
InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePoly );
|
||||
InsertNodesIntoLink( elem, n12, n22, nodeList, toCreatePolygons );
|
||||
// 2. perform insertion into the link of adjacent faces
|
||||
while (true) {
|
||||
const SMDS_MeshElement* adjElem = findAdjacentFace( n12, n22, elem );
|
||||
if ( adjElem )
|
||||
InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePoly );
|
||||
InsertNodesIntoLink( adjElem, n12, n22, nodeList, toCreatePolygons );
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (toCreatePolyedrs) {
|
||||
// perform insertion into the links of adjacent volumes
|
||||
UpdateVolumes(n12, n22, nodeList);
|
||||
}
|
||||
// 3. find an element appeared on n1 and n2 after the insertion
|
||||
insertMap.erase( elem );
|
||||
elem = findAdjacentFace( n1, n2, 0 );
|
||||
@ -3695,18 +3836,22 @@ SMESH_MeshEditor::Sew_Error
|
||||
const SMDS_MeshNode* n1 = nodeList.front(); nodeList.pop_front();
|
||||
const SMDS_MeshNode* n2 = nodeList.front(); nodeList.pop_front();
|
||||
|
||||
InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePoly );
|
||||
InsertNodesIntoLink( elem, n1, n2, nodeList, toCreatePolygons );
|
||||
|
||||
if ( !theSideIsFreeBorder ) {
|
||||
// look for and insert nodes into the faces adjacent to elem
|
||||
while (true) {
|
||||
const SMDS_MeshElement* adjElem = findAdjacentFace( n1, n2, elem );
|
||||
if ( adjElem )
|
||||
InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePoly );
|
||||
InsertNodesIntoLink( adjElem, n1, n2, nodeList, toCreatePolygons );
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (toCreatePolyedrs) {
|
||||
// perform insertion into the links of adjacent volumes
|
||||
UpdateVolumes(n1, n2, nodeList);
|
||||
}
|
||||
}
|
||||
|
||||
} // end: insert new nodes
|
||||
@ -3890,6 +4035,87 @@ void SMESH_MeshEditor::InsertNodesIntoLink(const SMDS_MeshElement* theFace,
|
||||
aMesh->ChangeElementNodes( theFace, newNodes, iSplit == iBestQuad ? 4 : 3 );
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : UpdateVolumes
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
void SMESH_MeshEditor::UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
|
||||
const SMDS_MeshNode* theBetweenNode2,
|
||||
list<const SMDS_MeshNode*>& theNodesToInsert)
|
||||
{
|
||||
SMDS_ElemIteratorPtr invElemIt = theBetweenNode1->GetInverseElementIterator();
|
||||
while (invElemIt->more()) { // loop on inverse elements of theBetweenNode1
|
||||
const SMDS_MeshElement* elem = invElemIt->next();
|
||||
if (elem->GetType() != SMDSAbs_Volume)
|
||||
continue;
|
||||
|
||||
// check, if current volume has link theBetweenNode1 - theBetweenNode2
|
||||
SMDS_VolumeTool aVolume (elem);
|
||||
if (!aVolume.IsLinked(theBetweenNode1, theBetweenNode2))
|
||||
continue;
|
||||
|
||||
// insert new nodes in all faces of the volume, sharing link theBetweenNode1 - theBetweenNode2
|
||||
int iface, nbFaces = aVolume.NbFaces();
|
||||
vector<const SMDS_MeshNode *> poly_nodes;
|
||||
vector<int> quantities (nbFaces);
|
||||
|
||||
for (iface = 0; iface < nbFaces; iface++) {
|
||||
int nbFaceNodes = aVolume.NbFaceNodes(iface), nbInserted = 0;
|
||||
// faceNodes will contain (nbFaceNodes + 1) nodes, last = first
|
||||
const SMDS_MeshNode** faceNodes = aVolume.GetFaceNodes(iface);
|
||||
|
||||
for (int inode = 0; inode < nbFaceNodes; inode++) {
|
||||
poly_nodes.push_back(faceNodes[inode]);
|
||||
|
||||
if (nbInserted == 0) {
|
||||
if (faceNodes[inode] == theBetweenNode1) {
|
||||
if (faceNodes[inode + 1] == theBetweenNode2) {
|
||||
nbInserted = theNodesToInsert.size();
|
||||
|
||||
// add nodes to insert
|
||||
list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.begin();
|
||||
for (; nIt != theNodesToInsert.end(); nIt++) {
|
||||
poly_nodes.push_back(*nIt);
|
||||
}
|
||||
}
|
||||
} else if (faceNodes[inode] == theBetweenNode2) {
|
||||
if (faceNodes[inode + 1] == theBetweenNode1) {
|
||||
nbInserted = theNodesToInsert.size();
|
||||
|
||||
// add nodes to insert in reversed order
|
||||
list<const SMDS_MeshNode*>::iterator nIt = theNodesToInsert.end();
|
||||
nIt--;
|
||||
for (; nIt != theNodesToInsert.begin(); nIt--) {
|
||||
poly_nodes.push_back(*nIt);
|
||||
}
|
||||
poly_nodes.push_back(*nIt);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
}
|
||||
}
|
||||
quantities[iface] = nbFaceNodes + nbInserted;
|
||||
}
|
||||
|
||||
// Replace or update the volume
|
||||
SMESHDS_Mesh *aMesh = GetMeshDS();
|
||||
|
||||
if (elem->IsPoly()) {
|
||||
aMesh->ChangePolyhedronNodes(elem, poly_nodes, quantities);
|
||||
|
||||
} else {
|
||||
int aShapeId = FindShape( elem );
|
||||
|
||||
SMDS_MeshElement* newElem =
|
||||
aMesh->AddPolyhedralVolume(poly_nodes, quantities);
|
||||
if (aShapeId && newElem)
|
||||
aMesh->SetMeshElementOnShape(newElem, aShapeId);
|
||||
|
||||
aMesh->RemoveElement(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : SewSideElements
|
||||
//purpose :
|
||||
|
@ -154,6 +154,12 @@ class SMESH_MeshEditor {
|
||||
// Return list of group of nodes close to each other within theTolerance.
|
||||
// Search among theNodes or in the whole mesh if theNodes is empty.
|
||||
|
||||
int SimplifyFace (const vector<const SMDS_MeshNode *> faceNodes,
|
||||
vector<const SMDS_MeshNode *>& poly_nodes,
|
||||
vector<int>& quantities) const;
|
||||
// Split face, defined by <faceNodes>, into several faces by repeating nodes.
|
||||
// Is used by MergeNodes()
|
||||
|
||||
void MergeNodes (TListOfListOfNodes & theNodeGroups);
|
||||
// In each group, the cdr of nodes are substituted by the first one
|
||||
// in all elements.
|
||||
@ -190,7 +196,8 @@ class SMESH_MeshEditor {
|
||||
const SMDS_MeshNode* theSide2SecondNode,
|
||||
const SMDS_MeshNode* theSide2ThirdNode = 0,
|
||||
const bool theSide2IsFreeBorder = true,
|
||||
const bool toCreatePoly = false);
|
||||
const bool toCreatePolygons = false,
|
||||
const bool toCreatePolyedrs = false);
|
||||
// Sew the free border to the side2 by replacing nodes in
|
||||
// elements on the free border with nodes of the elements
|
||||
// of the side 2. If nb of links in the free border and
|
||||
@ -232,6 +239,12 @@ class SMESH_MeshEditor {
|
||||
// insert theNodesToInsert into theFace between theBetweenNode1 and theBetweenNode2.
|
||||
// If toCreatePoly is true, replace theFace by polygon, else split theFace.
|
||||
|
||||
void UpdateVolumes (const SMDS_MeshNode* theBetweenNode1,
|
||||
const SMDS_MeshNode* theBetweenNode2,
|
||||
std::list<const SMDS_MeshNode*>& theNodesToInsert);
|
||||
// insert theNodesToInsert into all volumes, containing link
|
||||
// theBetweenNode1 - theBetweenNode2, between theBetweenNode1 and theBetweenNode2.
|
||||
|
||||
// static int SortQuadNodes (const SMDS_Mesh * theMesh,
|
||||
// int theNodeIds[] );
|
||||
// // Set 4 nodes of a quadrangle face in a good order.
|
||||
|
@ -3138,7 +3138,9 @@ bool SMESH_Pattern::Apply (const SMDS_MeshVolume* theVolume,
|
||||
// coordinates computed by either of Apply...() methods
|
||||
//=======================================================================
|
||||
|
||||
bool SMESH_Pattern::MakeMesh (SMESH_Mesh* theMesh, bool toCreatePoly)
|
||||
bool SMESH_Pattern::MakeMesh (SMESH_Mesh* theMesh,
|
||||
const bool toCreatePolygons,
|
||||
const bool toCreatePolyedrs)
|
||||
{
|
||||
MESSAGE(" ::MakeMesh() " );
|
||||
if ( !myIsComputed )
|
||||
@ -3371,13 +3373,14 @@ bool SMESH_Pattern::MakeMesh (SMESH_Mesh* theMesh, bool toCreatePoly)
|
||||
editor.Remove( elemIDs, false );
|
||||
}
|
||||
|
||||
if (toCreatePoly && myIs2D) {
|
||||
if (toCreatePolygons) {
|
||||
// replace adjacent faces by polygons, inserting nodes in common link
|
||||
|
||||
map< TNodeSet, list< list<int> > >::iterator linksIt;
|
||||
for (linksIt = myLinks.begin(); linksIt != myLinks.end(); linksIt++) {
|
||||
// end nodes of link
|
||||
set<const SMDS_MeshNode*> ends = linksIt->first;
|
||||
if (ends.size() < 2) continue;
|
||||
set<const SMDS_MeshNode*>::iterator endsIt = ends.begin();
|
||||
const SMDS_MeshNode* n1 = *endsIt;
|
||||
endsIt++;
|
||||
@ -3403,13 +3406,17 @@ bool SMESH_Pattern::MakeMesh (SMESH_Mesh* theMesh, bool toCreatePoly)
|
||||
SMESH_MeshEditor::FindFaceInSet(n1, n2, elemSet, avoidSet);
|
||||
if (adjElem) {
|
||||
SMESH_MeshEditor editor (theMesh);
|
||||
editor.InsertNodesIntoLink(adjElem, n1, n2, link_nodes, toCreatePoly);
|
||||
editor.InsertNodesIntoLink(adjElem, n1, n2, link_nodes, toCreatePolygons);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toCreatePolyedrs) {
|
||||
// replace adjacent volumes by polyedres, inserting nodes in common link
|
||||
|
||||
}
|
||||
|
||||
return setErrorCode( ERR_OK );
|
||||
}
|
||||
|
@ -128,7 +128,9 @@ class SMESH_Pattern {
|
||||
bool GetMappedPoints ( std::list<const gp_XYZ *> & thePoints ) const;
|
||||
// Return nodes coordinates computed by Apply() method
|
||||
|
||||
bool MakeMesh (SMESH_Mesh* theMesh, bool toCreatePoly = false);
|
||||
bool MakeMesh (SMESH_Mesh* theMesh,
|
||||
const bool toCreatePolygons = false,
|
||||
const bool toCreatePolyedrs = false);
|
||||
// Create nodes and elements in <theMesh> using nodes
|
||||
// coordinates computed by either of Apply...() methods
|
||||
|
||||
|
@ -207,7 +207,8 @@ QFrame* SMESHGUI_MeshPatternDlg::createMainFrame( QWidget* theParent )
|
||||
myReverseChk = new QCheckBox( tr( "REVERSE" ), aPatGrp );
|
||||
|
||||
// CreatePoly check box
|
||||
myCreatePolyChk = new QCheckBox( tr( "CREATE_POLYGONS_NEAR_BOUNDARY" ), aPatGrp );
|
||||
myCreatePolygonsChk = new QCheckBox( tr( "CREATE_POLYGONS_NEAR_BOUNDARY" ), aPatGrp );
|
||||
myCreatePolyedrsChk = new QCheckBox( tr( "CREATE_POLYEDRS_NEAR_BOUNDARY" ), aPatGrp );
|
||||
|
||||
// Pictures 2d and 3d
|
||||
for ( int i = 0; i < 2; i++ )
|
||||
@ -392,9 +393,10 @@ bool SMESHGUI_MeshPatternDlg::onApply()
|
||||
myGeomObj[ Object ], myGeomObj[ Vertex1 ], myGeomObj[ Vertex2 ] );
|
||||
}
|
||||
|
||||
bool toCreatePoly = (myCreatePolyChk->isChecked() && (myType == Type_2d));
|
||||
bool toCreatePolygons = myCreatePolygonsChk->isChecked();
|
||||
bool toCreatePolyedrs = myCreatePolyedrsChk->isChecked();
|
||||
|
||||
if ( myPattern->MakeMesh( myMesh, toCreatePoly ) )
|
||||
if ( myPattern->MakeMesh( myMesh, toCreatePolygons, toCreatePolyedrs ) )
|
||||
{
|
||||
mySelection->ClearIObjects();
|
||||
SMESHGUI* aCompGUI = SMESHGUI::GetSMESHGUI();
|
||||
@ -1119,6 +1121,9 @@ void SMESHGUI_MeshPatternDlg::onTypeChanged( int theType )
|
||||
mySelEdit[ Vertex2 ]->setText( "" );
|
||||
mySelEdit[ Ids ] ->setText( "" );
|
||||
|
||||
myCreatePolygonsChk->show();
|
||||
myCreatePolyedrsChk->show();
|
||||
|
||||
if ( theType == Type_2d )
|
||||
{
|
||||
// Geom widgets
|
||||
@ -1126,7 +1131,6 @@ void SMESHGUI_MeshPatternDlg::onTypeChanged( int theType )
|
||||
mySelBtn [ Vertex2 ]->hide();
|
||||
mySelEdit[ Vertex2 ]->hide();
|
||||
myReverseChk->show();
|
||||
myCreatePolyChk->show();
|
||||
myPicture2d->show();
|
||||
myPicture3d->hide();
|
||||
mySelLbl[ Object ]->setText( tr( "FACE" ) );
|
||||
@ -1143,7 +1147,6 @@ void SMESHGUI_MeshPatternDlg::onTypeChanged( int theType )
|
||||
mySelBtn [ Vertex2 ]->show();
|
||||
mySelEdit[ Vertex2 ]->show();
|
||||
myReverseChk->hide();
|
||||
myCreatePolyChk->hide();
|
||||
myPicture2d->hide();
|
||||
myPicture3d->show();
|
||||
mySelLbl[ Object ]->setText( tr( "3D_BLOCK" ) );
|
||||
|
@ -145,7 +145,8 @@ private:
|
||||
QPushButton* myNewBtn;
|
||||
|
||||
QCheckBox* myReverseChk;
|
||||
QCheckBox* myCreatePolyChk;
|
||||
QCheckBox* myCreatePolygonsChk;
|
||||
QCheckBox* myCreatePolyedrsChk;
|
||||
SMESHGUI_PatternWidget* myPicture2d;
|
||||
QFrame* myPicture3d;
|
||||
QLabel* myPreview3d;
|
||||
|
@ -246,9 +246,14 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( QWidget* parent, const char* name, SALOM
|
||||
GroupArgumentsLayout->addWidget( CheckBoxMerge, 2, 0 );
|
||||
|
||||
// Control for the polygons creation instead of splitting
|
||||
CheckBoxPoly = new QCheckBox( GroupArguments, "CheckBoxPoly" );
|
||||
CheckBoxPoly->setText( tr( "CREATE_POLYGONS_INSTEAD_SPLITTING" ) );
|
||||
GroupArgumentsLayout->addWidget( CheckBoxPoly, 3, 0 );
|
||||
CheckBoxPolygons = new QCheckBox( GroupArguments, "CheckBoxPolygons" );
|
||||
CheckBoxPolygons->setText( tr( "CREATE_POLYGONS_INSTEAD_SPLITTING" ) );
|
||||
GroupArgumentsLayout->addWidget( CheckBoxPolygons, 3, 0 );
|
||||
|
||||
// Control for the polyedres creation to obtain conform mesh
|
||||
CheckBoxPolyedrs = new QCheckBox( GroupArguments, "CheckBoxPolyedrs" );
|
||||
CheckBoxPolyedrs->setText( tr( "CREATE_POLYEDRS_NEAR_BOUNDARY" ) );
|
||||
GroupArgumentsLayout->addWidget( CheckBoxPolyedrs, 4, 0 );
|
||||
|
||||
|
||||
SMESHGUI_SewingDlgLayout->addWidget( GroupArguments, 1, 0 );
|
||||
@ -325,7 +330,8 @@ void SMESHGUI_SewingDlg::Init()
|
||||
myActor = 0;
|
||||
myMesh = SMESH::SMESH_Mesh::_nil();
|
||||
CheckBoxMerge->setChecked(false);
|
||||
CheckBoxPoly->setChecked(false);
|
||||
CheckBoxPolygons->setChecked(false);
|
||||
CheckBoxPolyedrs->setChecked(false);
|
||||
SelectionIntoArgument();
|
||||
}
|
||||
|
||||
@ -361,8 +367,12 @@ void SMESHGUI_SewingDlg::ConstructorsClicked(int constructorId)
|
||||
LineEdit6->setEnabled(true);
|
||||
}
|
||||
|
||||
if (constructorId != 0 && CheckBoxPoly->isVisible())
|
||||
CheckBoxPoly->hide();
|
||||
if (constructorId == 1 || constructorId == 3) {
|
||||
if (CheckBoxPolygons->isVisible())
|
||||
CheckBoxPolygons->hide();
|
||||
if (CheckBoxPolyedrs->isVisible())
|
||||
CheckBoxPolyedrs->hide();
|
||||
}
|
||||
|
||||
switch(constructorId)
|
||||
{
|
||||
@ -372,8 +382,10 @@ void SMESHGUI_SewingDlg::ConstructorsClicked(int constructorId)
|
||||
SubGroup1->setTitle( tr( "BORDER_1" ) );
|
||||
SubGroup2->setTitle( tr( "BORDER_2" ) );
|
||||
|
||||
if (!CheckBoxPoly->isVisible())
|
||||
CheckBoxPoly->show();
|
||||
if (!CheckBoxPolygons->isVisible())
|
||||
CheckBoxPolygons->show();
|
||||
if (!CheckBoxPolyedrs->isVisible())
|
||||
CheckBoxPolyedrs->show();
|
||||
|
||||
break;
|
||||
}
|
||||
@ -401,8 +413,10 @@ void SMESHGUI_SewingDlg::ConstructorsClicked(int constructorId)
|
||||
SelectButton5->setEnabled(false);
|
||||
LineEdit5->setEnabled(false);
|
||||
|
||||
if (!CheckBoxPoly->isVisible())
|
||||
CheckBoxPoly->show();
|
||||
if (!CheckBoxPolygons->isVisible())
|
||||
CheckBoxPolygons->show();
|
||||
if (!CheckBoxPolyedrs->isVisible())
|
||||
CheckBoxPolyedrs->show();
|
||||
|
||||
myOk5 = true;
|
||||
|
||||
@ -464,8 +478,9 @@ bool SMESHGUI_SewingDlg::ClickOnApply()
|
||||
if ( IsValid() )
|
||||
{
|
||||
bool toMerge = CheckBoxMerge->isChecked();
|
||||
bool toCreatePoly = CheckBoxPoly->isChecked();
|
||||
|
||||
bool toCreatePolygons = CheckBoxPolygons->isChecked();
|
||||
bool toCreatePolyedrs = CheckBoxPolyedrs->isChecked();
|
||||
|
||||
try
|
||||
{
|
||||
SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor();
|
||||
@ -481,7 +496,8 @@ bool SMESHGUI_SewingDlg::ClickOnApply()
|
||||
LineEdit4->text().toLong(),
|
||||
LineEdit5->text().toLong(),
|
||||
LineEdit6->text().toLong(),
|
||||
toCreatePoly);
|
||||
toCreatePolygons,
|
||||
toCreatePolyedrs);
|
||||
else if (aConstructorId == 1)
|
||||
anError = aMeshEditor->SewConformFreeBorders(LineEdit1->text().toLong(),
|
||||
LineEdit2->text().toLong(),
|
||||
@ -494,7 +510,8 @@ bool SMESHGUI_SewingDlg::ClickOnApply()
|
||||
LineEdit3->text().toLong(),
|
||||
LineEdit4->text().toLong(),
|
||||
LineEdit6->text().toLong(),
|
||||
toCreatePoly);
|
||||
toCreatePolygons,
|
||||
toCreatePolyedrs);
|
||||
else if (aConstructorId == 3)
|
||||
{
|
||||
QStringList aListElementsId1 = QStringList::split( " ", LineEdit1->text(), false);
|
||||
|
@ -111,8 +111,9 @@ private:
|
||||
QLineEdit* LineEdit5;
|
||||
QLineEdit* LineEdit6;
|
||||
QCheckBox* CheckBoxMerge;
|
||||
QCheckBox* CheckBoxPoly;
|
||||
|
||||
QCheckBox* CheckBoxPolygons;
|
||||
QCheckBox* CheckBoxPolyedrs;
|
||||
|
||||
private slots:
|
||||
|
||||
void ConstructorsClicked(int constructorId);
|
||||
|
@ -190,13 +190,11 @@ CORBA::Boolean SMESH_MeshEditor_i::AddPolyhedralVolume
|
||||
{
|
||||
int NbNodes = IDsOfNodes.length();
|
||||
std::vector<const SMDS_MeshNode*> n (NbNodes);
|
||||
//const SMDS_MeshNode* n [NbNodes];
|
||||
for (int i = 0; i < NbNodes; i++)
|
||||
n[i] = GetMeshDS()->FindNode(IDsOfNodes[i]);
|
||||
|
||||
int NbFaces = Quantities.length();
|
||||
std::vector<int> q (NbFaces);
|
||||
//int q [NbFaces];
|
||||
for (int j = 0; j < NbFaces; j++)
|
||||
q[j] = Quantities[j];
|
||||
|
||||
@ -213,13 +211,22 @@ CORBA::Boolean SMESH_MeshEditor_i::AddPolyhedralVolumeByFaces
|
||||
(const SMESH::long_array & IdsOfFaces)
|
||||
{
|
||||
int NbFaces = IdsOfFaces.length();
|
||||
std::vector<const SMDS_MeshFace*> faces (NbFaces);
|
||||
for (int i = 0; i < NbFaces; i++)
|
||||
faces[i] = (SMDS_MeshFace *)GetMeshDS()->FindElement(IdsOfFaces[i]);
|
||||
std::vector<const SMDS_MeshNode*> poly_nodes;
|
||||
std::vector<int> quantities (NbFaces);
|
||||
|
||||
//GetMeshDS()->AddPolyhedralVolumeByFaces(faces);
|
||||
//return true;
|
||||
return false;
|
||||
std::vector<const SMDS_MeshFace*> faces (NbFaces);
|
||||
for (int i = 0; i < NbFaces; i++) {
|
||||
const SMDS_MeshElement* aFace = GetMeshDS()->FindElement(IdsOfFaces[i]);
|
||||
quantities[i] = aFace->NbNodes();
|
||||
|
||||
SMDS_ElemIteratorPtr It = aFace->nodesIterator();
|
||||
while (It->more()) {
|
||||
poly_nodes.push_back(static_cast<const SMDS_MeshNode *>(It->next()));
|
||||
}
|
||||
}
|
||||
|
||||
GetMeshDS()->AddPolyhedralVolume(poly_nodes, quantities);
|
||||
return true;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@ -917,7 +924,8 @@ SMESH::SMESH_MeshEditor::Sew_Error
|
||||
CORBA::Long FirstNodeID2,
|
||||
CORBA::Long SecondNodeID2,
|
||||
CORBA::Long LastNodeID2,
|
||||
CORBA::Boolean CreatePoly)
|
||||
CORBA::Boolean CreatePolygons,
|
||||
CORBA::Boolean CreatePolyedrs)
|
||||
{
|
||||
SMESHDS_Mesh* aMesh = GetMeshDS();
|
||||
|
||||
@ -945,7 +953,8 @@ SMESH::SMESH_MeshEditor::Sew_Error
|
||||
aSide2SecondNode,
|
||||
aSide2ThirdNode,
|
||||
true,
|
||||
CreatePoly) );
|
||||
CreatePolygons,
|
||||
CreatePolyedrs) );
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
@ -985,7 +994,7 @@ SMESH::SMESH_MeshEditor::Sew_Error
|
||||
aSide2SecondNode,
|
||||
aSide2ThirdNode,
|
||||
true,
|
||||
false) );
|
||||
false, false) );
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
@ -999,7 +1008,8 @@ SMESH::SMESH_MeshEditor::Sew_Error
|
||||
CORBA::Long LastNodeIDOnFreeBorder,
|
||||
CORBA::Long FirstNodeIDOnSide,
|
||||
CORBA::Long LastNodeIDOnSide,
|
||||
CORBA::Boolean CreatePoly)
|
||||
CORBA::Boolean CreatePolygons,
|
||||
CORBA::Boolean CreatePolyedrs)
|
||||
{
|
||||
SMESHDS_Mesh* aMesh = GetMeshDS();
|
||||
|
||||
@ -1026,7 +1036,8 @@ SMESH::SMESH_MeshEditor::Sew_Error
|
||||
aSide2SecondNode,
|
||||
aSide2ThirdNode,
|
||||
false,
|
||||
CreatePoly) );
|
||||
CreatePolygons,
|
||||
CreatePolyedrs) );
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
@ -165,7 +165,8 @@ class SMESH_MeshEditor_i: public POA_SMESH::SMESH_MeshEditor
|
||||
CORBA::Long FirstNodeID2,
|
||||
CORBA::Long SecondNodeID2,
|
||||
CORBA::Long LastNodeID2,
|
||||
CORBA::Boolean CreatePoly);
|
||||
CORBA::Boolean CreatePolygons,
|
||||
CORBA::Boolean CreatePolyedrs);
|
||||
SMESH::SMESH_MeshEditor::Sew_Error
|
||||
SewConformFreeBorders(CORBA::Long FirstNodeID1,
|
||||
CORBA::Long SecondNodeID1,
|
||||
@ -178,7 +179,8 @@ class SMESH_MeshEditor_i: public POA_SMESH::SMESH_MeshEditor
|
||||
CORBA::Long LastNodeIDOnFreeBorder,
|
||||
CORBA::Long FirstNodeIDOnSide,
|
||||
CORBA::Long LastNodeIDOnSide,
|
||||
CORBA::Boolean CreatePoly);
|
||||
CORBA::Boolean CreatePolygons,
|
||||
CORBA::Boolean CreatePolyedrs);
|
||||
SMESH::SMESH_MeshEditor::Sew_Error
|
||||
SewSideElements(const SMESH::long_array& IDsOfSide1Elements,
|
||||
const SMESH::long_array& IDsOfSide2Elements,
|
||||
|
@ -297,13 +297,14 @@ SMESH::point_array*
|
||||
//=======================================================================
|
||||
|
||||
CORBA::Boolean SMESH_Pattern_i::MakeMesh (SMESH::SMESH_Mesh_ptr theMesh,
|
||||
const CORBA::Boolean CreatePoly)
|
||||
const CORBA::Boolean CreatePolygons,
|
||||
const CORBA::Boolean CreatePolyedrs)
|
||||
{
|
||||
::SMESH_Mesh* aMesh = getMesh( theMesh );
|
||||
if ( !aMesh )
|
||||
return false;
|
||||
|
||||
return myPattern.MakeMesh( aMesh, CreatePoly );
|
||||
return myPattern.MakeMesh( aMesh, CreatePolygons, CreatePolyedrs );
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
@ -76,7 +76,8 @@ class SMESH_Pattern_i:
|
||||
CORBA::Long theNode001Index);
|
||||
|
||||
CORBA::Boolean MakeMesh (SMESH::SMESH_Mesh_ptr theMesh,
|
||||
const CORBA::Boolean CreatePoly);
|
||||
const CORBA::Boolean CreatePolygons,
|
||||
const CORBA::Boolean CreatePolyedrs);
|
||||
|
||||
SMESH::SMESH_Pattern::ErrorCode GetErrorCode();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user