From: eap Date: Fri, 18 Sep 2015 14:10:34 +0000 (+0300) Subject: IMP 23078: [CEA 1498] Sewing of meshes without having to set the nodes ids X-Git-Tag: V7_7_0b1^0 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=02ac54c6f33c5437c1d2204d704cf3da6fd31a8e;p=modules%2Fsmesh.git IMP 23078: [CEA 1498] Sewing of meshes without having to set the nodes ids --- diff --git a/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc b/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc index c014ee634..308a6899a 100644 --- a/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc +++ b/doc/salome/gui/SMESH/input/2d_meshing_hypo.doc @@ -38,7 +38,7 @@ the meshed face boundary. \image html hypo_quad_params_dialog.png "Quadrangle parameters: Transition" -Quadrangle parameters is a hypothesis for Quadrangle (Mapping) algorithm. +Quadrangle parameters is a hypothesis for \ref quad_ijk_algo_page. Transition tab is used to define the algorithm of transition between opposite sides of the face with a different number of diff --git a/doc/salome/gui/SMESH/input/creating_groups.doc b/doc/salome/gui/SMESH/input/creating_groups.doc index 61077e052..da12c8337 100644 --- a/doc/salome/gui/SMESH/input/creating_groups.doc +++ b/doc/salome/gui/SMESH/input/creating_groups.doc @@ -23,7 +23,9 @@ elements which will form your group:
  • Name field allows to enter the name of your new group.
  • Color - allows to assign to the group a certain color. The - chosen color is used to display the elements of the group.
  • + chosen color is used to display the elements of the group.
    + Activation of Auto Color item in mesh context menu + switches on a random choice of a color for a new group. Mesh module distinguishes between the three Group types: Standalone Group, Group on Geometry and Group on Filter. diff --git a/doc/salome/gui/SMESH/input/index.doc b/doc/salome/gui/SMESH/input/index.doc index f81ce43ed..9ecb7c5f0 100644 --- a/doc/salome/gui/SMESH/input/index.doc +++ b/doc/salome/gui/SMESH/input/index.doc @@ -16,17 +16,19 @@ either \ref importing_exporting_meshes_page "imported" or manually created); -
  • \ref importing_exporting_meshes_page "importing and exporting meshes in various formats";
  • +
  • \ref importing_exporting_meshes_page "importing and exporting meshes" + in various formats;
  • \subpage modifying_meshes_page "modifying meshes" with a vast array of dedicated operations;
  • -
  • \subpage grouping_elements_page "creating groups of mesh - elements";
  • +
  • \subpage grouping_elements_page "creating groups" of mesh + elements;
  • filtering mesh entities (nodes or elements) using \subpage filters_page "Filters" functionality for \ref grouping_elements_page "creating groups" and applying \ref modifying_meshes_page "mesh modifications";
  • \subpage viewing_meshes_overview_page "viewing meshes" in - the VTK viewer;
  • + the VTK viewer and \ref mesh_infos_page "getting info" on mesh + and its sub-objects;
  • applying to meshes \subpage quality_page "Quality Controls", allowing to highlight important elements;
  • taking various \subpage measurements_page "measurements" of the diff --git a/doc/salome/gui/SMESH/input/merging_nodes.doc b/doc/salome/gui/SMESH/input/merging_nodes.doc index 439e1fea3..31c93f771 100644 --- a/doc/salome/gui/SMESH/input/merging_nodes.doc +++ b/doc/salome/gui/SMESH/input/merging_nodes.doc @@ -21,10 +21,10 @@ then converted to the single node. processed.
  • \b Tolerance is a maximum distance between nodes sufficient for merging.
  • -
  • Activation of No merge of corner and medium nodes check-box - prevents merging medium nodes of quadratic elements with corner - nodes. This check-box is enabled provided that the selected mesh - includes quadratic elements.
  • +
  • Activation of No merge of corner and medium nodes of quadratic + cells check-box prevents merging medium nodes of quadratic + elements with corner nodes. This check-box is enabled provided + that the selected mesh includes quadratic elements.
  • Exclude Groups group box allows to ignore the nodes which belong to the specified mesh groups.
  • Nodes to keep group box allows to specify nodes to keep in diff --git a/doc/salome/gui/SMESH/input/mesh_infos.doc b/doc/salome/gui/SMESH/input/mesh_infos.doc index cd9860ae8..2013cd426 100644 --- a/doc/salome/gui/SMESH/input/mesh_infos.doc +++ b/doc/salome/gui/SMESH/input/mesh_infos.doc @@ -14,14 +14,16 @@ in the toolbar. "Mesh Information" button The Mesh Information dialog box provides three tab pages: -- \ref advanced_mesh_infos_anchor "Base Info" - to show base -information about the selected mesh object. +- \ref advanced_mesh_infos_anchor "Base Info" - to show + base and quantitative information about the selected mesh object. - \ref mesh_element_info_anchor "Element Info" - to show -detailed information about the selected mesh node or element. -- \ref mesh_addition_info_anchor "Additional Info" - to show additional information available -for the selected mesh, sub-mesh or group object. + detailed information about the selected mesh nodes or elements. +- \ref mesh_addition_info_anchor "Additional Info" - to show + additional information available for the selected mesh, sub-mesh or + group object. - \ref mesh_quality_info_anchor "Quality Info" - to show -overall quality information about the selected mesh, sub-mesh or group object. + overall quality information about the selected mesh, sub-mesh or group + object. \anchor advanced_mesh_infos_anchor

    Base Information

    diff --git a/doc/salome/gui/SMESH/input/sewing_meshes.doc b/doc/salome/gui/SMESH/input/sewing_meshes.doc index b7640f30b..8b7bb76c4 100644 --- a/doc/salome/gui/SMESH/input/sewing_meshes.doc +++ b/doc/salome/gui/SMESH/input/sewing_meshes.doc @@ -27,7 +27,13 @@ the type of sewing operation you would like to perform.
  • \anchor free_borders_anchor

    Sew free borders

    -This functionality allows you to unite two free borders of a 2D mesh. +This functionality allows you to unite free borders of a 2D mesh. + +There are two working modes: \a Automatic and \a Manual. In the \b +Automatic mode, the program finds free borders coincident within a +certain tolerance and sew them. Optionally it is possible to adjust +the found free borders before sewing. In the \b Manual mode you are to +define borders to sew by picking three nodes of each border. \image html sewing1.png diff --git a/doc/salome/gui/SMESH/input/viewing_meshes_overview.doc b/doc/salome/gui/SMESH/input/viewing_meshes_overview.doc index 248685579..2472c24fa 100644 --- a/doc/salome/gui/SMESH/input/viewing_meshes_overview.doc +++ b/doc/salome/gui/SMESH/input/viewing_meshes_overview.doc @@ -26,8 +26,11 @@ information about the mesh.
  • \subpage find_element_by_point_page "Find Element by Point" - allows to find all mesh elements, to which belongs a point with the given coordinates.
  • -
  • Auto Color - switch on / off auto-assigning colors for the groups.
  • -
  • \subpage numbering_page "Numbering" - allows to display the ID +
  • Auto Color - switch on / off auto-assigning colors for the + groups. If switched on, a default color of a new group in + \ref creating_groups_page "Create Group" dialog is chosen + randomly.
  • +
  • \subpage numbering_page "Numbering" - allows to display the ID numbers of all meshing elements or nodes composing your mesh in the viewer.
  • \subpage display_mode_page "Display Mode" - allows to select between diff --git a/idl/SMESH_MeshEditor.idl b/idl/SMESH_MeshEditor.idl index 57f50fb50..8c63fdbda 100644 --- a/idl/SMESH_MeshEditor.idl +++ b/idl/SMESH_MeshEditor.idl @@ -29,13 +29,37 @@ module SMESH { + interface NumericalFunctor; + enum Bnd_Dimension { BND_2DFROM3D, BND_1DFROM3D, BND_1DFROM2D }; + + struct FreeBorder + { + SMESH::long_array nodeIDs; // all nodes defining a free border + // 1st and last node is same in a closed border + }; + struct FreeBorderPart + { + short border; // border index within a sequence + long node1; // node index within the border-th FreeBorder + long node2; + long nodeLast; + }; + typedef sequence ListOfFreeBorders; + typedef sequence FreeBordersGroup; + typedef sequence ListOfFreeBorderGroups; + + struct CoincidentFreeBorders + { + ListOfFreeBorders borders; // nodes of all free borders + ListOfFreeBorderGroups coincidentGroups; // groups of coincident parts of borders + }; + + /*! * This interface makes modifications on the Mesh - removing elements and nodes etc. */ - interface NumericalFunctor; - interface SMESH_MeshEditor { /*! @@ -723,6 +747,21 @@ module SMESH short GetPointState(in double x, in double y, in double z) raises (SALOME::SALOME_Exception); + /*! + * Returns groups of FreeBorder's coincident within the given tolerance. + * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent + * to free borders being compared is used. + */ + CoincidentFreeBorders FindCoincidentFreeBorders(in double tolerance); + + /*! + * Sew FreeBorder's of each group + */ + short SewCoincidentFreeBorders (in CoincidentFreeBorders freeBorders, + in boolean createPolygons, + in boolean createPolyedrs) + raises (SALOME::SALOME_Exception); + enum Sew_Error { SEW_OK, SEW_BORDER1_NOT_FOUND, diff --git a/src/OBJECT/SMESH_Object.cxx b/src/OBJECT/SMESH_Object.cxx index bcb589937..1767ddf37 100644 --- a/src/OBJECT/SMESH_Object.cxx +++ b/src/OBJECT/SMESH_Object.cxx @@ -559,22 +559,8 @@ bool SMESH_VisualObjDef::GetEdgeNodes( const int theElemId, if ( theEdgeNum < 0 || theEdgeNum > 3 || (nbNodes != 3 && nbNodes != 4) || theEdgeNum > nbNodes ) return false; - vector anIds( nbNodes ); - SMDS_ElemIteratorPtr anIter = anElem->nodesIterator(); - int i = 0; - while( anIter->more() && i < nbNodes ) - anIds[ i++ ] = anIter->next()->GetID(); - - if ( theEdgeNum < nbNodes - 1 ) - { - theNodeId1 = anIds[ theEdgeNum ]; - theNodeId2 = anIds[ theEdgeNum + 1 ]; - } - else - { - theNodeId1 = anIds[ nbNodes - 1 ]; - theNodeId2 = anIds[ 0 ]; - } + theNodeId1 = anElem->GetNode( theEdgeNum - 1 )->GetID(); + theNodeId2 = anElem->GetNode( theEdgeNum % nbNodes )->GetID(); return true; } diff --git a/src/SMDS/SMDS_MeshNode.cxx b/src/SMDS/SMDS_MeshNode.cxx index 3bd528bb7..3524480cc 100644 --- a/src/SMDS/SMDS_MeshNode.cxx +++ b/src/SMDS/SMDS_MeshNode.cxx @@ -42,7 +42,7 @@ int SMDS_MeshNode::nbNodes =0; //======================================================================= //function : SMDS_MeshNode -//purpose : +//purpose : //======================================================================= SMDS_MeshNode::SMDS_MeshNode() : SMDS_MeshElement(-1, -1, 0), @@ -83,31 +83,31 @@ SMDS_MeshNode::~SMDS_MeshNode() //======================================================================= //function : RemoveInverseElement -//purpose : +//purpose : //======================================================================= void SMDS_MeshNode::RemoveInverseElement(const SMDS_MeshElement * parent) { - //MESSAGE("RemoveInverseElement " << myID << " " << parent->GetID()); - const SMDS_MeshCell* cell = dynamic_cast(parent); - MYASSERT(cell); - SMDS_Mesh::_meshList[myMeshId]->getGrid()->RemoveReferenceToCell(myVtkID, cell->getVtkId()); + //MESSAGE("RemoveInverseElement " << myID << " " << parent->GetID()); + const SMDS_MeshCell* cell = dynamic_cast(parent); + MYASSERT(cell); + SMDS_Mesh::_meshList[myMeshId]->getGrid()->RemoveReferenceToCell(myVtkID, cell->getVtkId()); } //======================================================================= //function : Print -//purpose : +//purpose : //======================================================================= void SMDS_MeshNode::Print(ostream & OS) const { - OS << "Node <" << myID << "> : X = " << X() << " Y = " - << Y() << " Z = " << Z() << endl; + OS << "Node <" << myID << "> : X = " << X() << " Y = " + << Y() << " Z = " << Z() << endl; } //======================================================================= //function : SetPosition -//purpose : +//purpose : //======================================================================= void SMDS_MeshNode::SetPosition(const SMDS_PositionPtr& aPos) @@ -121,7 +121,7 @@ void SMDS_MeshNode::SetPosition(const SMDS_PositionPtr& aPos) //======================================================================= //function : GetPosition -//purpose : +//purpose : //======================================================================= const SMDS_PositionPtr& SMDS_MeshNode::GetPosition() const @@ -178,10 +178,10 @@ public: int smdsId = myMesh->fromVtkToSmds(vtkId); const SMDS_MeshElement* elem = myMesh->FindElement(smdsId); if (!elem) - { - MESSAGE("SMDS_MeshNode_MyInvIterator problem Null element"); - throw SALOME_Exception("SMDS_MeshNode_MyInvIterator problem Null element"); - } + { + MESSAGE("SMDS_MeshNode_MyInvIterator problem Null element"); + throw SALOME_Exception("SMDS_MeshNode_MyInvIterator problem Null element"); + } //MESSAGE("vtkId " << vtkId << " smdsId " << smdsId << " " << elem->GetType()); iter++; return elem; @@ -189,11 +189,11 @@ public: }; SMDS_ElemIteratorPtr SMDS_MeshNode:: - GetInverseElementIterator(SMDSAbs_ElementType type) const +GetInverseElementIterator(SMDSAbs_ElementType type) const { - vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID); - //MESSAGE("myID " << myID << " ncells " << l.ncells); - return SMDS_ElemIteratorPtr(new SMDS_MeshNode_MyInvIterator(SMDS_Mesh::_meshList[myMeshId], l.cells, l.ncells, type)); + vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID); + //MESSAGE("myID " << myID << " ncells " << l.ncells); + return SMDS_ElemIteratorPtr(new SMDS_MeshNode_MyInvIterator(SMDS_Mesh::_meshList[myMeshId], l.cells, l.ncells, type)); } // Same as GetInverseElementIterator but the create iterator only return @@ -208,47 +208,47 @@ private: int iter; vector myFiltCells; - public: +public: SMDS_MeshNode_MyIterator(SMDS_Mesh *mesh, vtkIdType* cells, int ncells, SMDSAbs_ElementType type): myMesh(mesh), myCells(cells), myNcells(ncells), myType(type), iter(0) { - //MESSAGE("myNcells " << myNcells); - for (; iterfromVtkToSmds(vtkId); - //MESSAGE("vtkId " << vtkId << " smdsId " << smdsId); - const SMDS_MeshElement* elem = myMesh->FindElement(smdsId); - if (elem->GetType() == type) - myFiltCells.push_back((SMDS_MeshElement*)elem); - } - myNcells = myFiltCells.size(); - //MESSAGE("myNcells " << myNcells); - iter = 0; - //MESSAGE("SMDS_MeshNode_MyIterator (filter) " << ncells << " " << myNcells); + //MESSAGE("myNcells " << myNcells); + for (; iterfromVtkToSmds(vtkId); + //MESSAGE("vtkId " << vtkId << " smdsId " << smdsId); + const SMDS_MeshElement* elem = myMesh->FindElement(smdsId); + if (elem->GetType() == type) + myFiltCells.push_back((SMDS_MeshElement*)elem); + } + myNcells = myFiltCells.size(); + //MESSAGE("myNcells " << myNcells); + iter = 0; + //MESSAGE("SMDS_MeshNode_MyIterator (filter) " << ncells << " " << myNcells); } bool more() { - return (iter< myNcells); + return (iter< myNcells); } const SMDS_MeshElement* next() { - const SMDS_MeshElement* elem = myFiltCells[iter]; - iter++; - return elem; + const SMDS_MeshElement* elem = myFiltCells[iter]; + iter++; + return elem; } }; SMDS_ElemIteratorPtr SMDS_MeshNode:: - elementsIterator(SMDSAbs_ElementType type) const +elementsIterator(SMDSAbs_ElementType type) const { if(type==SMDSAbs_Node) - return SMDS_MeshElement::elementsIterator(SMDSAbs_Node); + return SMDS_MeshElement::elementsIterator(SMDSAbs_Node); else { vtkCellLinks::Link l = SMDS_Mesh::_meshList[myMeshId]->getGrid()->GetCellLinks()->GetLink(myVtkID); @@ -258,7 +258,7 @@ SMDS_ElemIteratorPtr SMDS_MeshNode:: int SMDS_MeshNode::NbNodes() const { - return 1; + return 1; } double* SMDS_MeshNode::getCoord() const @@ -305,7 +305,7 @@ void SMDS_MeshNode::setXYZ(double x, double y, double z) SMDSAbs_ElementType SMDS_MeshNode::GetType() const { - return SMDSAbs_Node; + return SMDSAbs_Node; } vtkIdType SMDS_MeshNode::GetVtkType() const @@ -358,11 +358,11 @@ int SMDS_MeshNode::NbInverseElements(SMDSAbs_ElementType type) const int nb = 0; SMDS_Mesh *mesh = SMDS_Mesh::_meshList[myMeshId]; for (int i=0; iFindElement(mesh->fromVtkToSmds(l.cells[i])); - if (elem->GetType() == type) - nb++; - } + { + const SMDS_MeshElement* elem = mesh->FindElement(mesh->fromVtkToSmds(l.cells[i])); + if (elem->GetType() == type) + nb++; + } return nb; } @@ -371,14 +371,14 @@ int SMDS_MeshNode::NbInverseElements(SMDSAbs_ElementType type) const /////////////////////////////////////////////////////////////////////////////// bool operator<(const SMDS_MeshNode& e1, const SMDS_MeshNode& e2) { - return e1.getVtkId() faces; - if ( nbElems > 0 ) { - SMDS_ElemIteratorPtr fIt = fSubMesh->GetElements(); - while ( fIt->more() ) { - const SMDS_MeshElement* f = fIt->next(); - if ( f && f->GetType() == SMDSAbs_Face ) - faces.push_back( f ); - } - } - else { - SMDS_FaceIteratorPtr fIt = aMeshDS->facesIterator(); - while ( fIt->more() ) - faces.push_back( fIt->next() ); - } + SMDS_ElemIteratorPtr fIt; + if ( nbElems > 0 ) + fIt = fSubMesh->GetElements(); + else + fIt = aMeshDS->elementsIterator( SMDSAbs_Face ); // put nodes of all faces into the nodePointIDMap and fill myElemPointIDs - list< const SMDS_MeshElement* >::iterator fIt = faces.begin(); - for ( ; fIt != faces.end(); ++fIt ) + while ( fIt->more() ) { + const SMDS_MeshElement* face = fIt->next(); myElemPointIDs.push_back( TElemDef() ); TElemDef& elemPoints = myElemPointIDs.back(); - int nbNodes = (*fIt)->NbCornerNodes(); + int nbNodes = face->NbCornerNodes(); for ( int i = 0;i < nbNodes; ++i ) { - const SMDS_MeshElement* node = (*fIt)->GetNode( i ); + const SMDS_MeshElement* node = face->GetNode( i ); TNodePointIDMap::iterator nIdIt = nodePointIDMap.insert( make_pair( node, -1 )).first; if ( nIdIt->second == -1 ) - { - elemPoints.push_back( iPoint ); nIdIt->second = iPoint++; - } - else - elemPoints.push_back( (*nIdIt).second ); + elemPoints.push_back( (*nIdIt).second ); } } myPoints.resize( iPoint ); diff --git a/src/SMESHGUI/CMakeLists.txt b/src/SMESHGUI/CMakeLists.txt index b334baa56..c62f185e4 100644 --- a/src/SMESHGUI/CMakeLists.txt +++ b/src/SMESHGUI/CMakeLists.txt @@ -142,6 +142,8 @@ SET(_moc_HEADERS SMESHGUI_FieldSelectorWdg.h SMESHGUI_DisplayEntitiesDlg.h SMESHGUI_SplitBiQuad.h + SMESHGUI_PreVisualObj.h + SMESHGUI_IdPreview.h ) # header files / no moc processing @@ -251,6 +253,8 @@ SET(_other_SOURCES SMESHGUI_FieldSelectorWdg.cxx SMESHGUI_DisplayEntitiesDlg.cxx SMESHGUI_SplitBiQuad.cxx + SMESHGUI_PreVisualObj.cxx + SMESHGUI_IdPreview.cxx ) # sources / to compile diff --git a/src/SMESHGUI/SMESHGUI_IdPreview.cxx b/src/SMESHGUI/SMESHGUI_IdPreview.cxx new file mode 100644 index 000000000..7999bee3e --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_IdPreview.cxx @@ -0,0 +1,202 @@ +// Copyright (C) 2007-2015 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 +// + +#include "SMESHGUI_IdPreview.h" + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Extracted from SMESHGUI_MergeDlg.cxx + +SMESHGUI_IdPreview::SMESHGUI_IdPreview(SVTK_ViewWindow* theViewWindow): + myViewWindow(theViewWindow) +{ + myIdGrid = vtkUnstructuredGrid::New(); + + // Create and display actor + vtkDataSetMapper* aMapper = vtkDataSetMapper::New(); + aMapper->SetInputData( myIdGrid ); + + myIdActor = SALOME_Actor::New(); + myIdActor->SetInfinitive(true); + myIdActor->VisibilityOff(); + myIdActor->PickableOff(); + + myIdActor->SetMapper( aMapper ); + aMapper->Delete(); + + myViewWindow->AddActor(myIdActor); + + //Definition of points numbering pipeline + myPointsNumDataSet = vtkUnstructuredGrid::New(); + + myPtsMaskPoints = vtkMaskPoints::New(); + myPtsMaskPoints->SetInputData(myPointsNumDataSet); + myPtsMaskPoints->SetOnRatio(1); + + myPtsSelectVisiblePoints = vtkSelectVisiblePoints::New(); + myPtsSelectVisiblePoints->SetInputConnection(myPtsMaskPoints->GetOutputPort()); + myPtsSelectVisiblePoints->SelectInvisibleOff(); + myPtsSelectVisiblePoints->SetTolerance(0.1); + + myPtsLabeledDataMapper = vtkLabeledDataMapper::New(); + myPtsLabeledDataMapper->SetInputConnection(myPtsSelectVisiblePoints->GetOutputPort()); + myPtsLabeledDataMapper->SetLabelModeToLabelScalars(); + + vtkTextProperty* aPtsTextProp = vtkTextProperty::New(); + aPtsTextProp->SetFontFamilyToTimes(); + static int aPointsFontSize = 12; + aPtsTextProp->SetFontSize(aPointsFontSize); + aPtsTextProp->SetBold(1); + aPtsTextProp->SetItalic(0); + aPtsTextProp->SetShadow(0); + myPtsLabeledDataMapper->SetLabelTextProperty(aPtsTextProp); + aPtsTextProp->Delete(); + + myIsPointsLabeled = false; + + myPointLabels = vtkActor2D::New(); + myPointLabels->SetMapper(myPtsLabeledDataMapper); + myPointLabels->GetProperty()->SetColor(1,1,1); + myPointLabels->SetVisibility(myIsPointsLabeled); + + AddToRender(myViewWindow->getRenderer()); +} + +void SMESHGUI_IdPreview::SetPointsData ( SMDS_Mesh* theMesh, + const TColStd_MapOfInteger & theNodesIdMap ) +{ + vtkPoints* aPoints = vtkPoints::New(); + aPoints->SetNumberOfPoints(theNodesIdMap.Extent()); + myIDs.clear(); + + TColStd_MapIteratorOfMapOfInteger idIter( theNodesIdMap ); + for( int i = 0; idIter.More(); idIter.Next(), i++ ) + { + const SMDS_MeshNode* aNode = theMesh->FindNode(idIter.Key()); + aPoints->SetPoint( i, aNode->X(), aNode->Y(), aNode->Z() ); + myIDs.push_back(idIter.Key()); + } + + myIdGrid->SetPoints(aPoints); + + aPoints->Delete(); + + myIdActor->GetMapper()->Update(); +} + +void SMESHGUI_IdPreview::SetElemsData( const std::vector & theElemsIdMap, + const std::list & aGrCentersXYZ ) +{ + vtkPoints* aPoints = vtkPoints::New(); + aPoints->SetNumberOfPoints( theElemsIdMap.size() ); + myIDs = theElemsIdMap; + + std::list::const_iterator coordIt = aGrCentersXYZ.begin(); + for( int i = 0; coordIt != aGrCentersXYZ.end(); coordIt++, i++ ) + aPoints->SetPoint( i, coordIt->X(), coordIt->Y(), coordIt->Z() ); + + myIdGrid->SetPoints(aPoints); + aPoints->Delete(); + + myIdActor->GetMapper()->Update(); +} + +void SMESHGUI_IdPreview::AddToRender(vtkRenderer* theRenderer) +{ + myIdActor->AddToRender(theRenderer); + + myPtsSelectVisiblePoints->SetRenderer(theRenderer); + theRenderer->AddActor2D(myPointLabels); +} + +void SMESHGUI_IdPreview::RemoveFromRender(vtkRenderer* theRenderer) +{ + myIdActor->RemoveFromRender(theRenderer); + + myPtsSelectVisiblePoints->SetRenderer(theRenderer); + theRenderer->RemoveActor(myPointLabels); +} + +void SMESHGUI_IdPreview::SetPointsLabeled( bool theIsPointsLabeled, bool theIsActorVisible ) +{ + myIsPointsLabeled = theIsPointsLabeled && myIdGrid->GetNumberOfPoints(); + + if ( myIsPointsLabeled ) { + myPointsNumDataSet->ShallowCopy(myIdGrid); + vtkDataSet *aDataSet = myPointsNumDataSet; + int aNbElem = myIDs.size(); + vtkIntArray *anArray = vtkIntArray::New(); + anArray->SetNumberOfValues( aNbElem ); + for ( int i = 0; i < aNbElem; i++ ) + anArray->SetValue( i, myIDs[i] ); + aDataSet->GetPointData()->SetScalars( anArray ); + anArray->Delete(); + myPtsMaskPoints->SetInputData( aDataSet ); + myPointLabels->SetVisibility( theIsActorVisible ); + } + else { + myPointLabels->SetVisibility( false ); + } +} + +SMESHGUI_IdPreview::~SMESHGUI_IdPreview() +{ + RemoveFromRender(myViewWindow->getRenderer()); + + myIdGrid->Delete(); + + myViewWindow->RemoveActor(myIdActor); + myIdActor->Delete(); + + //Deleting of points numbering pipeline + //--------------------------------------- + myPointsNumDataSet->Delete(); + + //myPtsLabeledDataMapper->RemoveAllInputs(); //vtk 5.0 porting + myPtsLabeledDataMapper->Delete(); + + //myPtsSelectVisiblePoints->UnRegisterAllOutputs(); //vtk 5.0 porting + myPtsSelectVisiblePoints->Delete(); + + //myPtsMaskPoints->UnRegisterAllOutputs(); //vtk 5.0 porting + myPtsMaskPoints->Delete(); + + myPointLabels->Delete(); + + // myTimeStamp->Delete(); +} diff --git a/src/SMESHGUI/SMESHGUI_IdPreview.h b/src/SMESHGUI/SMESHGUI_IdPreview.h new file mode 100644 index 000000000..ac547ee4c --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_IdPreview.h @@ -0,0 +1,79 @@ +// Copyright (C) 2007-2015 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 +// + +#ifndef SMESHGUI_IdPreview_H +#define SMESHGUI_IdPreview_H + +#include "SMESH_SMESHGUI.hxx" + +#include +#include + +#include + +class SALOME_Actor; +class SMDS_Mesh; +class SVTK_ViewWindow; +class TColStd_MapOfInteger; +class vtkActor2D; +class vtkLabeledDataMapper; +class vtkMaskPoints; +class vtkRenderer; +class vtkSelectVisiblePoints; +class vtkTextProperty; +class vtkUnstructuredGrid; + +/*! + * \brief To display in the viewer IDs of selected elements or nodes + */ +class SMESHGUI_IdPreview +{ +public: + SMESHGUI_IdPreview(SVTK_ViewWindow* theViewWindow); + ~SMESHGUI_IdPreview(); + + void SetPointsData( SMDS_Mesh* theMesh, const TColStd_MapOfInteger & theNodesIdMap ); + void SetElemsData ( const std::vector & theElemsIdMap, + const std::list & theGrCentersXYZ ); + void SetPointsLabeled( bool theIsPointsLabeled, bool theIsActorVisible = true ); + + void AddToRender ( vtkRenderer* theRenderer ); + void RemoveFromRender( vtkRenderer* theRenderer ); + +protected: + + SVTK_ViewWindow* myViewWindow; + + vtkUnstructuredGrid* myIdGrid; + SALOME_Actor* myIdActor; + + vtkUnstructuredGrid* myPointsNumDataSet; + vtkMaskPoints* myPtsMaskPoints; + vtkSelectVisiblePoints* myPtsSelectVisiblePoints; + vtkLabeledDataMapper* myPtsLabeledDataMapper; + bool myIsPointsLabeled; + vtkActor2D* myPointLabels; + + std::vector myIDs; +}; + +#endif diff --git a/src/SMESHGUI/SMESHGUI_MergeDlg.cxx b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx index 92642d384..ec442214e 100644 --- a/src/SMESHGUI/SMESHGUI_MergeDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_MergeDlg.cxx @@ -28,10 +28,11 @@ #include "SMESHGUI_MergeDlg.h" #include "SMESHGUI.h" -#include "SMESHGUI_Utils.h" -#include "SMESHGUI_VTKUtils.h" +#include "SMESHGUI_IdPreview.h" #include "SMESHGUI_MeshUtils.h" #include "SMESHGUI_SpinBox.h" +#include "SMESHGUI_Utils.h" +#include "SMESHGUI_VTKUtils.h" #include #include @@ -61,34 +62,20 @@ #include CORBA_SERVER_HEADER(SMESH_Group) #include CORBA_SERVER_HEADER(SMESH_MeshEditor) -// VTK includes -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - // Qt includes #include +#include +#include +#include #include +#include +#include #include #include #include #include #include -#include -#include #include -#include -#include -#include #define SPACING 6 #define MARGIN 11 @@ -97,208 +84,27 @@ namespace { enum ActionType { MERGE_NODES, MERGE_ELEMENTS, TYPE_AUTO=0, TYPE_MANUAL }; } -namespace SMESH -{ - class TIdPreview - { // to display in the viewer IDs of the selected elements - SVTK_ViewWindow* myViewWindow; - - vtkUnstructuredGrid* myIdGrid; - SALOME_Actor* myIdActor; - - vtkUnstructuredGrid* myPointsNumDataSet; - vtkMaskPoints* myPtsMaskPoints; - vtkSelectVisiblePoints* myPtsSelectVisiblePoints; - vtkLabeledDataMapper* myPtsLabeledDataMapper; - vtkTextProperty* aPtsTextProp; - bool myIsPointsLabeled; - vtkActor2D* myPointLabels; - - std::vector myIDs; - - public: - TIdPreview(SVTK_ViewWindow* theViewWindow): - myViewWindow(theViewWindow) - { - myIdGrid = vtkUnstructuredGrid::New(); - - // Create and display actor - vtkDataSetMapper* aMapper = vtkDataSetMapper::New(); - aMapper->SetInputData( myIdGrid ); - - myIdActor = SALOME_Actor::New(); - myIdActor->SetInfinitive(true); - myIdActor->VisibilityOff(); - myIdActor->PickableOff(); - - myIdActor->SetMapper( aMapper ); - aMapper->Delete(); - - myViewWindow->AddActor(myIdActor); - - //Definition of points numbering pipeline - myPointsNumDataSet = vtkUnstructuredGrid::New(); - - myPtsMaskPoints = vtkMaskPoints::New(); - myPtsMaskPoints->SetInputData(myPointsNumDataSet); - myPtsMaskPoints->SetOnRatio(1); - - myPtsSelectVisiblePoints = vtkSelectVisiblePoints::New(); - myPtsSelectVisiblePoints->SetInputConnection(myPtsMaskPoints->GetOutputPort()); - myPtsSelectVisiblePoints->SelectInvisibleOff(); - myPtsSelectVisiblePoints->SetTolerance(0.1); - - myPtsLabeledDataMapper = vtkLabeledDataMapper::New(); - myPtsLabeledDataMapper->SetInputConnection(myPtsSelectVisiblePoints->GetOutputPort()); - myPtsLabeledDataMapper->SetLabelModeToLabelScalars(); - - vtkTextProperty* aPtsTextProp = vtkTextProperty::New(); - aPtsTextProp->SetFontFamilyToTimes(); - static int aPointsFontSize = 12; - aPtsTextProp->SetFontSize(aPointsFontSize); - aPtsTextProp->SetBold(1); - aPtsTextProp->SetItalic(0); - aPtsTextProp->SetShadow(0); - myPtsLabeledDataMapper->SetLabelTextProperty(aPtsTextProp); - aPtsTextProp->Delete(); - - myIsPointsLabeled = false; - - myPointLabels = vtkActor2D::New(); - myPointLabels->SetMapper(myPtsLabeledDataMapper); - myPointLabels->GetProperty()->SetColor(1,1,1); - myPointLabels->SetVisibility(myIsPointsLabeled); - - AddToRender(myViewWindow->getRenderer()); - } - - void SetPointsData ( SMDS_Mesh* theMesh, - TColStd_MapOfInteger & theNodesIdMap ) - { - vtkPoints* aPoints = vtkPoints::New(); - aPoints->SetNumberOfPoints(theNodesIdMap.Extent()); - myIDs.clear(); - - TColStd_MapIteratorOfMapOfInteger idIter( theNodesIdMap ); - for( int i = 0; idIter.More(); idIter.Next(), i++ ) { - const SMDS_MeshNode* aNode = theMesh->FindNode(idIter.Key()); - aPoints->SetPoint( i, aNode->X(), aNode->Y(), aNode->Z() ); - myIDs.push_back(idIter.Key()); - } - myIdGrid->SetPoints(aPoints); - aPoints->Delete(); - - myIdActor->GetMapper()->Update(); - } - - void SetElemsData( TColStd_MapOfInteger & theElemsIdMap, - std::list & aGrCentersXYZ ) - { - vtkPoints* aPoints = vtkPoints::New(); - aPoints->SetNumberOfPoints(theElemsIdMap.Extent()); - myIDs.clear(); - - TColStd_MapIteratorOfMapOfInteger idIter( theElemsIdMap ); - for( ; idIter.More(); idIter.Next() ) { - myIDs.push_back(idIter.Key()); - } - - gp_XYZ aXYZ; - std::list::iterator coordIt = aGrCentersXYZ.begin(); - for( int i = 0; coordIt != aGrCentersXYZ.end(); coordIt++, i++ ) { - aXYZ = *coordIt; - aPoints->SetPoint( i, aXYZ.X(), aXYZ.Y(), aXYZ.Z() ); - } - myIdGrid->SetPoints(aPoints); - aPoints->Delete(); - - myIdActor->GetMapper()->Update(); - } - - void AddToRender(vtkRenderer* theRenderer) - { - myIdActor->AddToRender(theRenderer); - - myPtsSelectVisiblePoints->SetRenderer(theRenderer); - theRenderer->AddActor2D(myPointLabels); - } - - void RemoveFromRender(vtkRenderer* theRenderer) - { - myIdActor->RemoveFromRender(theRenderer); - - myPtsSelectVisiblePoints->SetRenderer(theRenderer); - theRenderer->RemoveActor(myPointLabels); - } - - void SetPointsLabeled( bool theIsPointsLabeled, bool theIsActorVisible = true ) - { - myIsPointsLabeled = theIsPointsLabeled && myIdGrid->GetNumberOfPoints(); - - if ( myIsPointsLabeled ) { - myPointsNumDataSet->ShallowCopy(myIdGrid); - vtkDataSet *aDataSet = myPointsNumDataSet; - int aNbElem = myIDs.size(); - vtkIntArray *anArray = vtkIntArray::New(); - anArray->SetNumberOfValues( aNbElem ); - for ( int i = 0; i < aNbElem; i++ ) - anArray->SetValue( i, myIDs[i] ); - aDataSet->GetPointData()->SetScalars( anArray ); - anArray->Delete(); - myPtsMaskPoints->SetInputData( aDataSet ); - myPointLabels->SetVisibility( theIsActorVisible ); - } - else { - myPointLabels->SetVisibility( false ); - } - } - - ~TIdPreview() - { - RemoveFromRender(myViewWindow->getRenderer()); - - myIdGrid->Delete(); - - myViewWindow->RemoveActor(myIdActor); - myIdActor->Delete(); - - //Deleting of points numbering pipeline - //--------------------------------------- - myPointsNumDataSet->Delete(); - - //myPtsLabeledDataMapper->RemoveAllInputs(); //vtk 5.0 porting - myPtsLabeledDataMapper->Delete(); - - //myPtsSelectVisiblePoints->UnRegisterAllOutputs(); //vtk 5.0 porting - myPtsSelectVisiblePoints->Delete(); - - //myPtsMaskPoints->UnRegisterAllOutputs(); //vtk 5.0 porting - myPtsMaskPoints->Delete(); - - myPointLabels->Delete(); - -// myTimeStamp->Delete(); - } - }; +QPixmap SMESHGUI_MergeDlg::IconFirst() +{ + static const char * iconFirst[] = { + "18 10 2 1", + " g None", + ". g #000000", + " . . ", + " .. .. .. ", + " .. ... ... ", + " .. .... .... ", + " .. ..... ..... ", + " .. ..... ..... ", + " .. .... .... ", + " .. ... ... ", + " .. .. .. ", + " . . "}; + return iconFirst; } -static const char * IconFirst[] = { -"18 10 2 1", -" g None", -". g #000000", -" . . ", -" .. .. .. ", -" .. ... ... ", -" .. .... .... ", -" .. ..... ..... ", -" .. ..... ..... ", -" .. .... .... ", -" .. ... ... ", -" .. .. .. ", -" . . "}; - //================================================================================= // class : SMESHGUI_MergeDlg() // purpose : @@ -313,7 +119,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction) setAttribute(Qt::WA_DeleteOnClose, true); setWindowTitle(myAction == MERGE_ELEMENTS ? tr("SMESH_MERGE_ELEMENTS") : tr("SMESH_MERGE_NODES")); - myIdPreview = new SMESH::TIdPreview(SMESH::GetViewWindow( mySMESHGUI )); + myIdPreview = new SMESHGUI_IdPreview(SMESH::GetViewWindow( mySMESHGUI )); SUIT_ResourceMgr* aResMgr = SMESH::GetResourceMgr( mySMESHGUI ); QPixmap IconMergeNodes (aResMgr->loadPixmap("SMESH", tr("ICON_SMESH_MERGE_NODES"))); @@ -511,7 +317,7 @@ SMESHGUI_MergeDlg::SMESHGUI_MergeDlg (SMESHGUI* theModule, int theAction) RemoveElemButton = new QPushButton(GroupEdit); RemoveElemButton->setIcon(IconRemove); SetFirstButton = new QPushButton(GroupEdit); - SetFirstButton->setIcon(QPixmap(IconFirst)); + SetFirstButton->setIcon(IconFirst()); GroupEditLayout->addWidget(ListEdit, 0, 0, 2, 1); GroupEditLayout->addWidget(AddElemButton, 0, 1); @@ -645,8 +451,9 @@ void SMESHGUI_MergeDlg::Init() // function : FindGravityCenter() // purpose : //================================================================================= -void SMESHGUI_MergeDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap, - std::list< gp_XYZ > & theGrCentersXYZ) +void SMESHGUI_MergeDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap, + std::vector& theIDs, + std::list< gp_XYZ > & theGrCentersXYZ) { if (!myActor) return; @@ -658,11 +465,13 @@ void SMESHGUI_MergeDlg::FindGravityCenter(TColStd_MapOfInteger & theElemsIdMap, int nbNodes; + theIDs.reserve( theElemsIdMap.Extent() ); TColStd_MapIteratorOfMapOfInteger idIter( theElemsIdMap ); for( ; idIter.More(); idIter.Next() ) { const SMDS_MeshElement* anElem = aMesh->FindElement(idIter.Key()); if ( !anElem ) continue; + theIDs.push_back( idIter.Key() ); gp_XYZ anXYZ(0., 0., 0.); SMDS_ElemIteratorPtr nodeIt = anElem->nodesIterator(); @@ -948,7 +757,7 @@ void SMESHGUI_MergeDlg::onDetect() SMESH::SMESH_IDSource_var src; if ( mySubMeshOrGroup->_is_nil() ) src = SMESH::SMESH_IDSource::_duplicate( myMesh ); - else src = SMESH::SMESH_IDSource::_duplicate( mySubMeshOrGroup ); + else src = SMESH::SMESH_IDSource::_duplicate( mySubMeshOrGroup ); switch (myAction) { case MERGE_NODES : @@ -1034,8 +843,9 @@ void SMESHGUI_MergeDlg::onSelectGroup() } else { std::list< gp_XYZ > aGrCentersXYZ; - FindGravityCenter(anIndices, aGrCentersXYZ); - myIdPreview->SetElemsData( anIndices, aGrCentersXYZ); + std::vector anIDs; + FindGravityCenter(anIndices, anIDs, aGrCentersXYZ); + myIdPreview->SetElemsData( anIDs, aGrCentersXYZ ); myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility()); } else @@ -1087,8 +897,9 @@ void SMESHGUI_MergeDlg::onSelectElementFromGroup() } else { std::list< gp_XYZ > aGrCentersXYZ; - FindGravityCenter(anIndices, aGrCentersXYZ); - myIdPreview->SetElemsData(anIndices, aGrCentersXYZ); + std::vector anIDs; + FindGravityCenter(anIndices, anIDs, aGrCentersXYZ); + myIdPreview->SetElemsData(anIDs, aGrCentersXYZ); myIdPreview->SetPointsLabeled(!anIndices.IsEmpty(), myActor->GetVisibility()); } else diff --git a/src/SMESHGUI/SMESHGUI_MergeDlg.h b/src/SMESHGUI/SMESHGUI_MergeDlg.h index 754dde0f0..52fd3d556 100644 --- a/src/SMESHGUI/SMESHGUI_MergeDlg.h +++ b/src/SMESHGUI/SMESHGUI_MergeDlg.h @@ -38,25 +38,27 @@ // STL includes #include +#include // IDL includes #include #include CORBA_SERVER_HEADER(SMESH_Mesh) +class LightApp_SelectionMgr; +class QButtonGroup; +class QCheckBox; class QGroupBox; class QLabel; class QLineEdit; +class QListWidget; class QPushButton; class QRadioButton; -class QCheckBox; -class QListWidget; -class QButtonGroup; class SMESHGUI; +class SMESHGUI_IdPreview; class SMESHGUI_SpinBox; class SMESH_Actor; -class SVTK_Selector; -class LightApp_SelectionMgr; class SUIT_SelectionFilter; +class SVTK_Selector; class TColStd_MapOfInteger; namespace SMESH @@ -76,6 +78,8 @@ public: SMESHGUI_MergeDlg( SMESHGUI*, int ); ~SMESHGUI_MergeDlg(); + static QPixmap IconFirst(); + private: void Init(); void enterEvent( QEvent* ); /* mouse enter the QWidget */ @@ -84,7 +88,8 @@ private: bool isKeepNodesIDsSelection(); bool isNewKeepNodesGroup( const char* entry ); - void FindGravityCenter( TColStd_MapOfInteger&, + void FindGravityCenter( TColStd_MapOfInteger&, + std::vector& , std::list& ); // add the centers of gravity of ElemsIdMap elements to the GrCentersXYZ list @@ -103,7 +108,7 @@ private: SUIT_SelectionFilter* myMeshOrSubMeshOrGroupFilter; SUIT_SelectionFilter* mySubMeshOrGroupFilter; - SMESH::TIdPreview* myIdPreview; + SMESHGUI_IdPreview* myIdPreview; int myAction; bool myIsBusy; diff --git a/src/SMESHGUI/SMESHGUI_PreVisualObj.cxx b/src/SMESHGUI/SMESHGUI_PreVisualObj.cxx new file mode 100644 index 000000000..3e05490da --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_PreVisualObj.cxx @@ -0,0 +1,142 @@ +// Copyright (C) 2007-2015 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 +// + +#include "SMESHGUI_PreVisualObj.h" + +#include +#include + +SMESHGUI_PreVisualObj::SMESHGUI_PreVisualObj() +{ + myMesh = new SMDS_Mesh(); +} + +bool SMESHGUI_PreVisualObj::Update( int theIsClear = true ) +{ + return false; +} + +void SMESHGUI_PreVisualObj::UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor ) +{ + if ( theFunctor ) theFunctor->SetMesh( GetMesh() ); +} + +int SMESHGUI_PreVisualObj::GetElemDimension( const int theObjId ) +{ + if ( const SMDS_MeshElement* anElem = myMesh->FindElement( theObjId )) + { + switch ( anElem->GetType() ) + { + case SMDSAbs_Edge : return 1; + case SMDSAbs_Face : return 2; + case SMDSAbs_Volume: return 3; + // case SMDSAbs_0DElement : return 0; + // case SMDSAbs_Ball : return 0; + default : return 0; + } + } + return -1; +} + +int SMESHGUI_PreVisualObj::GetNbEntities( const SMDSAbs_ElementType theType ) const +{ + myMesh->GetMeshInfo().NbElements( theType ); +} + +SMESH::SMESH_Mesh_ptr SMESHGUI_PreVisualObj::GetMeshServer() +{ + return SMESH::SMESH_Mesh::_nil(); +} + +//================================================================================= +// function : GetEdgeNodes +// purpose : Retrieve ids of nodes from edge of elements ( edge is numbered from 1 ) +//================================================================================= + +bool SMESHGUI_PreVisualObj::GetEdgeNodes( const int theElemId, + const int theEdgeNum, + int& theNodeId1, + int& theNodeId2 ) const +{ + const SMDS_MeshElement* e = myMesh->FindElement( theElemId ); + if ( !e || e->GetType() != SMDSAbs_Face ) + return false; + + int nbNodes = e->NbCornerNodes(); + if ( theEdgeNum < 0 || theEdgeNum > nbNodes ) + return false; + + theNodeId1 = e->GetNode( theEdgeNum-1 )->GetID(); + theNodeId2 = e->GetNode( theEdgeNum % nbNodes )->GetID(); + + return true; +} + +bool SMESHGUI_PreVisualObj::IsValid() const +{ + return GetNbEntities( SMDSAbs_All ) > 0; +} + +vtkUnstructuredGrid* SMESHGUI_PreVisualObj::GetUnstructuredGrid() +{ + return myMesh->getGrid(); +} + + +vtkIdType SMESHGUI_PreVisualObj::GetNodeObjId( int theVTKID ) +{ + const SMDS_MeshNode* aNode = myMesh->FindNodeVtk( theVTKID ); + return aNode ? aNode->GetID() : -1; +} + +vtkIdType SMESHGUI_PreVisualObj::GetNodeVTKId( int theObjID ) +{ + const SMDS_MeshNode* aNode = myMesh->FindNode( theObjID ); + return aNode ? aNode->GetID() : -1; +} + +vtkIdType SMESHGUI_PreVisualObj::GetElemObjId( int theVTKID ) +{ + return this->GetMesh()->fromVtkToSmds(theVTKID); +} + +vtkIdType SMESHGUI_PreVisualObj::GetElemVTKId( int theObjID ) +{ + const SMDS_MeshElement* e = myMesh->FindElement(theObjID); + return e ? e->getVtkId() : -1; +} + +void SMESHGUI_PreVisualObj::ClearEntitiesFlags() +{ + myEntitiesState = SMESH_Actor::eAllEntity; + myEntitiesFlag = false; +} + +bool SMESHGUI_PreVisualObj::GetEntitiesFlag() +{ + return myEntitiesFlag; +} + +unsigned int SMESHGUI_PreVisualObj::GetEntitiesState() +{ + return myEntitiesState; +} diff --git a/src/SMESHGUI/SMESHGUI_PreVisualObj.h b/src/SMESHGUI/SMESHGUI_PreVisualObj.h new file mode 100644 index 000000000..dcbfac9e8 --- /dev/null +++ b/src/SMESHGUI/SMESHGUI_PreVisualObj.h @@ -0,0 +1,71 @@ +// Copyright (C) 2007-2015 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 : SMESHGUI_PreVisualObj.h +// Module : SMESH +// +#ifndef SMESHGUI_PreVisualObj_H +#define SMESHGUI_PreVisualObj_H + +#include "SMESH_SMESHGUI.hxx" + +#include "SMESH_Object.h" + +/*! + * \brief Incarnation of SMESH_VisualObj allowing usage of SMESH_Actor + * to show arbitrary mesh data. SMESHGUI_PreVisualObj encapsulates + * a instance of SMDS_Mesh that can be filled by its user. + * Main usage: to initialize a SMESH_Actor to display some preview + */ +class SMESHGUI_EXPORT SMESHGUI_PreVisualObj : public SMESH_VisualObj +{ + mutable SMDS_Mesh* myMesh; + bool myEntitiesFlag; + unsigned int myEntitiesState; + + public: + SMESHGUI_PreVisualObj(); + virtual SMDS_Mesh* GetMesh() const { return myMesh; } + + virtual bool Update( int theIsClear ); + virtual bool NulData() { return false; } + virtual void UpdateFunctor( const SMESH::Controls::FunctorPtr& theFunctor ); + virtual int GetElemDimension( const int theObjId ); + virtual int GetNbEntities( const SMDSAbs_ElementType theType) const; + virtual bool IsValid() const; + virtual bool GetEdgeNodes( const int theElemId, + const int theEdgeNum, + int& theNodeId1, + int& theNodeId2 ) const; + + virtual vtkIdType GetNodeObjId( int theVTKID ); + virtual vtkIdType GetNodeVTKId( int theObjID ); + virtual vtkIdType GetElemObjId( int theVTKID ); + virtual vtkIdType GetElemVTKId( int theObjID ); + virtual void ClearEntitiesFlags(); + virtual bool GetEntitiesFlag(); + virtual unsigned int GetEntitiesState(); + + virtual SMESH::SMESH_Mesh_ptr GetMeshServer(); + virtual vtkUnstructuredGrid* GetUnstructuredGrid(); +}; + +#endif diff --git a/src/SMESHGUI/SMESHGUI_SewingDlg.cxx b/src/SMESHGUI/SMESHGUI_SewingDlg.cxx index 19b8a1d5c..6979a07ce 100644 --- a/src/SMESHGUI/SMESHGUI_SewingDlg.cxx +++ b/src/SMESHGUI/SMESHGUI_SewingDlg.cxx @@ -28,27 +28,31 @@ #include "SMESHGUI_SewingDlg.h" #include "SMESHGUI.h" +#include "SMESHGUI_IdPreview.h" +#include "SMESHGUI_IdValidator.h" +#include "SMESHGUI_MergeDlg.h" +#include "SMESHGUI_MeshUtils.h" +#include "SMESHGUI_PreVisualObj.h" +#include "SMESHGUI_SpinBox.h" #include "SMESHGUI_Utils.h" #include "SMESHGUI_VTKUtils.h" -#include "SMESHGUI_MeshUtils.h" -#include "SMESHGUI_IdValidator.h" -#include #include +#include +#include // SALOME GUI includes -#include -#include +#include +#include +#include #include #include #include - -#include -#include - +#include +#include #include #include -#include +#include // OCCT includes #include @@ -56,24 +60,60 @@ // Qt includes #include #include +#include +#include #include +#include +#include #include #include +#include #include #include -#include -#include +#include #include -#include -#include - -// IDL includes -#include -#include CORBA_SERVER_HEADER(SMESH_MeshEditor) #define SPACING 6 #define MARGIN 11 +namespace +{ + enum ActionType { MODE_AUTO=0, MODE_MANUAL, + MOVE_LEFT_1=0, MOVE_RIGHT_1, MOVE_LEFT_2, MOVE_RIGHT_2, + GROUP_COLOR=Qt::UserRole, GROUP_INDEX }; +} + +//================================================================================= +/*! + * \brief Dispalayer of free borders + */ +//================================================================================= + +struct SMESHGUI_SewingDlg::BorderGroupDisplayer +{ + const SMESH::ListOfFreeBorders& myBorders; + const SMESH::FreeBordersGroup& myGroup; + QColor myColor; + SMESH::SMESH_Mesh_ptr myMesh; + + std::vector< SMESH_Actor* > myPartActors; + SVTK_ViewWindow* myViewWindow; + SMESHGUI_IdPreview myIdPreview; + + BorderGroupDisplayer( const SMESH::CoincidentFreeBorders& borders, + int groupIndex, + QColor color, + SMESH::SMESH_Mesh_ptr mesh); + ~BorderGroupDisplayer(); + void Hide(); + void ShowGroup( bool wholeBorders ); + void ShowPart( int partIndex, bool toEdit ); + void Update(); + +private: + void getPartEnds( int partIndex, std::vector & ids, std::list& coords); +}; + //================================================================================= // class : SMESHGUI_SewingDlg() // purpose : @@ -89,6 +129,7 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule ) QPixmap image2 (mgr->loadPixmap("SMESH", tr("ICON_SMESH_SEWING_BORDERTOSIDE"))); QPixmap image3 (mgr->loadPixmap("SMESH", tr("ICON_SMESH_SEWING_SIDEELEMENTS"))); QPixmap image4 (mgr->loadPixmap("SMESH", tr("ICON_SELECT"))); + QPixmap IconRemove(mgr->loadPixmap("SMESH", tr("ICON_REMOVE"))); setModal(false); setAttribute(Qt::WA_DeleteOnClose, true); @@ -203,9 +244,162 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule ) // Control for the polyedres creation to obtain conform mesh CheckBoxPolyedrs = new QCheckBox(tr("CREATE_POLYEDRS_NEAR_BOUNDARY"), GroupArguments); + /***************************************************************/ + // Controls to switch free borders mode ( auto || manual ) + + ModeGroup = new QGroupBox( tr( "SMESH_MODE" ), GroupArguments ); + ModeButGrp = new QButtonGroup( ModeGroup ); + QHBoxLayout* aModeGroupLayout = new QHBoxLayout( ModeGroup ); + aModeGroupLayout->setMargin( MARGIN ); + aModeGroupLayout->setSpacing( SPACING ); + + QRadioButton* rb1 = new QRadioButton( tr( "SMESH_AUTOMATIC" ), ModeGroup ); + QRadioButton* rb2 = new QRadioButton( tr( "SMESH_MANUAL" ), ModeGroup ); + ModeButGrp->addButton( rb1, MODE_AUTO ); + ModeButGrp->addButton( rb2, MODE_MANUAL ); + aModeGroupLayout->addWidget( rb1 ); + aModeGroupLayout->addWidget( rb2 ); + rb1->setChecked(true); + + /***************************************************************/ + // Controls for detecting coincident free borders + + SewFreeBordersWidget = new QWidget( GroupArguments ); + QVBoxLayout* aSewFreeBordersLayout = new QVBoxLayout( SewFreeBordersWidget ); + aSewFreeBordersLayout->setMargin( 0 ); + aSewFreeBordersLayout->setSpacing( SPACING ); + + // Tolerance + QWidget* TolAndAuto = new QWidget(SewFreeBordersWidget); + QLabel* TextLabelTolerance = new QLabel(tr("SMESH_TOLERANCE"), TolAndAuto); + SpinBoxTolerance = new SMESHGUI_SpinBox(TolAndAuto); + SpinBoxTolerance->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + SpinBoxTolerance->RangeStepAndValidator(0.0, COORD_MAX, 0.00001, "len_tol_precision"); + SpinBoxTolerance->SetValue(0.); // auto-tolerance + + // Auto Sewing + AutoSewCheck = new QCheckBox(tr("AUTO_SEWING"), TolAndAuto); + AutoSewCheck->setChecked( true ); + + // mesh + QGroupBox* GroupMesh = new QGroupBox(tr("SMESH_SELECT_WHOLE_MESH"), SewFreeBordersWidget); + QHBoxLayout* GroupMeshLayout = new QHBoxLayout(GroupMesh); + GroupMeshLayout->setSpacing(SPACING); + GroupMeshLayout->setMargin(MARGIN); + + QLabel* TextLabelName = new QLabel(tr("SMESH_NAME"), GroupMesh); + //SelectMeshButton = new QPushButton(GroupMesh); + //SelectMeshButton->setIcon(IconSelect); + LineEditMesh = new QLineEdit(GroupMesh); + LineEditMesh->setReadOnly(true); + + GroupMeshLayout->addWidget(TextLabelName); + //GroupMeshLayout->addWidget(SelectMeshButton); + GroupMeshLayout->addWidget(LineEditMesh); + + QGridLayout* TolAndAutoLayout = new QGridLayout( TolAndAuto ); + TolAndAutoLayout->setSpacing(SPACING); + TolAndAutoLayout->setMargin(0); + TolAndAutoLayout->addWidget(GroupMesh, 0, 0, 1, 2 ); + TolAndAutoLayout->addWidget(TextLabelTolerance, 1, 0 ); + TolAndAutoLayout->addWidget(SpinBoxTolerance, 1, 1 ); + TolAndAutoLayout->addWidget(AutoSewCheck, 2, 0 ); + + aSewFreeBordersLayout->addWidget( TolAndAuto ); + + /******************/ + // Coincident group + GroupCoincidentWidget = new QWidget(SewFreeBordersWidget); + QGridLayout* GroupCoincidentLayout = new QGridLayout(GroupCoincidentWidget); + GroupCoincidentLayout->setSpacing(SPACING); + GroupCoincidentLayout->setMargin(0); + + QGroupBox* GroupCoincident = new QGroupBox(tr("COINCIDENT_FREE_BORDERS"), GroupCoincidentWidget); + QGridLayout* aCoincidentLayout = new QGridLayout(GroupCoincident); + aCoincidentLayout->setSpacing(SPACING); + aCoincidentLayout->setMargin(MARGIN); + + /*******/ + // borders + ListCoincident = new QListWidget(GroupCoincident); + ListCoincident->setSelectionMode(QListWidget::ExtendedSelection); + + DetectButton = new QPushButton(tr("DETECT"), GroupCoincident); + RemoveGroupButton = new QPushButton(tr("SMESH_BUT_REMOVE"), GroupCoincident); + + SelectAllCheck = new QCheckBox(tr("SELECT_ALL"), GroupCoincident); + + aCoincidentLayout->addWidget(ListCoincident, 0, 0, 4, 2); + aCoincidentLayout->addWidget(DetectButton, 1, 2); + aCoincidentLayout->addWidget(RemoveGroupButton, 3, 2); + aCoincidentLayout->addWidget(SelectAllCheck, 4, 0); + aCoincidentLayout->setRowMinimumHeight(1, 10); + aCoincidentLayout->setRowStretch (1, 5); + + GroupCoincidentLayout->addWidget( GroupCoincident ); + + /*****************************************/ + // Controls for editing the selected group + + QGroupBox* GroupEdit = new QGroupBox(tr("EDIT_SELECTED_GROUP"), GroupCoincidentWidget); + QGridLayout* GroupEditLayout = new QGridLayout(GroupEdit); + GroupEditLayout->setSpacing(SPACING); + GroupEditLayout->setMargin(MARGIN); + + ListEdit = new QListWidget(GroupEdit); + ListEdit->setFlow( QListView::LeftToRight ); + ListEdit->setSelectionMode(QListWidget::ExtendedSelection); + SetFirstButton = new QPushButton(GroupEdit); + SetFirstButton->setIcon(QPixmap(SMESHGUI_MergeDlg::IconFirst())); + RemoveElemButton = new QPushButton(GroupEdit); + RemoveElemButton->setIcon(IconRemove); + + MoveBorderEndsButGrp = new QButtonGroup( GroupEdit ); + QToolButton* moveBut1 = new QToolButton( GroupEdit ); + QToolButton* moveBut2 = new QToolButton( GroupEdit ); + QToolButton* moveBut3 = new QToolButton( GroupEdit ); + QToolButton* moveBut4 = new QToolButton( GroupEdit ); + moveBut1->setArrowType( Qt::LeftArrow ); + moveBut2->setArrowType( Qt::RightArrow ); + moveBut3->setArrowType( Qt::LeftArrow ); + moveBut4->setArrowType( Qt::RightArrow ); + MoveBorderEndsButGrp->addButton( moveBut1, MOVE_LEFT_1 ); + MoveBorderEndsButGrp->addButton( moveBut2, MOVE_RIGHT_1 ); + MoveBorderEndsButGrp->addButton( moveBut3, MOVE_LEFT_2 ); + MoveBorderEndsButGrp->addButton( moveBut4, MOVE_RIGHT_2 ); + + SwapBut = new QPushButton( "<->", GroupEdit ); + BorderEndLine[0] = new QLineEdit( GroupEdit ); + BorderEndLine[1] = new QLineEdit( GroupEdit ); + BorderEndLine[0]->setReadOnly(true); + BorderEndLine[1]->setReadOnly(true); + QLabel* StepLabel = new QLabel(tr("STEP"), GroupEdit ); + StepSpin = new SalomeApp_IntSpinBox( 1, 100000, 1, GroupEdit, + /*acceptNames=*/false, /*showTip=*/false ); + StepSpin->setValue( 1 ); + + GroupEditLayout->addWidget(ListEdit, 0, 0, 1, 8); + GroupEditLayout->addWidget(SetFirstButton, 0, 8); + GroupEditLayout->addWidget(RemoveElemButton, 0, 9); + GroupEditLayout->addWidget(moveBut1, 1, 0); + GroupEditLayout->addWidget(BorderEndLine[0], 1, 1); + GroupEditLayout->addWidget(moveBut2, 1, 2); + GroupEditLayout->addWidget(moveBut3, 1, 3); + GroupEditLayout->addWidget(BorderEndLine[1], 1, 4); + GroupEditLayout->addWidget(moveBut4, 1, 5); + GroupEditLayout->setColumnStretch( 6, 5 ); + GroupEditLayout->addWidget(SwapBut, 1, 7); + GroupEditLayout->addWidget(StepLabel, 1, 8); + GroupEditLayout->addWidget(StepSpin, 1, 9); + + GroupCoincidentLayout->addWidget( GroupEdit ); + aSewFreeBordersLayout->addWidget( GroupCoincidentWidget ); + // layout + GroupArgumentsLayout->addWidget(ModeGroup); GroupArgumentsLayout->addWidget(SubGroup1); GroupArgumentsLayout->addWidget(SubGroup2); + GroupArgumentsLayout->addWidget(SewFreeBordersWidget); GroupArgumentsLayout->addWidget(CheckBoxMerge); GroupArgumentsLayout->addWidget(CheckBoxPolygons); GroupArgumentsLayout->addWidget(CheckBoxPolyedrs); @@ -238,6 +432,7 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule ) SMESHGUI_SewingDlgLayout->addWidget(ConstructorsBox); SMESHGUI_SewingDlgLayout->addWidget(GroupArguments); SMESHGUI_SewingDlgLayout->addWidget(GroupButtons); + //SMESHGUI_SewingDlgLayout->setStretch( 2, 10 ); /* Initialisations */ RadioButton1->setChecked(true); @@ -253,6 +448,9 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule ) myHelpFileName = "sewing_meshes_page.html"; + myActor = 0; + setDisplayMode(); + Init(); /* signals and slots connections */ @@ -283,6 +481,18 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule ) connect(LineEdit5, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&))); connect(LineEdit6, SIGNAL(textChanged(const QString&)), SLOT(onTextChange(const QString&))); + connect(ModeButGrp, SIGNAL(buttonClicked(int)), SLOT(onModeChange(int))); + connect(AutoSewCheck, SIGNAL(stateChanged(int)), SLOT(onAutoSew(int))); + connect(DetectButton, SIGNAL(clicked()), SLOT(onDetectClicked())); + connect(RemoveGroupButton, SIGNAL(clicked()), SLOT(onRemoveGroupClicked())); + connect(ListCoincident, SIGNAL(itemSelectionChanged()), SLOT(onSelectGroup())); + connect(SelectAllCheck, SIGNAL(stateChanged(int)), SLOT(onSelectAll(int))); + connect(ListEdit, SIGNAL(itemSelectionChanged()), SLOT(onSelectBorderPartFromGroup())); + connect(SetFirstButton, SIGNAL(clicked()), SLOT(onSetFirstClicked())); + connect(RemoveElemButton, SIGNAL(clicked()), SLOT(onRemoveElemClicked())); + connect(MoveBorderEndsButGrp, SIGNAL(buttonClicked(int)), SLOT(onMoveBorderEnd(int))); + connect(SwapBut, SIGNAL(clicked()), SLOT(onSwapClicked())); + ConstructorsClicked(0); } @@ -292,6 +502,12 @@ SMESHGUI_SewingDlg::SMESHGUI_SewingDlg( SMESHGUI* theModule ) //================================================================================= SMESHGUI_SewingDlg::~SMESHGUI_SewingDlg() { + for ( size_t i = 0; i < myBorderDisplayers.size(); ++i ) + { + delete myBorderDisplayers[ i ]; + myBorderDisplayers[ i ] = 0; + } + myBorderDisplayers.clear(); } //================================================================================= @@ -302,13 +518,16 @@ void SMESHGUI_SewingDlg::Init() { myBusy = false; - myEditCurrentArgument = LineEdit1; - LineEdit1->setFocus(); - myActor = 0; + if ( LineEdit1->isVisible() ) + myEditCurrentArgument = LineEdit1; + else + myEditCurrentArgument = LineEditMesh; + myEditCurrentArgument->setFocus(); + //myActor = 0; myMesh = SMESH::SMESH_Mesh::_nil(); - CheckBoxMerge->setChecked(false); - CheckBoxPolygons->setChecked(false); - CheckBoxPolyedrs->setChecked(false); + // CheckBoxMerge->setChecked(false); + // CheckBoxPolygons->setChecked(false); + // CheckBoxPolyedrs->setChecked(false); SelectionIntoArgument(); } @@ -349,75 +568,97 @@ void SMESHGUI_SewingDlg::ConstructorsClicked (int constructorId) CheckBoxPolyedrs->hide(); } + if (( !SubGroup1->isVisible() ) && + ( constructorId != 0 || ModeButGrp->checkedId() == MODE_MANUAL )) + { + SubGroup1->show(); + SubGroup2->show(); + } + + if ( constructorId != 0 ) + { + ModeGroup->hide(); + SewFreeBordersWidget->hide(); + } + + bool isNodeSelection = true; + switch (constructorId) { case 0: - { - GroupArguments->setTitle(tr("SEW_FREE_BORDERS")); - SubGroup1->setTitle(tr("BORDER_1")); - SubGroup2->setTitle(tr("BORDER_2")); + { + GroupArguments->setTitle(tr("SEW_FREE_BORDERS")); + SubGroup1->setTitle(tr("BORDER_1")); + SubGroup2->setTitle(tr("BORDER_2")); - if (!CheckBoxPolygons->isVisible()) - CheckBoxPolygons->show(); - if (!CheckBoxPolyedrs->isVisible()) - CheckBoxPolyedrs->show(); + if (!CheckBoxPolygons->isVisible()) + CheckBoxPolygons->show(); + if (!CheckBoxPolyedrs->isVisible()) + CheckBoxPolyedrs->show(); - break; + if ( !ModeGroup->isVisible() ) + { + ModeGroup->show(); } + onModeChange( ModeButGrp->checkedId() ); + + isNodeSelection = ( ModeButGrp->checkedId() == MODE_MANUAL ); + + break; + } case 1: - { - GroupArguments->setTitle(tr("SEW_CONFORM_FREE_BORDERS")); - SubGroup1->setTitle(tr("BORDER_1")); - SubGroup2->setTitle(tr("BORDER_2")); + { + GroupArguments->setTitle(tr("SEW_CONFORM_FREE_BORDERS")); + SubGroup1->setTitle(tr("BORDER_1")); + SubGroup2->setTitle(tr("BORDER_2")); - TextLabel6->setEnabled(false); - SelectButton6->setEnabled(false); - LineEdit6->setEnabled(false); + TextLabel6->setEnabled(false); + SelectButton6->setEnabled(false); + LineEdit6->setEnabled(false); - myOk6 = true; + myOk6 = true; - break; - } + break; + } case 2: - { - GroupArguments->setTitle(tr("SEW_BORDER_TO_SIDE")); - SubGroup1->setTitle(tr("BORDER")); - SubGroup2->setTitle(tr("SIDE")); - - TextLabel5->setEnabled(false); - SelectButton5->setEnabled(false); - LineEdit5->setEnabled(false); - - if (!CheckBoxPolygons->isVisible()) - CheckBoxPolygons->show(); - if (!CheckBoxPolyedrs->isVisible()) - CheckBoxPolyedrs->show(); - - myOk5 = true; - - break; - } - case 3: - { - GroupArguments->setTitle(tr("SEW_SIDE_ELEMENTS")); - SubGroup1->setTitle(tr("SIDE_1")); - SubGroup2->setTitle(tr("SIDE_2")); + { + GroupArguments->setTitle(tr("SEW_BORDER_TO_SIDE")); + SubGroup1->setTitle(tr("BORDER")); + SubGroup2->setTitle(tr("SIDE")); - TextLabel1->setText(tr("SMESH_ID_ELEMENTS")); - TextLabel2->setText(tr("NODE1_TO_MERGE")); - TextLabel3->setText(tr("NODE2_TO_MERGE")); - TextLabel4->setText(tr("SMESH_ID_ELEMENTS")); - TextLabel5->setText(tr("NODE1_TO_MERGE")); - TextLabel6->setText(tr("NODE2_TO_MERGE")); + TextLabel5->setEnabled(false); + SelectButton5->setEnabled(false); + LineEdit5->setEnabled(false); - LineEdit1->setValidator(new SMESHGUI_IdValidator(this)); - LineEdit4->setValidator(new SMESHGUI_IdValidator(this)); + if (!CheckBoxPolygons->isVisible()) + CheckBoxPolygons->show(); + if (!CheckBoxPolyedrs->isVisible()) + CheckBoxPolyedrs->show(); - SMESH::SetPointRepresentation(false); + myOk5 = true; - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) - aViewWindow->SetSelectionMode(CellSelection); - break; - } + break; + } + case 3: + { + GroupArguments->setTitle(tr("SEW_SIDE_ELEMENTS")); + SubGroup1->setTitle(tr("SIDE_1")); + SubGroup2->setTitle(tr("SIDE_2")); + + TextLabel1->setText(tr("SMESH_ID_ELEMENTS")); + TextLabel2->setText(tr("NODE1_TO_MERGE")); + TextLabel3->setText(tr("NODE2_TO_MERGE")); + TextLabel4->setText(tr("SMESH_ID_ELEMENTS")); + TextLabel5->setText(tr("NODE1_TO_MERGE")); + TextLabel6->setText(tr("NODE2_TO_MERGE")); + + LineEdit1->setValidator(new SMESHGUI_IdValidator(this)); + LineEdit4->setValidator(new SMESHGUI_IdValidator(this)); + + isNodeSelection = false; + if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) + aViewWindow->SetSelectionMode(CellSelection); + break; + } } if (constructorId != 3) { @@ -430,21 +671,581 @@ void SMESHGUI_SewingDlg::ConstructorsClicked (int constructorId) LineEdit1->setValidator(new SMESHGUI_IdValidator(this, 1)); LineEdit4->setValidator(new SMESHGUI_IdValidator(this, 1)); + } + if ( isNodeSelection ) + { SMESH::SetPointRepresentation(true); - if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) aViewWindow->SetSelectionMode(NodeSelection); } + UpdateButtons(); + connect(mySelectionMgr, SIGNAL(currentSelectionChanged()), this, SLOT(SelectionIntoArgument())); mySelectionMgr->setSelectedObjects( io ); QApplication::instance()->processEvents(); updateGeometry(); + + resize(100,100); +} + +//======================================================================= +//function : storeDisplayMode +//purpose : save representation of a mesh and switch it to wireframe mode +//======================================================================= + +void SMESHGUI_SewingDlg::setDisplayMode() +{ + myStoredEntityMode = 0; + myStoredRepresentation = -1; + if ( myActor ) + { + myStoredEntityMode = myActor->GetEntityMode(); + myStoredRepresentation = myActor->GetRepresentation(); + + myActor->SetEntityMode( myStoredEntityMode & ~SMESH_Actor::eVolumes ); + myActor->SetRepresentation( SMESH_Actor::eEdge ); + } +} + +//======================================================================= +//function : restoreDisplayMode +//purpose : restore representation of a mesh +//======================================================================= + +void SMESHGUI_SewingDlg::restoreDisplayMode() +{ + if ( myActor && myStoredEntityMode ) + { + if ( myActor->GetEntityMode() == ( myStoredEntityMode & ~SMESH_Actor::eVolumes )) + myActor->SetEntityMode( myStoredEntityMode ); + + if ( myActor->GetRepresentation() == SMESH_Actor::eEdge ) + myActor->SetRepresentation( myStoredRepresentation ); + + myStoredEntityMode = 0; + myStoredRepresentation = -1; + } +} + +//======================================================================= +//function : onModeChange +//purpose : SLOT called when mode (auto or manual) of Sew free borders change +//======================================================================= + +void SMESHGUI_SewingDlg::onModeChange( int mode ) +{ + if ( mode == MODE_MANUAL ) + { + myEditCurrentArgument = LineEdit1; + if ( !SubGroup1->isVisible() ) + SubGroup1->show(), SubGroup2->show(); + SewFreeBordersWidget->hide(); + } + else + { + myEditCurrentArgument = LineEditMesh; + SubGroup1->hide(), SubGroup2->hide(); + if ( !SewFreeBordersWidget->isVisible() ) + SewFreeBordersWidget->show(); + } + onAutoSew( AutoSewCheck->isChecked() ); + + QApplication::instance()->processEvents(); + updateGeometry(); + resize(100,100); } +//======================================================================= +//function : onAutoSew +//purpose : SLOT called when Auto Sewing check box is checked +//======================================================================= + +void SMESHGUI_SewingDlg::onAutoSew( int isAuto ) +{ + GroupCoincidentWidget->setVisible( !isAuto ); + + QApplication::instance()->processEvents(); + + SewFreeBordersWidget->hide(); + if ( ModeButGrp->checkedId() == MODE_AUTO ) + SewFreeBordersWidget->show(); + + UpdateButtons(); + + updateGeometry(); + resize(minimumSizeHint()); +} + +//======================================================================= +//function : haveBorders +//purpose : Returns true if myBorders have been initialized +//======================================================================= + +bool SMESHGUI_SewingDlg::haveBorders() +{ + return ( & myBorders.in() && + myBorders->borders.length() && + myBorders->coincidentGroups.length() ); +} + +//======================================================================= +//function : getGroupText +//purpose : Returns a text of a given group of coincident free borders +//======================================================================= + +QString SMESHGUI_SewingDlg::getPartText(const SMESH::FreeBorderPart& aPART) +{ + QString text; + if ( 0 <= aPART.border && aPART.border < myBorders->borders.length() ) + { + const SMESH::FreeBorder& aBRD = myBorders->borders[ aPART.border ]; + if ( 0 <= aPART.node1 && aPART.node1 < aBRD.nodeIDs.length() && + 0 <= aPART.nodeLast && aPART.nodeLast < aBRD.nodeIDs.length() ) + { + text += QString("( %1 %2 ) ") + .arg( aBRD.nodeIDs[ aPART.node1 ] ) + .arg( aBRD.nodeIDs[ aPART.nodeLast ] ); + } + } + return text; +} + +//======================================================================= +//function : getGroupText +//purpose : Returns a text of a given group of coincident free borders +//======================================================================= + +QString SMESHGUI_SewingDlg::getGroupText(int groupIndex) +{ + QString text; + + if ( haveBorders() && + groupIndex >= 0 && + groupIndex < myBorders->coincidentGroups.length() ) + { + const SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ groupIndex ]; + + for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP ) + { + QString partText = getPartText( aGRP[ iP ]); + if ( partText.isEmpty() ) + return ""; + text += partText; + } + } + return text; +} + +//======================================================================= +//function : onDetectClicked +//purpose : SLOT called when [Detect] is clicked +//======================================================================= + +void SMESHGUI_SewingDlg::onDetectClicked() +{ + ListCoincident->clear(); + + if ( myMesh->_is_nil() ) + return; + + SUIT_OverrideCursor wc; + + SMESH::SMESH_MeshEditor_var editor = myMesh->GetMeshEditor(); + myBorders = editor->FindCoincidentFreeBorders( SpinBoxTolerance->GetValue() ); + if ( !haveBorders() ) + return; + + for ( size_t i = 0; i < myBorderDisplayers.size(); ++i ) + { + delete myBorderDisplayers[ i ]; + myBorderDisplayers[ i ] = 0; + } + myBorderDisplayers.resize( myBorders->coincidentGroups.length(), 0 ); + + for ( CORBA::ULong i = 0; i < myBorders->coincidentGroups.length(); ++i ) + { + QString groupText = getGroupText( i ); + if ( groupText.isEmpty() ) + continue; + + QColor groupColor; + groupColor.setHsvF( float(i) / myBorders->coincidentGroups.length(), 1., 1. ); + QPixmap icon( QSize( 20, 20 )); + icon.fill( groupColor ); + + QListWidgetItem * item = new QListWidgetItem( icon, groupText, ListCoincident ); + item->setData( GROUP_COLOR, groupColor ); + item->setData( GROUP_INDEX, i ); + } + + onSelectGroup(); + + UpdateButtons(); +} + +//======================================================================= +//function : onRemoveGroupClicked +//purpose : +//======================================================================= + +void SMESHGUI_SewingDlg::onRemoveGroupClicked() +{ + QList selItems = ListCoincident->selectedItems(); + for ( int i = 0; i < selItems.count(); ++i ) + { + QListWidgetItem* item = selItems[ i ]; + item->setSelected( false ); + int groupIndex = item->data( GROUP_INDEX ).toInt(); + delete item; + myBorderDisplayers[ groupIndex ]->Hide(); + SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + aGRP.length( 0 ); + } + UpdateButtons(); +} + +//======================================================================= +//function : showGroup +//purpose : display a group of coincident free borders in the Viewer +//======================================================================= + +void SMESHGUI_SewingDlg::showGroup( QListWidgetItem* item ) +{ + if ( !item || + item->listWidget() != ListCoincident || + !haveBorders() ) + return; + + int groupIndex = item->data( GROUP_INDEX ).toInt(); + QColor groupColor = item->data( GROUP_COLOR ).value(); + if ( groupIndex >= 0 && + groupIndex < myBorders->coincidentGroups.length() ) + { + if ( !myBorderDisplayers[ groupIndex ]) + myBorderDisplayers[ groupIndex ] = new BorderGroupDisplayer( myBorders, groupIndex, groupColor, myMesh ); + bool wholeBorders = setCurrentGroup(); + myBorderDisplayers[ groupIndex ]->ShowGroup( wholeBorders ); + } +} + +//======================================================================= +//function : setCurrentGroup +//purpose : set index of a current free border group to myCurGroupIndex +//======================================================================= + +bool SMESHGUI_SewingDlg::setCurrentGroup() +{ + if ( !haveBorders() ) + return false; + + QList selItems = ListCoincident->selectedItems(); + if ( selItems.count() != 1 ) + return false; + + myCurGroupIndex = selItems[0]->data( GROUP_INDEX ).toInt(); + + return ( myCurGroupIndex >= 0 && myCurGroupIndex < myBorders->coincidentGroups.length() ); +} + +//======================================================================= +//function : setCurrentPart +//purpose : set index of a current free border of a current group to myCurPartIndex +//======================================================================= + +bool SMESHGUI_SewingDlg::setCurrentPart() +{ + if ( !setCurrentGroup() ) + return false; + + if ( ListEdit->selectedItems().count() != 1 ) + return false; + + myCurPartIndex = ListEdit->currentRow(); + const SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + + return ( myCurPartIndex >= 0 && myCurPartIndex < aGRP.length() ); +} + +//======================================================================= +//function : onSelectGroup +//purpose : SLOT called when selection of coincident free borders change +//======================================================================= + +void SMESHGUI_SewingDlg::onSelectGroup() +{ + if ( myBusy ) + return; + ListEdit->clear(); + BorderEndLine[0]->clear(); + BorderEndLine[1]->clear(); + for ( size_t i = 0; i < myBorderDisplayers.size(); ++i ) + if ( myBorderDisplayers[ i ]) + myBorderDisplayers[ i ]->Hide(); + + QList selItems = ListCoincident->selectedItems(); + + RemoveGroupButton->setEnabled( selItems.count() > 0 ); + + onSelectBorderPartFromGroup(); // enable buttons + + if ( !haveBorders() ) + return; + + SelectAllCheck->blockSignals( true ); + if ( ListCoincident->count() != selItems.count() ) + SelectAllCheck->setChecked( false ); + SelectAllCheck->blockSignals( false ); + + if ( selItems.empty() ) // nothing selected - show all + for ( int i = 0; i < ListCoincident->count(); ++i ) + showGroup( ListCoincident->item( i )); + else + for ( int i = 0; i < selItems.count(); ++i ) + showGroup( selItems[ i ]); + + if ( setCurrentGroup() ) // edit a selected group + { + const SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP ) + new QListWidgetItem( getPartText( aGRP[ iP ]), ListEdit ); + } + SMESH::RepaintCurrentView(); +} + +//======================================================================= +//function : onSelectAll +//purpose : SLOT called when Select All is checked +//======================================================================= + +void SMESHGUI_SewingDlg::onSelectAll(int isOn) +{ + if ( isOn ) + ListCoincident->selectAll(); + else + ListCoincident->clearSelection(); +} + +//======================================================================= +//function : onSelectBorderPartFromGroup +//purpose : SLOT called when selection of borders in an edited group changes +//======================================================================= + +void SMESHGUI_SewingDlg::onSelectBorderPartFromGroup() +{ + if ( myBusy ) return; + BorderEndLine[0]->setText(""); + BorderEndLine[1]->setText(""); + MoveBorderEndsButGrp->button( MOVE_LEFT_1 )->setEnabled( false ); + MoveBorderEndsButGrp->button( MOVE_RIGHT_1 )->setEnabled( false ); + MoveBorderEndsButGrp->button( MOVE_LEFT_2 )->setEnabled( false ); + MoveBorderEndsButGrp->button( MOVE_RIGHT_2 )->setEnabled( false ); + SwapBut->setEnabled( false ); + SetFirstButton->setEnabled( false ); + RemoveElemButton->setEnabled ( ListEdit->count() > 2 ); + + if ( !setCurrentGroup() ) + return; + + if ( !myBorderDisplayers[ myCurGroupIndex ]) return; + myBorderDisplayers[ myCurGroupIndex ]->Hide(); + + QList selItems = ListEdit->selectedItems(); + bool editPart = ( setCurrentPart() ); + for ( int i = 0; i < selItems.count(); ++i ) + myBorderDisplayers[ myCurGroupIndex ]->ShowPart( ListEdit->row( selItems[i] ), editPart ); + + if ( selItems.isEmpty() ) + myBorderDisplayers[ myCurGroupIndex ]->ShowGroup( /*wholeBorders=*/ true ); + + if ( editPart ) + { + SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + SMESH::FreeBorderPart& aPRT = aGRP[ myCurPartIndex ]; + SMESH::FreeBorder& aBRD = myBorders->borders[ aPRT.border ]; + + BorderEndLine[0]->setText( QString::number( aBRD.nodeIDs[ aPRT.node1 ])); + BorderEndLine[1]->setText( QString::number( aBRD.nodeIDs[ aPRT.nodeLast ])); + SwapBut->setEnabled( true ); + SetFirstButton->setEnabled( myCurPartIndex > 0 ); + + int size = (int) aBRD.nodeIDs.length(); + bool isClosed = ( aBRD.nodeIDs[0] == aBRD.nodeIDs[ size-1 ]); + if ( !isClosed ) + { + bool isFwd = ( Abs( aPRT.node2 - aPRT.node1 ) == 1 ) ? aPRT.node2 > aPRT.node1 : aPRT.node2 < aPRT.node1; + int dn = ( isFwd ? +1 : -1 ) * StepSpin->value(); + MoveBorderEndsButGrp->button( MOVE_LEFT_1 )-> + setEnabled( 0 <= aPRT.node1-dn && aPRT.node1-dn < size ); + MoveBorderEndsButGrp->button( MOVE_RIGHT_1 )-> + setEnabled( 0 <= aPRT.node1+dn && aPRT.node1+dn < size ); + MoveBorderEndsButGrp->button( MOVE_LEFT_2 )-> + setEnabled( 0 <= aPRT.nodeLast-dn && aPRT.nodeLast-dn < size ); + MoveBorderEndsButGrp->button( MOVE_RIGHT_2 )-> + setEnabled( 0 <= aPRT.nodeLast+dn && aPRT.nodeLast+dn < size ); + } + else + { + MoveBorderEndsButGrp->button( MOVE_LEFT_1 )->setEnabled( true ); + MoveBorderEndsButGrp->button( MOVE_RIGHT_1 )->setEnabled( true ); + MoveBorderEndsButGrp->button( MOVE_LEFT_2 )->setEnabled( true ); + MoveBorderEndsButGrp->button( MOVE_RIGHT_2 )->setEnabled( true ); + } + } + SMESH::RepaintCurrentView(); +} + +//======================================================================= +//function : onGroupChange +//purpose : Update after modification of a current group by the user +//======================================================================= + +void SMESHGUI_SewingDlg::onGroupChange( bool partChange ) +{ + ListCoincident->currentItem()->setText( getGroupText( myCurGroupIndex )); + + const SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + for ( int i = 0; i < ListEdit->count(); ++i ) + ListEdit->item( i )->setText( getPartText( aGRP[ i ])); + + myBorderDisplayers[ myCurGroupIndex ]->Update(); + + if ( partChange ) + onSelectBorderPartFromGroup(); +} + +//======================================================================= +//function : onSetFirstClicked +//purpose : STOL called when |<< is clicked +//======================================================================= + +void SMESHGUI_SewingDlg::onSetFirstClicked() +{ + if ( !setCurrentPart() || myCurPartIndex == 0 || ListEdit->count() == 0 ) + return; + + SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + + SMESH::FreeBorderPart new1st = aGRP[ myCurPartIndex ]; + for ( ; myCurPartIndex > 0; --myCurPartIndex ) + aGRP[ myCurPartIndex ] = aGRP[ myCurPartIndex - 1 ]; + + aGRP[ 0 ] = new1st; + + onGroupChange(); + + myBusy = true; + ListEdit->clearSelection(); + myBusy = false; + ListEdit->setCurrentItem( ListEdit->item(0) );//ListEdit->item(0)->setSelected(true); +} + +//======================================================================= +//function : onRemoveElemClicked +//purpose : +//======================================================================= + +void SMESHGUI_SewingDlg::onRemoveElemClicked() +{ + if ( !setCurrentGroup() ) + return; + + SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + + QList selItems = ListEdit->selectedItems(); + for ( int i = 0; i < selItems.count(); ++i ) + { + int part = ListEdit->row( selItems[i] ); + for ( ; part + 1 < aGRP.length(); ++part ) + aGRP[ part ] = aGRP[ part + 1 ]; + aGRP.length( aGRP.length() - 1 ); + delete selItems[i]; + } + + if ( aGRP.length() == 0 ) + onRemoveGroupClicked(); + else + onGroupChange( /*partChange=*/true ); +} + +//======================================================================= +//function : onMoveBorderEnd +//purpose : +//======================================================================= + +void SMESHGUI_SewingDlg::onMoveBorderEnd(int button) +{ + if ( !setCurrentPart() ) + return; + + SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + SMESH::FreeBorderPart& aPRT = aGRP[ myCurPartIndex ]; + SMESH::FreeBorder& aBRD = myBorders->borders[ aPRT.border ]; + int size = (int) aBRD.nodeIDs.length(); + + bool isClosed = ( aBRD.nodeIDs[0] == aBRD.nodeIDs[ size-1 ]); + if ( isClosed ) --size; + + bool isFwd = ( Abs( aPRT.node2 - aPRT.node1 ) == 1 ) ? aPRT.node2 > aPRT.node1 : aPRT.node2 < aPRT.node1; + int dn = ( isFwd ? +1 : -1 ) * StepSpin->value(); + if ( button == MOVE_LEFT_1 || button == MOVE_LEFT_2 ) + dn *= -1; + + switch ( button ) { + case MOVE_LEFT_1: + case MOVE_RIGHT_1: + if (( isClosed ) || + ( 0 <= aPRT.node1+dn && aPRT.node1+dn < size )) + { + aPRT.node1 = ( aPRT.node1 + size + dn ) % size; + aPRT.node2 = ( aPRT.node2 + size + dn ) % size; + break; + } + case MOVE_LEFT_2: + case MOVE_RIGHT_2: + if (( isClosed ) || + ( 0 <= aPRT.nodeLast+dn && aPRT.nodeLast+dn < size )) + { + aPRT.nodeLast = ( aPRT.nodeLast + size + dn ) % size; + break; + } + default: + return; // impossible to move + } + + onGroupChange( /*partChange=*/true ); +} + +//======================================================================= +//function : onSwapClicked +//purpose : SLOT called when <-> is clicked +//======================================================================= + +void SMESHGUI_SewingDlg::onSwapClicked() +{ + if ( !setCurrentPart() ) + return; + + SMESH::FreeBordersGroup& aGRP = myBorders->coincidentGroups[ myCurGroupIndex ]; + SMESH::FreeBorderPart& aPRT = aGRP[ myCurPartIndex ]; + SMESH::FreeBorder& aBRD = myBorders->borders[ aPRT.border ]; + int size = (int) aBRD.nodeIDs.length(); + + bool isClosed = ( aBRD.nodeIDs[0] == aBRD.nodeIDs[ size-1 ]); + if ( isClosed ) --size; + + bool isFwd = ( Abs( aPRT.node2 - aPRT.node1 ) == 1 ) ? aPRT.node2 > aPRT.node1 : aPRT.node2 < aPRT.node1; + + std::swap( aPRT.nodeLast, aPRT.node1 ); + + aPRT.node2 = ( aPRT.node1 + ( isFwd ? -1 : +1 ) + size ) % size; + + onGroupChange( /*partChange=*/true ); +} + //================================================================================= // function : ClickOnApply() // purpose : @@ -456,11 +1257,11 @@ bool SMESHGUI_SewingDlg::ClickOnApply() bool aResult = false; - if (IsValid()) { - bool toMerge = CheckBoxMerge->isChecked(); + if (IsValid()) + { + bool toMerge = CheckBoxMerge->isChecked(); bool toCreatePolygons = CheckBoxPolygons->isChecked(); bool toCreatePolyedrs = CheckBoxPolyedrs->isChecked(); - try { SUIT_OverrideCursor aWaitCursor; SMESH::SMESH_MeshEditor_var aMeshEditor = myMesh->GetMeshEditor(); @@ -469,21 +1270,51 @@ bool SMESHGUI_SewingDlg::ClickOnApply() SMESH::SMESH_MeshEditor::Sew_Error anError; if (aConstructorId == 0) - anError = aMeshEditor->SewFreeBorders(LineEdit1->text().toLong(), - LineEdit2->text().toLong(), - LineEdit3->text().toLong(), - LineEdit4->text().toLong(), - LineEdit5->text().toLong(), - LineEdit6->text().toLong(), - toCreatePolygons, - toCreatePolyedrs); + { + if ( ModeButGrp->checkedId() == MODE_MANUAL ) + { + anError = aMeshEditor->SewFreeBorders(LineEdit1->text().toLong(), + LineEdit2->text().toLong(), + LineEdit3->text().toLong(), + LineEdit4->text().toLong(), + LineEdit5->text().toLong(), + LineEdit6->text().toLong(), + toCreatePolygons, + toCreatePolyedrs); + } + else + { + int nbCoincGroups = ListCoincident->count(); + if ( AutoSewCheck->isChecked() ) + { + myBorders = aMeshEditor->FindCoincidentFreeBorders( SpinBoxTolerance->GetValue() ); + nbCoincGroups = myBorders->coincidentGroups.length(); + } + CORBA::Short nbSewed = aMeshEditor->SewCoincidentFreeBorders( myBorders.inout(), + toCreatePolygons, + toCreatePolyedrs); + QString msg; + if ( nbCoincGroups == 0 ) + msg = tr("NO_BORDERS_TO_SEW"); + else if ( nbSewed < nbCoincGroups ) + msg = tr("NOT_ALL_BORDERS_SEWED").arg( nbSewed ).arg( nbCoincGroups ); + else + msg = tr("ALL_BORDERS_SEWED").arg( nbSewed ); + SUIT_MessageBox::information( this, tr("SMESH_INFORMATION"), msg ); + + anError = SMESH::SMESH_MeshEditor::SEW_OK; + } + } else if (aConstructorId == 1) + { anError = aMeshEditor->SewConformFreeBorders(LineEdit1->text().toLong(), LineEdit2->text().toLong(), LineEdit3->text().toLong(), LineEdit4->text().toLong(), LineEdit5->text().toLong()); + } else if (aConstructorId == 2) + { anError = aMeshEditor->SewBorderToSide(LineEdit1->text().toLong(), LineEdit2->text().toLong(), LineEdit3->text().toLong(), @@ -491,6 +1322,7 @@ bool SMESHGUI_SewingDlg::ClickOnApply() LineEdit6->text().toLong(), toCreatePolygons, toCreatePolyedrs); + } else if (aConstructorId == 3) { QStringList aListElementsId1 = LineEdit1->text().split(" ", QString::SkipEmptyParts); QStringList aListElementsId2 = LineEdit4->text().split(" ", QString::SkipEmptyParts); @@ -526,13 +1358,15 @@ bool SMESHGUI_SewingDlg::ClickOnApply() } if (aResult) { - Handle(SALOME_InteractiveObject) anIO = myActor->getIO(); - - SALOME_ListIO aList; - aList.Append(anIO); - mySelectionMgr->setSelectedObjects(aList, false); - SMESH::UpdateView(); + if ( myActor ) + { + Handle(SALOME_InteractiveObject) anIO = myActor->getIO(); + SALOME_ListIO aList; + aList.Append(anIO); + mySelectionMgr->setSelectedObjects(aList, false); + SMESH::UpdateView(); + } Init(); ConstructorsClicked(GetConstructorId()); @@ -576,6 +1410,13 @@ void SMESHGUI_SewingDlg::onCloseView() { DeactivateActiveDialog(); mySelector = 0; + + for ( size_t i = 0; i < myBorderDisplayers.size(); ++i ) + { + delete myBorderDisplayers[ i ]; + myBorderDisplayers[ i ] = 0; + } + myBorderDisplayers.clear(); } //================================================================================= @@ -584,6 +1425,7 @@ void SMESHGUI_SewingDlg::onCloseView() //================================================================================= void SMESHGUI_SewingDlg::reject() { + restoreDisplayMode(); //mySelectionMgr->clearSelected(); SMESH::SetPointRepresentation(false); if ( SVTK_ViewWindow* aViewWindow = SMESH::GetViewWindow( mySMESHGUI )) @@ -644,9 +1486,6 @@ void SMESHGUI_SewingDlg::onTextChange (const QString& theNewText) else if (send == LineEdit6) myOk6 = false; - buttonOk->setEnabled(false); - buttonApply->setEnabled(false); - // hilight entered elements/nodes SMDS_Mesh* aMesh = 0; @@ -718,10 +1557,7 @@ void SMESHGUI_SewingDlg::onTextChange (const QString& theNewText) } } - if (IsValid()) { - buttonOk->setEnabled(true); - buttonApply->setEnabled(true); - } + UpdateButtons(); myBusy = false; } @@ -735,6 +1571,7 @@ void SMESHGUI_SewingDlg::SelectionIntoArgument (bool isSelectionChanged) if (myBusy) return; // clear + restoreDisplayMode(); if (isSelectionChanged) myActor = 0; @@ -742,13 +1579,18 @@ void SMESHGUI_SewingDlg::SelectionIntoArgument (bool isSelectionChanged) myBusy = true; myEditCurrentArgument->setText(aString); + ListCoincident->clear(); + ListEdit->clear(); myBusy = false; + onSelectGroup(); // erase preview + if (!GroupButtons->isEnabled()) // inactive return; buttonOk->setEnabled(false); buttonApply->setEnabled(false); + DetectButton->setEnabled(false); // get selected mesh SALOME_ListIO aList; @@ -759,20 +1601,40 @@ void SMESHGUI_SewingDlg::SelectionIntoArgument (bool isSelectionChanged) return; Handle(SALOME_InteractiveObject) IO = aList.First(); - myMesh = SMESH::GetMeshByIO(IO); //@ SMESH::IObjectToInterface(IO); + myMesh = SMESH::GetMeshByIO(IO); myActor = SMESH::FindActorByEntry(aList.First()->getEntry()); + if (myMesh->_is_nil()) + return; + + CheckBoxPolyedrs->setEnabled( myMesh->NbVolumes() > 0 ); + + if ( myEditCurrentArgument == LineEditMesh ) + { + LineEditMesh->setText( IO->getName() ); + ListCoincident->clear(); + if ( AutoSewCheck->isChecked() ) + { + buttonOk->setEnabled(true); + buttonApply->setEnabled(true); + } + DetectButton->setEnabled( myMesh->NbFaces() > 0 ); + setDisplayMode(); + return; + } - if (myMesh->_is_nil() || !myActor) + if (!myActor) return; // get selected elements/nodes int aNbUnits = 0; - if (GetConstructorId() != 3 || - (myEditCurrentArgument != LineEdit1 && myEditCurrentArgument != LineEdit4)) { + if (( GetConstructorId() != 3 ) || + ( myEditCurrentArgument != LineEdit1 && myEditCurrentArgument != LineEdit4)) + { aNbUnits = SMESH::GetNameOfSelectedNodes(mySelector, IO, aString); if (aNbUnits != 1) return; - } else { + } + else { aNbUnits = SMESH::GetNameOfSelectedElements(mySelector, IO, aString); if (aNbUnits < 1) return; @@ -796,10 +1658,7 @@ void SMESHGUI_SewingDlg::SelectionIntoArgument (bool isSelectionChanged) else if (myEditCurrentArgument == LineEdit6) myOk6 = true; - if (IsValid()) { - buttonOk->setEnabled(true); - buttonApply->setEnabled(true); - } + UpdateButtons(); } //================================================================================= @@ -918,9 +1777,38 @@ int SMESHGUI_SewingDlg::GetConstructorId() //================================================================================= bool SMESHGUI_SewingDlg::IsValid() { + if ( myMesh->_is_nil() ) + return false; + + if ( GetConstructorId() == 0 && ModeButGrp->checkedId() == MODE_AUTO ) + { + if ( AutoSewCheck->isChecked() ) + return true; + + int nbGroups = 0; + if ( haveBorders() ) + for ( int i = 0; i < ListCoincident->count(); ++i ) + { + int groupIndex = ListCoincident->item(i)->data( GROUP_INDEX ).toInt(); + nbGroups += ( !getGroupText( groupIndex ).isEmpty() ); + } + return nbGroups > 0; + } return (myOk1 && myOk2 && myOk3 && myOk4 && myOk5 && myOk6); } +//======================================================================= +//function : UpdateButtons +//purpose : activate [Apply] buttons +//======================================================================= + +void SMESHGUI_SewingDlg::UpdateButtons() +{ + bool ok = IsValid(); + buttonOk->setEnabled( ok ); + buttonApply->setEnabled( ok ); +} + //================================================================================= // function : keyPressEvent() // purpose : @@ -936,3 +1824,157 @@ void SMESHGUI_SewingDlg::keyPressEvent( QKeyEvent* e ) ClickOnHelp(); } } + +SMESHGUI_SewingDlg:: +BorderGroupDisplayer::BorderGroupDisplayer( const SMESH::CoincidentFreeBorders& borders, + int groupIndex, + QColor color, + SMESH::SMESH_Mesh_ptr mesh): + myBorders ( borders.borders ), + myGroup ( borders.coincidentGroups[ groupIndex ]), + myColor ( color ), + myMesh ( mesh ), + myViewWindow( SMESH::GetCurrentVtkView() ), + myIdPreview ( myViewWindow ) +{ + Update(); +} + +SMESHGUI_SewingDlg::BorderGroupDisplayer::~BorderGroupDisplayer() +{ + for ( size_t i = 0; i < myPartActors.size(); ++i ) + { + if ( myPartActors[ i ]) { + myViewWindow->RemoveActor( myPartActors[i] ); + myPartActors[i]->Delete(); + } + } + myIdPreview.SetPointsLabeled(false); + //myViewWindow->Repaint(); +} + +void SMESHGUI_SewingDlg::BorderGroupDisplayer::Hide() +{ + for ( size_t i = 0; i < myPartActors.size(); ++i ) + if ( myPartActors[ i ]) + myPartActors[ i ]->SetVisibility(false); + + myIdPreview.SetPointsLabeled(false); +} + +void SMESHGUI_SewingDlg::BorderGroupDisplayer::ShowGroup( bool wholeBorders ) +{ + std::vector ids; + std::list coords; + for ( size_t i = 0; i < myPartActors.size(); ++i ) + if ( myPartActors[ i ]) + { + myPartActors[ i ]->SetPointRepresentation( wholeBorders ); + myPartActors[ i ]->SetVisibility( true ); + if ( wholeBorders ) + getPartEnds( i, ids, coords ); + } + if ( wholeBorders ) + myIdPreview.SetElemsData( ids, coords ); + myIdPreview.SetPointsLabeled( wholeBorders, true ); +} + +void SMESHGUI_SewingDlg::BorderGroupDisplayer::ShowPart( int partIndex, bool toEdit ) +{ + if ( partIndex < (int) myPartActors.size() ) + { + myPartActors[partIndex]->SetVisibility(true); + myPartActors[partIndex]->SetPointRepresentation(toEdit); + + if ( toEdit ) + { + std::vector ids; + std::list coords; + getPartEnds( partIndex, ids, coords ); + + myIdPreview.SetElemsData( ids, coords ); + myIdPreview.SetPointsLabeled( true, /*show=*/true ); + } + } +} + +void SMESHGUI_SewingDlg::BorderGroupDisplayer::getPartEnds( int partIndex, + std::vector & ids, + std::list& coords) +{ + const SMESH::FreeBorderPart& aPART = myGroup [ partIndex ]; + const SMESH::FreeBorder& aBRD = myBorders[ aPART.border ]; + + ids.push_back( aBRD.nodeIDs[ aPART.node1 ]); + ids.push_back( aBRD.nodeIDs[ aPART.nodeLast ]); + + SMDS_Mesh* mesh = myPartActors[ partIndex ]->GetObject()->GetMesh(); + + coords.push_back( SMESH_TNodeXYZ( mesh->FindNode( aPART.node1+1 ))); + coords.push_back( SMESH_TNodeXYZ( mesh->FindNode( aPART.nodeLast+1 ))); +} + +void SMESHGUI_SewingDlg::BorderGroupDisplayer::Update() +{ + Hide(); + myPartActors.resize( myGroup.length(), 0 ); + + for ( size_t i = 0; i < myPartActors.size(); ++i ) + { + TVisualObjPtr obj; + if ( myPartActors[ i ]) + obj = myPartActors[ i ]->GetObject(); + else + obj = TVisualObjPtr( new SMESHGUI_PreVisualObj() ); + SMDS_Mesh* mesh = obj->GetMesh(); + mesh->Clear(); + + // add nodes + const SMESH::FreeBorderPart& aPRT = myGroup[ i ]; + const SMESH::FreeBorder& aBRD = myBorders[ aPRT.border ]; + for ( CORBA::ULong iN = 0; iN < aBRD.nodeIDs.length(); ++iN ) + { + SMESH::double_array_var xyz = myMesh->GetNodeXYZ( aBRD.nodeIDs[ iN ]); + if ( xyz->length() == 3 ) + mesh->AddNode( xyz[0], xyz[1], xyz[2] ); + } + + // add edges + bool isFwd = ( Abs( aPRT.node2 - aPRT.node1 ) == 1 ) ? aPRT.node2 > aPRT.node1 : aPRT.node2 < aPRT.node1; + int dn = isFwd ? +1 : -1; + int size = (int) aBRD.nodeIDs.length(); + int n2, n1 = aPRT.node1; + for ( n2 = n1 + dn; ( n2 >= 0 && n2 < size ); n2 += dn ) + { + mesh->AddEdgeWithID( n1+1, n2+1, mesh->NbEdges() + 1 ); + n1 = n2; + if ( n2 == aPRT.nodeLast ) + break; + } + if ( n2 % size != aPRT.nodeLast ) + { + if ( n2 < 0 ) n1 = size; + else n1 = 0; + for ( n2 = n1 + dn; ( n2 >= 0 && n2 < size ); n2 += dn ) + { + mesh->AddEdgeWithID( n1+1, n2+1, mesh->NbEdges() + 1 ); + n1 = n2; + if ( n2 == aPRT.nodeLast ) + break; + } + } + + if ( !myPartActors[ i ]) // TVisualObj must be filled before actor creation + { + myPartActors[ i ] = SMESH_Actor::New( obj, "", "", 1 ); + myPartActors[ i ]->SetEdgeColor( myColor.redF(), myColor.greenF(), myColor.blueF() ); + myPartActors[ i ]->SetLineWidth( 3 * SMESH::GetFloat("SMESH:element_width",1)); + myPartActors[ i ]->SetPickable( false ); + myPartActors[ i ]->SetNodeColor( myColor.redF(), myColor.greenF(), myColor.blueF() ); + myPartActors[ i ]->SetMarkerStd( VTK::MT_POINT, 13 ); + myViewWindow->AddActor( myPartActors[ i ]); + myViewWindow->Repaint(); + } + } +} + diff --git a/src/SMESHGUI/SMESHGUI_SewingDlg.h b/src/SMESHGUI/SMESHGUI_SewingDlg.h index 3d2b91f36..2bf5c591c 100644 --- a/src/SMESHGUI/SMESHGUI_SewingDlg.h +++ b/src/SMESHGUI/SMESHGUI_SewingDlg.h @@ -36,6 +36,9 @@ // IDL includes #include #include CORBA_SERVER_HEADER(SMESH_Mesh) +#include CORBA_SERVER_HEADER(SMESH_MeshEditor) + +#include class QButtonGroup; class QGroupBox; @@ -48,6 +51,10 @@ class SMESHGUI; class SMESH_Actor; class SVTK_Selector; class LightApp_SelectionMgr; +class SMESHGUI_SpinBox; +class SalomeApp_IntSpinBox; +class QListWidget; +class QListWidgetItem; //================================================================================= // class : SMESHGUI_SewingDlg @@ -67,7 +74,8 @@ private: void keyPressEvent( QKeyEvent* ); int GetConstructorId(); bool IsValid(); - + void UpdateButtons(); + SMESHGUI* mySMESHGUI; /* Current SMESHGUI object */ LightApp_SelectionMgr* mySelectionMgr; /* User shape selection */ int myOk1, myOk2, myOk3, myOk4, myOk5, myOk6; @@ -114,13 +122,67 @@ private: QCheckBox* CheckBoxPolygons; QCheckBox* CheckBoxPolyedrs; + QWidget* SewFreeBordersWidget; + QGroupBox* ModeGroup; + QButtonGroup* ModeButGrp; + //QPushButton* SelectMeshButton; + QLineEdit* LineEditMesh; + + SMESHGUI_SpinBox* SpinBoxTolerance; + QCheckBox* AutoSewCheck; + + QWidget* GroupCoincidentWidget; + QListWidget* ListCoincident; + QPushButton* DetectButton; + QPushButton* RemoveGroupButton; + QCheckBox* SelectAllCheck; + + QListWidget* ListEdit; + QButtonGroup* MoveBorderEndsButGrp; + QLineEdit* BorderEndLine[2]; + QPushButton* SwapBut; + QPushButton* SetFirstButton; + QPushButton* RemoveElemButton; + SalomeApp_IntSpinBox* StepSpin; + QString myHelpFileName; -protected slots: + + struct BorderGroupDisplayer; + std::vector< BorderGroupDisplayer* > myBorderDisplayers; + SMESH::CoincidentFreeBorders_var myBorders; + int myCurGroupIndex; + int myCurPartIndex; + int myStoredRepresentation; + unsigned int myStoredEntityMode; + + bool haveBorders(); + QString getGroupText( int groupIndex ); + QString getPartText( const SMESH::FreeBorderPart& part ); + void showGroup( QListWidgetItem* item ); + bool setCurrentGroup(); + bool setCurrentPart(); + void onGroupChange(bool partChange=false); + void setDisplayMode(); + void restoreDisplayMode(); + + + protected slots: virtual void reject(); -private slots: + private slots: void ConstructorsClicked( int ); + void onModeChange( int ); + void onAutoSew( int ); + void onDetectClicked(); + void onRemoveGroupClicked(); + void onSelectGroup(); + void onSelectAll(int); + void onSelectBorderPartFromGroup(); + void onSetFirstClicked(); + void onRemoveElemClicked(); + void onMoveBorderEnd(int); + void onSwapClicked(); void ClickOnOk(); bool ClickOnApply(); void ClickOnHelp(); diff --git a/src/SMESHGUI/SMESH_msg_en.ts b/src/SMESHGUI/SMESH_msg_en.ts index 8eb62658c..36a4916cc 100644 --- a/src/SMESHGUI/SMESH_msg_en.ts +++ b/src/SMESHGUI/SMESH_msg_en.ts @@ -5141,7 +5141,7 @@ Please select a group and try again SEPARATE_CORNERS_AND_MEDIUM - No merge of corner and medium nodes + No merge of corner and medium nodes of quadratic cells KEEP_NODES @@ -5155,10 +5155,6 @@ Please select a group and try again SELECT Select: - - - - SMESHGUI_ExtrusionAlongPathDlg @@ -6665,6 +6661,42 @@ It is impossible to read point coordinates from file SIDE_2 Side 2 + + AUTO_SEWING + Auto Sewing + + + COINCIDENT_FREE_BORDERS + Coincident Free Borders + + + DETECT + Detect + + + SELECT_ALL + Select all + + + EDIT_SELECTED_GROUP + Edit Selected Group + + + STEP + Step + + + NO_BORDERS_TO_SEW + No free borders to sew found + + + NOT_ALL_BORDERS_SEWED + %1 of %2 groups of borders sewed + + + ALL_BORDERS_SEWED + %1 group(s) of borders sewed + SMESHGUI_ShapeByMeshDlg diff --git a/src/SMESHUtils/CMakeLists.txt b/src/SMESHUtils/CMakeLists.txt index 8bafe47f4..c79b29f28 100644 --- a/src/SMESHUtils/CMakeLists.txt +++ b/src/SMESHUtils/CMakeLists.txt @@ -79,6 +79,7 @@ SET(SMESHUtils_SOURCES SMESH_File.cxx SMESH_MeshAlgos.cxx SMESH_MAT2d.cxx + SMESH_FreeBorders.cxx ) # --- rules --- diff --git a/src/SMESHUtils/SMESH_FreeBorders.cxx b/src/SMESHUtils/SMESH_FreeBorders.cxx new file mode 100644 index 000000000..8d5e8ca53 --- /dev/null +++ b/src/SMESHUtils/SMESH_FreeBorders.cxx @@ -0,0 +1,507 @@ +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, 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_FreeBorders.cxx +// Created : Tue Sep 8 17:08:39 2015 +// Author : Edward AGAPOV (eap) + +//================================================================================ +// Implementation of SMESH_MeshAlgos::FindCoincidentFreeBorders() +//================================================================================ + +#include "SMESH_MeshAlgos.hxx" + +#include "SMDS_LinearEdge.hxx" +#include "SMDS_Mesh.hxx" +#include "SMDS_SetIterator.hxx" + +#include +#include +#include +#include + +#include +#include + +using namespace SMESH_MeshAlgos; + +namespace +{ + struct BEdge; + + /*! + * \brief Node on a free border + */ + struct BNode + { + const SMDS_MeshNode * myNode; + mutable std::vector< BEdge* > myLinkedEdges; + mutable std::vector< BEdge* > myCloseEdges; + + BNode(const SMDS_MeshNode * node): myNode( node ) {} + void AddLinked( BEdge* e ) const; + void AddClose ( const BEdge* e ) const; + BEdge* FindCloseEdgeOfBorder( int borderID ) const; + bool operator<(const BNode& other) const { return myNode->GetID() < other.myNode->GetID(); } + }; + /*! + * \brief Edge of a free border + */ + struct BEdge : public SMDS_LinearEdge + { + const BNode* myBNode1; + const BNode* myBNode2; + int myBorderID; + int myID; // within a border + BEdge* myPrev; + BEdge* myNext; + const SMDS_MeshElement* myFace; + std::set< int > myCloseBorders; + bool myInGroup; + + BEdge():SMDS_LinearEdge( 0, 0 ), myBorderID(-1), myID(-1), myPrev(0), myNext(0), myInGroup(0) {} + + void Set( const BNode * node1, + const BNode * node2, + const SMDS_MeshElement* face, + const int ID) + { + myBNode1 = node1; + myBNode2 = node2; + myNodes[0] = node1->myNode; + myNodes[1] = node2->myNode; + myFace = face; + setId( ID ); // mesh element ID + } + bool Contains( const BNode* n ) const + { + return ( n == myBNode1 || n == myBNode2 ); + } + void AddLinked( BEdge* e ) + { + if ( e->Contains( myBNode1 )) myPrev = e; + else myNext = e; + } + void RemoveLinked( BEdge* e ) + { + if ( myPrev == e ) myPrev = 0; + if ( myNext == e ) myNext = 0; + } + void Reverse() + { + std::swap( myBNode1, myBNode2 ); + myNodes[0] = myBNode1->myNode; + myNodes[1] = myBNode2->myNode; + } + void Orient() + { + if (( myPrev && !myPrev->Contains( myBNode1 )) || + ( myNext && !myNext->Contains( myBNode2 ))) + std::swap( myPrev, myNext ); + if ( myPrev && myPrev->myBNode2 != myBNode1 ) myPrev->Reverse(); + if ( myNext && myNext->myBNode1 != myBNode2 ) myNext->Reverse(); + } + void SetID( int id ) + { + if ( myID < 0 ) + { + myID = id; + if ( myNext ) + myNext->SetID( id + 1 ); + } + } + void FindRangeOfSameCloseBorders(BEdge* eRange[2]) + { + eRange[0] = this; + while ( eRange[0]->myPrev && eRange[0]->myPrev->myCloseBorders == this->myCloseBorders ) + { + if ( eRange[0]->myPrev == this /*|| eRange[0]->myPrev->myInGroup*/ ) + break; + eRange[0] = eRange[0]->myPrev; + } + eRange[1] = this; + if ( eRange[0]->myPrev != this ) // not closed range + while ( eRange[1]->myNext && eRange[1]->myNext->myCloseBorders == this->myCloseBorders ) + { + if ( eRange[1]->myNext == this /*|| eRange[1]->myNext->myInGroup*/ ) + break; + eRange[1] = eRange[1]->myNext; + } + } + }; + + void BNode::AddLinked( BEdge* e ) const + { + myLinkedEdges.reserve(2); + myLinkedEdges.push_back( e ); + if ( myLinkedEdges.size() < 2 ) return; + + if ( myLinkedEdges.size() == 2 ) + { + myLinkedEdges[0]->AddLinked( myLinkedEdges[1] ); + myLinkedEdges[1]->AddLinked( myLinkedEdges[0] ); + } + else + { + for ( size_t i = 0; i < myLinkedEdges.size(); ++i ) + for ( size_t j = 0; j < myLinkedEdges.size(); ++j ) + if ( i != j ) + myLinkedEdges[i]->RemoveLinked( myLinkedEdges[j] ); + } + } + void BNode::AddClose ( const BEdge* e ) const + { + if ( ! e->Contains( this )) + myCloseEdges.push_back( const_cast< BEdge* >( e )); + } + BEdge* BNode::FindCloseEdgeOfBorder( int borderID ) const + { + for ( size_t i = 0; i < myCloseEdges.size(); ++i ) + if ( borderID == myCloseEdges[ i ]->myBorderID ) + return myCloseEdges[ i ]; + return 0; + } + + /// Accessor to SMDS_MeshElement* inherited by BEdge + struct ElemAcess + { + static const SMDS_MeshElement* value( std::vector< BEdge >::const_iterator it) + { + return & (*it); + } + }; + /// Iterator over a vector of BEdge's + static SMDS_ElemIteratorPtr getElemIterator( const std::vector< BEdge > & bedges ) + { + typedef SMDS_SetIterator + < const SMDS_MeshElement*, std::vector< BEdge >::const_iterator, ElemAcess > BEIter; + return SMDS_ElemIteratorPtr( new BEIter( bedges.begin(), bedges.end() )); + } + +} // namespace + +// struct needed for NCollection_Map +struct TLinkHasher +{ + static int HashCode(const SMESH_TLink& link, int aLimit) + { + return ::HashCode( link.node1()->GetID() + link.node2()->GetID(), aLimit ); + } + static Standard_Boolean IsEqual(const SMESH_TLink& l1, const SMESH_TLink& l2) + { + return ( l1.node1() == l2.node1() && l1.node2() == l2.node2() ); + } +}; + +//================================================================================ +/* + * Returns groups of TFreeBorder's coincident within the given tolerance. + * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent + * to free borders being compared is used. + */ +//================================================================================ + +void SMESH_MeshAlgos::FindCoincidentFreeBorders(SMDS_Mesh& mesh, + double tolerance, + CoincidentFreeBorders & foundFreeBordes) +{ + // find free links + typedef NCollection_DataMap TLink2FaceMap; + TLink2FaceMap linkMap; + SMDS_FaceIteratorPtr faceIt = mesh.facesIterator(); + while ( faceIt->more() ) + { + const SMDS_MeshElement* face = faceIt->next(); + if ( !face ) continue; + + const SMDS_MeshNode* n0 = face->GetNode( face->NbNodes() - 1 ); + SMDS_NodeIteratorPtr nodeIt = face->interlacedNodesIterator(); + while ( nodeIt->more() ) + { + const SMDS_MeshNode* n1 = nodeIt->next(); + SMESH_TLink link( n0, n1 ); + if ( !linkMap.Bind( link, face )) + linkMap.UnBind( link ); + n0 = n1; + } + } + if ( linkMap.IsEmpty() ) + return; + + // form free borders + std::set < BNode > bNodes; + std::vector< BEdge > bEdges( linkMap.Extent() ); + + TLink2FaceMap::Iterator linkIt( linkMap ); + for ( int iEdge = 0; linkIt.More(); linkIt.Next(), ++iEdge ) + { + const SMESH_TLink & link = linkIt.Key(); + std::set< BNode >::iterator n1 = bNodes.insert( BNode( link.node1() )).first; + std::set< BNode >::iterator n2 = bNodes.insert( BNode( link.node2() )).first; + bEdges[ iEdge ].Set( &*n1, &*n2, linkIt.Value(), iEdge+1 ); + n1->AddLinked( & bEdges[ iEdge ] ); + n2->AddLinked( & bEdges[ iEdge ] ); + } + linkMap.Clear(); + + // assign IDs to borders + std::vector< BEdge* > borders; // 1st of connected (via myPrev and myNext) edges + std::set< BNode >::iterator bn = bNodes.begin(); + for ( ; bn != bNodes.end(); ++bn ) + { + for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i ) + { + if ( bn->myLinkedEdges[i]->myBorderID < 0 ) + { + BEdge* be = bn->myLinkedEdges[i]; + int borderID = borders.size(); + borders.push_back( be ); + for ( ; be && be->myBorderID < 0; be = be->myNext ) + { + be->myBorderID = borderID; + be->Orient(); + } + bool isClosed = ( be == bn->myLinkedEdges[i] ); + be = bn->myLinkedEdges[i]->myPrev; + for ( ; be && be->myBorderID < 0; be = be->myPrev ) + { + be->myBorderID = borderID; + be->Orient(); + } + if ( !isClosed ) + while ( borders.back()->myPrev ) + borders.back() = borders.back()->myPrev; + + borders.back()->SetID( 0 ); // set IDs to all edges of the border + } + } + } + + // compute tolerance of each border + double maxTolerance = tolerance; + std::vector< double > bordToler( borders.size(), tolerance ); + if ( maxTolerance < std::numeric_limits< double >::min() ) + { + // no tolerance provided by the user; compute tolerance of each border + // as one tenth of an average size of faces adjacent to a border + for ( size_t i = 0; i < borders.size(); ++i ) + { + double avgFaceSize = 0; + int nbFaces = 0; + BEdge* be = borders[ i ]; + do { + double facePerimeter = 0; + gp_Pnt p0 = SMESH_TNodeXYZ( be->myFace->GetNode( be->myFace->NbNodes() - 1 )); + SMDS_NodeIteratorPtr nodeIt = be->myFace->interlacedNodesIterator(); + while ( nodeIt->more() ) + { + gp_Pnt p1 = SMESH_TNodeXYZ( nodeIt->next() ); + facePerimeter += p0.Distance( p1 ); + p0 = p1; + } + avgFaceSize += ( facePerimeter / be->myFace->NbCornerNodes() ); + nbFaces++; + + be = be->myNext; + } + while ( be && be != borders[i] ); + + bordToler[ i ] = 0.1 * avgFaceSize / nbFaces; + maxTolerance = Max( maxTolerance, bordToler[ i ]); + } + } + + // for every border node find close border edges + SMESH_ElementSearcher* searcher = + GetElementSearcher( mesh, getElemIterator( bEdges ), maxTolerance ); + SMESHUtils::Deleter< SMESH_ElementSearcher > searcherDeleter( searcher ); + std::vector< const SMDS_MeshElement* > candidateEdges; + for ( bn = bNodes.begin(); bn != bNodes.end(); ++bn ) + { + gp_Pnt point = SMESH_TNodeXYZ( bn->myNode ); + searcher->FindElementsByPoint( point, SMDSAbs_Edge, candidateEdges ); + if ( candidateEdges.size() <= bn->myLinkedEdges.size() ) + continue; + + double nodeTol = 0; + for ( size_t i = 0; i < bn->myLinkedEdges.size(); ++i ) + nodeTol = Max( nodeTol, bordToler[ bn->myLinkedEdges[ i ]->myBorderID ]); + + for ( size_t i = 0; i < candidateEdges.size(); ++i ) + { + const BEdge* be = static_cast< const BEdge* >( candidateEdges[ i ]); + double tol = Max( nodeTol, bordToler[ be->myBorderID ]); + if ( maxTolerance - tol < 1e-12 || + !SMESH_MeshAlgos::IsOut( be, point, tol )) + bn->AddClose( be ); + } + } + + // for every border edge find close borders + + std::vector< BEdge* > closeEdges; + for ( size_t i = 0; i < bEdges.size(); ++i ) + { + BEdge& be = bEdges[i]; + if ( be.myBNode1->myCloseEdges.empty() || + be.myBNode2->myCloseEdges.empty() ) + continue; + + closeEdges.clear(); + for ( size_t iE1 = 0; iE1 < be.myBNode1->myCloseEdges.size(); ++iE1 ) + { + // find edges of the same border close to both nodes of the edge + BEdge* closeE1 = be.myBNode1->myCloseEdges[ iE1 ]; + BEdge* closeE2 = be.myBNode2->FindCloseEdgeOfBorder( closeE1->myBorderID ); + if ( !closeE2 ) + continue; + // check that edges connecting closeE1 and closeE2 (if any) are also close to 'be' + if ( closeE1 != closeE2 ) + { + bool coincide; + for ( int j = 0; j < 2; ++j ) // move closeE1 -> closeE2 or inversely + { + BEdge* ce = closeE1; + do { + coincide = ( ce->myBNode2->FindCloseEdgeOfBorder( be.myBorderID )); + ce = ce->myNext; + } while ( coincide && ce && ce != closeE2 ); + + if ( coincide && ce == closeE2 ) + break; + if ( j == 0 ) + std::swap( closeE1, closeE2 ); + coincide = false; + } + if ( !coincide ) + continue; + closeEdges.push_back( closeE1 ); + closeEdges.push_back( closeE2 ); + } + else + { + closeEdges.push_back( closeE1 ); + } + be.myCloseBorders.insert( closeE1->myBorderID ); + } + if ( !closeEdges.empty() ) + { + be.myCloseBorders.insert( be.myBorderID ); + // for ( size_t iB = 0; iB < closeEdges.size(); ++iB ) + // closeEdges[ iB ]->myCloseBorders.insert( be.myCloseBorders.begin(), + // be.myCloseBorders.end() ); + } + } + + // Fill in CoincidentFreeBorders + + // save nodes of free borders + foundFreeBordes._borders.resize( borders.size() ); + for ( size_t i = 0; i < borders.size(); ++i ) + { + BEdge* be = borders[i]; + foundFreeBordes._borders[i].push_back( be->myBNode1->myNode ); + do { + foundFreeBordes._borders[i].push_back( be->myBNode2->myNode ); + be = be->myNext; + } + while ( be && be != borders[i] ); + } + + // form groups of coincident parts of free borders + + TFreeBorderPart part; + TCoincidentGroup group; + for ( size_t i = 0; i < borders.size(); ++i ) + { + BEdge* be = borders[i]; + + // look for an edge close to other borders + do { + if ( !be->myInGroup && !be->myCloseBorders.empty() ) + break; + be = be->myNext; + } while ( be && be != borders[i] ); + + if ( !be || be->myInGroup || be->myCloseBorders.empty() ) + continue; // all edges of a border treated or are non-coincident + + group.clear(); + + // look for the 1st and last edge of a coincident group + BEdge* beRange[2]; + be->FindRangeOfSameCloseBorders( beRange ); + BEdge* be1st = beRange[0]; + + // fill in a group + part._border = i; + part._node1 = beRange[0]->myID; + part._node2 = beRange[0]->myID + 1; + part._nodeLast = beRange[1]->myID + 1; + group.push_back( part ); + + be = beRange[0]; + be->myInGroup = true; + while ( be != beRange[1] ) + { + be->myInGroup = true; + be = be->myNext; + } + beRange[1]->myInGroup = true; + + // add parts of other borders + std::set::iterator closeBord = be1st->myCloseBorders.begin(); + for ( ; closeBord != be1st->myCloseBorders.end(); ++closeBord ) + { + be = be1st->myBNode2->FindCloseEdgeOfBorder( *closeBord ); + if ( !be ) continue; + + be->FindRangeOfSameCloseBorders( beRange ); + + // find out mutual orientation of borders + bool reverse = ( beRange[0]->myBNode1->FindCloseEdgeOfBorder( i ) != be1st && + beRange[0]->myBNode2->FindCloseEdgeOfBorder( i ) != be1st ); + + // fill in a group + part._border = beRange[0]->myBorderID; + if ( reverse ) { + part._node1 = beRange[1]->myID + 1; + part._node2 = beRange[1]->myID; + part._nodeLast = beRange[0]->myID; + } + else { + part._node1 = beRange[0]->myID; + part._node2 = beRange[0]->myID + 1; + part._nodeLast = beRange[1]->myID + 1; + } + group.push_back( part ); + + be = beRange[0]; + be->myInGroup = true; + while ( be != beRange[1] ) + { + be->myInGroup = true; + be = be->myNext; + } + beRange[1]->myInGroup = true; + } + + foundFreeBordes._coincidentGroups.push_back( group ); + + } // loop on free borders +} diff --git a/src/SMESHUtils/SMESH_MeshAlgos.cxx b/src/SMESHUtils/SMESH_MeshAlgos.cxx index a16379b00..dc157e716 100644 --- a/src/SMESHUtils/SMESH_MeshAlgos.cxx +++ b/src/SMESHUtils/SMESH_MeshAlgos.cxx @@ -439,8 +439,10 @@ struct SMESH_ElementSearcherImpl: public SMESH_ElementSearcher bool _outerFacesFound; set _outerFaces; // empty means "no internal faces at all" - SMESH_ElementSearcherImpl( SMDS_Mesh& mesh, SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr()) - : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(-1),_outerFacesFound(false) {} + SMESH_ElementSearcherImpl( SMDS_Mesh& mesh, + double tol=-1, + SMDS_ElemIteratorPtr elemIt=SMDS_ElemIteratorPtr()) + : _mesh(&mesh),_meshPartIt(elemIt),_ebbTree(0),_nodeSearcher(0),_tolerance(tol),_outerFacesFound(false) {} virtual ~SMESH_ElementSearcherImpl() { if ( _ebbTree ) delete _ebbTree; _ebbTree = 0; @@ -1091,32 +1093,22 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin // get ordered nodes - vector< gp_XYZ > xyz; - vector nodeList; + vector< SMESH_TNodeXYZ > xyz; - SMDS_ElemIteratorPtr nodeIt = element->nodesIterator(); - if ( element->IsQuadratic() ) { - nodeIt = element->interlacedNodesElemIterator(); - // if (const SMDS_VtkFace* f=dynamic_cast(element)) - // nodeIt = f->interlacedNodesElemIterator(); - // else if (const SMDS_VtkEdge* e =dynamic_cast(element)) - // nodeIt = e->interlacedNodesElemIterator(); - } + SMDS_ElemIteratorPtr nodeIt = element->interlacedNodesElemIterator(); while ( nodeIt->more() ) { SMESH_TNodeXYZ node = nodeIt->next(); xyz.push_back( node ); - nodeList.push_back(node._node); } - int i, nbNodes = (int) nodeList.size(); // central node of biquadratic is missing + int i, nbNodes = (int) xyz.size(); // central node of biquadratic is missing if ( element->GetType() == SMDSAbs_Face ) // -------------------------------------------------- { // compute face normal gp_Vec faceNorm(0,0,0); xyz.push_back( xyz.front() ); - nodeList.push_back( nodeList.front() ); for ( i = 0; i < nbNodes; ++i ) { gp_Vec edge1( xyz[i+1], xyz[i]); @@ -1129,7 +1121,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin // degenerated face: point is out if it is out of all face edges for ( i = 0; i < nbNodes; ++i ) { - SMDS_LinearEdge edge( nodeList[i], nodeList[i+1] ); + SMDS_LinearEdge edge( xyz[i]._node, xyz[i+1]._node ); if ( !IsOut( &edge, point, tol )) return false; } @@ -1216,13 +1208,28 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin // (we consider quadratic edge as being composed of two straight parts) for ( i = 1; i < nbNodes; ++i ) { - gp_Vec edge( xyz[i-1], xyz[i]); - gp_Vec n1p ( xyz[i-1], point); - double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude(); - if ( dist > tol ) + gp_Vec edge( xyz[i-1], xyz[i] ); + gp_Vec n1p ( xyz[i-1], point ); + // double dist = ( edge ^ n1p ).Magnitude() / edge.Magnitude(); + // if ( dist > tol ) + // continue; + // gp_Vec n2p( xyz[i], point ); + // if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol ) + // continue; + double u = ( edge * n1p ) / edge.SquareMagnitude(); // param [0,1] on the edge + if ( u < 0. ) { + if ( n1p.SquareMagnitude() < tol * tol ) + return false; continue; - gp_Vec n2p( xyz[i], point ); - if ( fabs( edge.Magnitude() - n1p.Magnitude() - n2p.Magnitude()) > tol ) + } + if ( u > 1. ) { + if ( point.SquareDistance( xyz[i] ) < tol * tol ) + return false; + continue; + } + gp_XYZ proj = ( 1. - u ) * xyz[i-1] + u * xyz[i]; // projection of the point on the edge + double dist2 = point.SquareDistance( proj ); + if ( dist2 > tol * tol ) continue; return false; // point is ON this part } @@ -1231,7 +1238,7 @@ bool SMESH_MeshAlgos::IsOut( const SMDS_MeshElement* element, const gp_Pnt& poin // Node or 0D element ------------------------------------------------------------------------- { gp_Vec n2p ( xyz[0], point ); - return n2p.Magnitude() <= tol; + return n2p.SquareMagnitude() <= tol * tol; } return true; } @@ -1650,9 +1657,10 @@ SMESH_NodeSearcher* SMESH_MeshAlgos::GetNodeSearcher(SMDS_Mesh& mesh) */ //======================================================================= -SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh) +SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh, + double tolerance) { - return new SMESH_ElementSearcherImpl( mesh ); + return new SMESH_ElementSearcherImpl( mesh, tolerance ); } //======================================================================= @@ -1662,7 +1670,8 @@ SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh) //======================================================================= SMESH_ElementSearcher* SMESH_MeshAlgos::GetElementSearcher(SMDS_Mesh& mesh, - SMDS_ElemIteratorPtr elemIt) + SMDS_ElemIteratorPtr elemIt, + double tolerance) { - return new SMESH_ElementSearcherImpl( mesh, elemIt ); + return new SMESH_ElementSearcherImpl( mesh, tolerance, elemIt ); } diff --git a/src/SMESHUtils/SMESH_MeshAlgos.hxx b/src/SMESHUtils/SMESH_MeshAlgos.hxx index fe5074eb5..9b860a6ab 100644 --- a/src/SMESHUtils/SMESH_MeshAlgos.hxx +++ b/src/SMESHUtils/SMESH_MeshAlgos.hxx @@ -156,10 +156,45 @@ namespace SMESH_MeshAlgos * \brief Return SMESH_ElementSearcher. The caller is responsible for deleting it */ SMESHUtils_EXPORT - SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh ); + SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh, + double tolerance=-1.); SMESHUtils_EXPORT SMESH_ElementSearcher* GetElementSearcher( SMDS_Mesh& mesh, - SMDS_ElemIteratorPtr elemIt ); -} + SMDS_ElemIteratorPtr elemIt, + double tolerance=-1. ); + + + + typedef std::vector TFreeBorder; + typedef std::vector TFreeBorderVec; + struct TFreeBorderPart + { + int _border; // border index within a TFreeBorderVec + int _node1; // node index within the border-th TFreeBorder + int _node2; + int _nodeLast; + }; + typedef std::vector TCoincidentGroup; + typedef std::vector TCoincidentGroupVec; + struct CoincidentFreeBorders + { + TFreeBorderVec _borders; // nodes of all free borders + TCoincidentGroupVec _coincidentGroups; // groups of coincident parts of borders + }; + + /*! + * Returns TFreeBorder's coincident within the given tolerance. + * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent + * to free borders being compared is used. + * + * (Implemented in ./SMESH_FreeBorders.cxx) + */ + SMESHUtils_EXPORT + void FindCoincidentFreeBorders(SMDS_Mesh& mesh, + double tolerance, + CoincidentFreeBorders & foundFreeBordes); + + +} // SMESH_MeshAlgos #endif diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 8b51e5b8e..bb9106fe6 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -2414,6 +2414,7 @@ void _pyMeshEditor::Process( const Handle(_pyCommand)& theCommand) "Mirror","MirrorObject","Translate","TranslateObject","Rotate","RotateObject", "FindCoincidentNodes","MergeNodes","FindEqualElements", "MergeElements","MergeEqualElements","SewFreeBorders","SewConformFreeBorders", + "FindCoincidentFreeBorders", "SewCoincidentFreeBorders", "SewBorderToSide","SewSideElements","ChangeElemNodes","GetLastCreatedNodes", "GetLastCreatedElems", "MirrorMakeMesh","MirrorObjectMakeMesh","TranslateMakeMesh","TranslateObjectMakeMesh", diff --git a/src/SMESH_I/SMESH_DumpPython.cxx b/src/SMESH_I/SMESH_DumpPython.cxx index 20fea4abc..a676b7a16 100644 --- a/src/SMESH_I/SMESH_DumpPython.cxx +++ b/src/SMESH_I/SMESH_DumpPython.cxx @@ -547,6 +547,39 @@ namespace SMESH DumpArray( theList, *this ); return *this; } + TPythonDump& TPythonDump::operator<<(const SMESH::CoincidentFreeBorders& theCFB) + { + // dump CoincidentFreeBorders as a list of lists, each enclosed list + // contains node IDs of a group of coincident free borders where + // each consequent triple of IDs describe a free border: (n1, n2, nLast) + // For example [[1, 2, 10, 20, 21, 40], [11, 12, 15, 55, 54, 41]] describes + // two groups of coincident free borders, each group including two borders + + myStream << "["; + for ( CORBA::ULong i = 0; i < theCFB.coincidentGroups.length(); ++i ) + { + const SMESH::FreeBordersGroup& aGRP = theCFB.coincidentGroups[ i ]; + if ( i ) myStream << ","; + myStream << "["; + for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP ) + { + const SMESH::FreeBorderPart& aPART = aGRP[ iP ]; + if ( 0 <= aPART.border && aPART.border < theCFB.borders.length() ) + { + if ( iP ) myStream << ", "; + const SMESH::FreeBorder& aBRD = theCFB.borders[ aPART.border ]; + myStream << aBRD.nodeIDs[ aPART.node1 ] << ","; + myStream << aBRD.nodeIDs[ aPART.node2 ] << ","; + myStream << aBRD.nodeIDs[ aPART.nodeLast ]; + } + } + myStream << "]"; + } + myStream << "]"; + + return *this; + } + const char* TPythonDump::NotPublishedObjectName() { return theNotPublishedObjectName; diff --git a/src/SMESH_I/SMESH_MeshEditor_i.cxx b/src/SMESH_I/SMESH_MeshEditor_i.cxx index 206c73da4..34f310940 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.cxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.cxx @@ -4572,6 +4572,182 @@ static SMESH::SMESH_MeshEditor::Sew_Error convError( const::SMESH_MeshEditor::Se return SMESH::SMESH_MeshEditor::SEW_OK; } +//======================================================================= +/*! + * Returns groups of FreeBorder's coincident within the given tolerance. + * If the tolerance <= 0.0 then one tenth of an average size of elements adjacent + * to free borders being compared is used. + */ +//======================================================================= + +SMESH::CoincidentFreeBorders* +SMESH_MeshEditor_i::FindCoincidentFreeBorders(CORBA::Double tolerance) +{ + SMESH::CoincidentFreeBorders_var aCFB = new SMESH::CoincidentFreeBorders; + + SMESH_TRY; + + SMESH_MeshAlgos::CoincidentFreeBorders cfb; + SMESH_MeshAlgos::FindCoincidentFreeBorders( *getMeshDS(), tolerance, cfb ); + + // copy free borders + aCFB->borders.length( cfb._borders.size() ); + for ( size_t i = 0; i < cfb._borders.size(); ++i ) + { + SMESH_MeshAlgos::TFreeBorder& nodes = cfb._borders[i]; + SMESH::FreeBorder& aBRD = aCFB->borders[i]; + aBRD.nodeIDs.length( nodes.size() ); + for ( size_t iN = 0; iN < nodes.size(); ++iN ) + aBRD.nodeIDs[ iN ] = nodes[ iN ]->GetID(); + } + + // copy coincident parts + aCFB->coincidentGroups.length( cfb._coincidentGroups.size() ); + for ( size_t i = 0; i < cfb._coincidentGroups.size(); ++i ) + { + SMESH_MeshAlgos::TCoincidentGroup& grp = cfb._coincidentGroups[i]; + SMESH::FreeBordersGroup& aGRP = aCFB->coincidentGroups[i]; + aGRP.length( grp.size() ); + for ( size_t iP = 0; iP < grp.size(); ++iP ) + { + SMESH_MeshAlgos::TFreeBorderPart& part = grp[ iP ]; + SMESH::FreeBorderPart& aPART = aGRP[ iP ]; + aPART.border = part._border; + aPART.node1 = part._node1; + aPART.node2 = part._node2; + aPART.nodeLast = part._nodeLast; + } + } + SMESH_CATCH( SMESH::doNothing ); + + TPythonDump() << "CoincidentFreeBorders = " + << this << ".FindCoincidentFreeBorders( " << tolerance << " )"; + + return aCFB._retn(); +} + +//======================================================================= +/*! + * Sew FreeBorder's of each group + */ +//======================================================================= + +CORBA::Short SMESH_MeshEditor_i:: +SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders, + CORBA::Boolean createPolygons, + CORBA::Boolean createPolyhedra) + throw (SALOME::SALOME_Exception) +{ + CORBA::Short nbSewed = 0; + + SMESH_MeshAlgos::TFreeBorderVec groups; + SMESH_MeshAlgos::TFreeBorder borderNodes; // triples on nodes for every FreeBorderPart + + // check the input + for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i ) + { + const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ]; + for ( CORBA::ULong iP = 0; iP < aGRP.length(); ++iP ) + { + const SMESH::FreeBorderPart& aPART = aGRP[ iP ]; + if ( aPART.border < 0 || aPART.border >= freeBorders.borders.length() ) + THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::border index", SALOME::BAD_PARAM); + + const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ]; + + if ( aPART.node1 < 0 || aPART.node1 > aBRD.nodeIDs.length() ) + THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node1", SALOME::BAD_PARAM); + if ( aPART.node2 < 0 || aPART.node2 > aBRD.nodeIDs.length() ) + THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::node2", SALOME::BAD_PARAM); + if ( aPART.nodeLast < 0 || aPART.nodeLast > aBRD.nodeIDs.length() ) + THROW_SALOME_CORBA_EXCEPTION("Invalid FreeBorderPart::nodeLast", SALOME::BAD_PARAM); + + // do not keep these nodes for further sewing as nodes can be removed by the sewing + const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1 ]); + const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2 ]); + const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]); + if ( !n1) + THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node1", SALOME::BAD_PARAM); + if ( !n2 ) + THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::node2", SALOME::BAD_PARAM); + if ( !n3 ) + THROW_SALOME_CORBA_EXCEPTION("Nonexistent FreeBorderPart::nodeLast", SALOME::BAD_PARAM); + } + } + + //TIDSortedElemSet dummy; + + ::SMESH_MeshEditor::Sew_Error res, ok = ::SMESH_MeshEditor::SEW_OK; + for ( CORBA::ULong i = 0; i < freeBorders.coincidentGroups.length(); ++i ) + { + const SMESH::FreeBordersGroup& aGRP = freeBorders.coincidentGroups[ i ]; + if ( aGRP.length() < 2 ) + continue; + + //int n1bord2, n2bord2; + + bool groupSewed = false; + for ( CORBA::ULong iP = 1; iP < aGRP.length(); ++iP ) + { + const SMESH::FreeBorderPart& aPART_0 = aGRP[ 0 ]; + const SMESH::FreeBorder& aBRD_0 = freeBorders.borders[ aPART_0.border ]; + + const SMDS_MeshNode* n0 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.node1 ]); + const SMDS_MeshNode* n1 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.node2 ]); + const SMDS_MeshNode* n2 = getMeshDS()->FindNode( aBRD_0.nodeIDs[ aPART_0.nodeLast ]); + + const SMESH::FreeBorderPart& aPART = aGRP[ iP ]; + const SMESH::FreeBorder& aBRD = freeBorders.borders[ aPART.border ]; + + const SMDS_MeshNode* n3 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node1 ]); + const SMDS_MeshNode* n4 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.node2 ]); + const SMDS_MeshNode* n5 = getMeshDS()->FindNode( aBRD.nodeIDs[ aPART.nodeLast ]); + + if ( !n0 || !n1 || !n2 || !n3 || !n4 || !n5 ) + continue; + + // if ( iP == 1 ) + // { + // n1bord2 = aBRD.nodeIDs[ aPART.node1 ]; + // n2bord2 = aBRD.nodeIDs[ aPART.node2 ]; + // } + // else if ( !SMESH_MeshAlgos::FindFaceInSet( n0, n1, dummy, dummy )) + // { + // // a face including n0 and n1 was split; + // // find a new face starting at n0 in order to get a new n1 + // const SMDS_MeshNode* n1test = getMeshDS()->FindNode( n1bord2 ); + // const SMDS_MeshNode* n2test = getMeshDS()->FindNode( n2bord2 ); + // if ( n1test && SMESH_MeshAlgos::FindFaceInSet( n0, n1test, dummy, dummy )) + // n1 = n1test; + // else if ( n2test && SMESH_MeshAlgos::FindFaceInSet( n0, n2test, dummy, dummy )) + // n1 = n2test; + // // else continue; ?????? + // } + + if ( iP > 1 ) + { + n1 = n2; // at border-to-side sewing only last side node (n1) is needed + n2 = 0; // and n2 is not used + } + + // 1st border moves to 2nd + res = getEditor().SewFreeBorder( n3, n4, n5 ,// 1st + n0 ,n1 ,n2 ,// 2nd + /*2ndIsFreeBorder=*/ iP == 1, + createPolygons, createPolyhedra); + groupSewed = ( res == ok ); + } + nbSewed += groupSewed; + } + + TPythonDump() << "nbSewed = " << this << ".SewCoincidentFreeBorders( " + << freeBorders << ", " + << createPolygons << ", " + << createPolyhedra << " )"; + + return nbSewed; +} + //======================================================================= //function : SewFreeBorders //purpose : @@ -4621,14 +4797,14 @@ SMESH_MeshEditor_i::SewFreeBorders(CORBA::Long FirstNodeID1, SMESH::SMESH_MeshEditor::Sew_Error error = convError( getEditor().SewFreeBorder (aBorderFirstNode, - aBorderSecondNode, - aBorderLastNode, - aSide2FirstNode, - aSide2SecondNode, - aSide2ThirdNode, - true, - CreatePolygons, - CreatePolyedrs) ); + aBorderSecondNode, + aBorderLastNode, + aSide2FirstNode, + aSide2SecondNode, + aSide2ThirdNode, + true, + CreatePolygons, + CreatePolyedrs) ); declareMeshModified( /*isReComputeSafe=*/false ); @@ -4681,13 +4857,13 @@ SMESH_MeshEditor_i::SewConformFreeBorders(CORBA::Long FirstNodeID1, SMESH::SMESH_MeshEditor::Sew_Error error = convError( getEditor().SewFreeBorder (aBorderFirstNode, - aBorderSecondNode, - aBorderLastNode, - aSide2FirstNode, - aSide2SecondNode, - aSide2ThirdNode, - true, - false, false) ); + aBorderSecondNode, + aBorderLastNode, + aSide2FirstNode, + aSide2SecondNode, + aSide2ThirdNode, + true, + false, false) ); declareMeshModified( /*isReComputeSafe=*/false ); return error; @@ -4743,14 +4919,14 @@ SMESH_MeshEditor_i::SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder, SMESH::SMESH_MeshEditor::Sew_Error error = convError( getEditor().SewFreeBorder (aBorderFirstNode, - aBorderSecondNode, - aBorderLastNode, - aSide2FirstNode, - aSide2SecondNode, - aSide2ThirdNode, - false, - CreatePolygons, - CreatePolyedrs) ); + aBorderSecondNode, + aBorderLastNode, + aSide2FirstNode, + aSide2SecondNode, + aSide2ThirdNode, + false, + CreatePolygons, + CreatePolyedrs) ); declareMeshModified( /*isReComputeSafe=*/false ); return error; diff --git a/src/SMESH_I/SMESH_MeshEditor_i.hxx b/src/SMESH_I/SMESH_MeshEditor_i.hxx index 97fe0ba88..3c36508b8 100644 --- a/src/SMESH_I/SMESH_MeshEditor_i.hxx +++ b/src/SMESH_I/SMESH_MeshEditor_i.hxx @@ -538,6 +538,12 @@ public: CORBA::Short GetPointState(CORBA::Double x, CORBA::Double y, CORBA::Double z) throw (SALOME::SALOME_Exception); + SMESH::CoincidentFreeBorders* FindCoincidentFreeBorders(CORBA::Double tolerance); + CORBA::Short SewCoincidentFreeBorders(const SMESH::CoincidentFreeBorders& freeBorders, + CORBA::Boolean createPolygons, + CORBA::Boolean createPolyedrs) + throw (SALOME::SALOME_Exception); + SMESH::SMESH_MeshEditor::Sew_Error SewFreeBorders(CORBA::Long FirstNodeID1, CORBA::Long SecondNodeID1, @@ -546,15 +552,13 @@ public: CORBA::Long SecondNodeID2, CORBA::Long LastNodeID2, CORBA::Boolean CreatePolygons, - CORBA::Boolean CreatePolyedrs) - throw (SALOME::SALOME_Exception); + CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception); SMESH::SMESH_MeshEditor::Sew_Error SewConformFreeBorders(CORBA::Long FirstNodeID1, CORBA::Long SecondNodeID1, CORBA::Long LastNodeID1, CORBA::Long FirstNodeID2, - CORBA::Long SecondNodeID2) - throw (SALOME::SALOME_Exception); + CORBA::Long SecondNodeID2) throw (SALOME::SALOME_Exception); SMESH::SMESH_MeshEditor::Sew_Error SewBorderToSide(CORBA::Long FirstNodeIDOnFreeBorder, CORBA::Long SecondNodeIDOnFreeBorder, @@ -562,16 +566,14 @@ public: CORBA::Long FirstNodeIDOnSide, CORBA::Long LastNodeIDOnSide, CORBA::Boolean CreatePolygons, - CORBA::Boolean CreatePolyedrs) - throw (SALOME::SALOME_Exception); + CORBA::Boolean CreatePolyedrs) throw (SALOME::SALOME_Exception); SMESH::SMESH_MeshEditor::Sew_Error SewSideElements(const SMESH::long_array& IDsOfSide1Elements, const SMESH::long_array& IDsOfSide2Elements, CORBA::Long NodeID1OfSide1ToMerge, CORBA::Long NodeID1OfSide2ToMerge, CORBA::Long NodeID2OfSide1ToMerge, - CORBA::Long NodeID2OfSide2ToMerge) - throw (SALOME::SALOME_Exception); + CORBA::Long NodeID2OfSide2ToMerge) throw (SALOME::SALOME_Exception); /*! * Set new nodes for given element. diff --git a/src/SMESH_I/SMESH_PythonDump.hxx b/src/SMESH_I/SMESH_PythonDump.hxx index 4d4f6b728..696376297 100644 --- a/src/SMESH_I/SMESH_PythonDump.hxx +++ b/src/SMESH_I/SMESH_PythonDump.hxx @@ -27,6 +27,7 @@ #include #include CORBA_SERVER_HEADER(SMESH_Mesh) +#include CORBA_SERVER_HEADER(SMESH_MeshEditor) #include CORBA_SERVER_HEADER(GEOM_Gen) #include CORBA_SERVER_HEADER(SALOMEDS) @@ -229,6 +230,9 @@ namespace SMESH TPythonDump& operator<<(const SMESH::ListOfIDSources& theList); + TPythonDump& + operator<<(const SMESH::CoincidentFreeBorders& theCFB); + static const char* SMESHGenName() { return "smeshgen"; } static const char* MeshEditorName() { return "mesh_editor"; } static const char* NotPublishedObjectName(); diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index 1d6de9c75..8f49d4937 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -4519,6 +4519,52 @@ class Mesh: def MergeEqualElements(self): self.editor.MergeEqualElements() + ## Returns groups of FreeBorder's coincident within the given tolerance. + # @param tolerance the tolerance. If the tolerance <= 0.0 then one tenth of an average + # size of elements adjacent to free borders being compared is used. + # @return SMESH.CoincidentFreeBorders structure + # @ingroup l2_modif_trsf + def FindCoincidentFreeBorders (self, tolerance=0.): + return self.editor.FindCoincidentFreeBorders( tolerance ) + + ## Sew FreeBorder's of each group + # @param freeBorders either a SMESH.CoincidentFreeBorders structure or a list of lists + # where each enclosed list contains node IDs of a group of coincident free + # borders such that each consequent triple of IDs within a group describes + # a free border in a usual way: n1, n2, nLast - i.e. 1st node, 2nd node and + # last node of a border. + # For example [[1, 2, 10, 20, 21, 40], [11, 12, 15, 55, 54, 41]] describes two + # groups of coincident free borders, each group including two borders. + # @param createPolygons if @c True faces adjacent to free borders are converted to + # polygons if a node of opposite border falls on a face edge, else such + # faces are split into several ones. + # @param createPolyhedra if @c True volumes adjacent to free borders are converted to + # polyhedra if a node of opposite border falls on a volume edge, else such + # volumes, if any, remain intact and the mesh becomes non-conformal. + # @return a number of successfully sewed groups + # @ingroup l2_modif_trsf + def SewCoincidentFreeBorders (self, freeBorders, createPolygons=False, createPolyhedra=False): + if freeBorders and isinstance( freeBorders, list ): + # construct SMESH.CoincidentFreeBorders + if isinstance( freeBorders[0], int ): + freeBorders = [freeBorders] + borders = [] + coincidentGroups = [] + for nodeList in freeBorders: + if not nodeList or len( nodeList ) % 3: + raise ValueError, "Wrong number of nodes in this group: %s" % nodeList + group = [] + while nodeList: + group.append ( SMESH.FreeBorderPart( len(borders), 0, 1, 2 )) + borders.append( SMESH.FreeBorder( nodeList[:3] )) + nodeList = nodeList[3:] + pass + coincidentGroups.append( group ) + pass + freeBorders = SMESH.CoincidentFreeBorders( borders, coincidentGroups ) + + return self.editor.SewCoincidentFreeBorders( freeBorders, createPolygons, createPolyhedra ) + ## Sews free borders # @return SMESH::Sew_Error # @ingroup l2_modif_trsf