From a02233c2455e2c732e1823208565d3b674b07e15 Mon Sep 17 00:00:00 2001 From: adam Date: Mon, 17 May 2010 07:32:12 +0000 Subject: [PATCH] Local sizes implementation --- adm_local/cmake_files/FindNETGEN.cmake | 75 +++-- idl/NETGENPlugin_Algorithm.idl | 6 + src/GUI/Makefile.am | 5 +- src/GUI/NETGENPluginGUI_HypothesisCreator.cxx | 269 +++++++++++++++++- src/GUI/NETGENPluginGUI_HypothesisCreator.h | 15 + src/GUI/NETGENPlugin_msg_en.ts | 28 ++ src/NETGEN/netgen_copy_include_for_salome | 20 +- src/NETGENPlugin/Makefile.am | 3 +- src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx | 78 ++++- src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx | 10 + .../NETGENPlugin_Hypothesis_i.cxx | 43 +++ .../NETGENPlugin_Hypothesis_i.hxx | 5 + src/NETGENPlugin/NETGENPlugin_Mesher.cxx | 129 +++++++++ 13 files changed, 656 insertions(+), 30 deletions(-) diff --git a/adm_local/cmake_files/FindNETGEN.cmake b/adm_local/cmake_files/FindNETGEN.cmake index 4855340..a1379ac 100644 --- a/adm_local/cmake_files/FindNETGEN.cmake +++ b/adm_local/cmake_files/FindNETGEN.cmake @@ -23,27 +23,60 @@ SET(NETGEN_INCLUDES) SET(NETGEN_INCLUDES ${NETGEN_INCLUDES} -I${NETGEN_INCLUDES_DIR}) SET(NETGEN_INCLUDES ${NETGEN_INCLUDES} -DNO_PARALLEL_THREADS -DOCCGEOMETRY) -FIND_LIBRARY(NETGEN_LIB_csg csg PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_gen gen PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_geom2d geom2d PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_gprim gprim PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_la la PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_mesh mesh PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_nginterface nginterface PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_occ occ PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_opti opti PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -FIND_LIBRARY(NETGEN_LIB_stlgeom stlgeom PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) +FIND_LIBRARY(NETGEN_LIB_nglib nglib PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) -SET(NETGEN_LIBS) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_csg}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_gen}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_geom2d}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_gprim}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_la}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_mesh}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_nginterface}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_occ}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_opti}) -SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_stlgeom}) +IF(NETGEN_LIB_nglib) + SET(NETGEN_NEW ON) + SET(NETGEN_INCLUDES ${NETGEN_INCLUDES} -I${NETGENHOME}/share/netgen/include -DNETGEN_NEW) +ELSE(NETGEN_LIB_nglib) + SET(NETGEN_NEW OFF) +ENDIF(NETGEN_LIB_nglib) + +IF(NETGEN_NEW) + SET(NETGEN_LIBS) + IF(WINDOWS) + FIND_LIBRARY(NETGEN_LIB_csg csg PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_gen gen PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_geom2d geom2d PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_gprim gprim PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_interface interface PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_la la PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_mesh mesh PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_occ occ PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_stl stl PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_csg}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_gen}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_geom2d}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_gprim}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_interface}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_la}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_mesh}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_occ}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_stl}) + ENDIF(WINDOWS) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_nglib}) +ELSE(NETGEN_NEW) + FIND_LIBRARY(NETGEN_LIB_csg csg PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_gen gen PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_geom2d geom2d PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_gprim gprim PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_la la PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_mesh mesh PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_nginterface nginterface PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_occ occ PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_opti opti PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + FIND_LIBRARY(NETGEN_LIB_stlgeom stlgeom PATHS ${NETGENHOME}/lib ${NETGENHOME}/lib/LINUX) + SET(NETGEN_LIBS) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_csg}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_gen}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_geom2d}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_gprim}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_la}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_mesh}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_nginterface}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_occ}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_opti}) + SET(NETGEN_LIBS ${NETGEN_LIBS} ${NETGEN_LIB_stlgeom}) +ENDIF(NETGEN_NEW) SET(CMAKE_BUILD 1) diff --git a/idl/NETGENPlugin_Algorithm.idl b/idl/NETGENPlugin_Algorithm.idl index fa7a5cc..365b046 100644 --- a/idl/NETGENPlugin_Algorithm.idl +++ b/idl/NETGENPlugin_Algorithm.idl @@ -35,6 +35,7 @@ */ module NETGENPlugin { + typedef sequence string_array; /*! * NETGENPlugin_NETGEN_3D: interface of "Tetrahedron (Netgen)" algorithm */ @@ -90,6 +91,11 @@ module NETGENPlugin void SetNbSegPerRadius(in double value); double GetNbSegPerRadius(); + + void SetLocalSizeOnEntry(in string entry, in double localSize); + double GetLocalSizeOnEntry(in string entry); + string_array GetLocalSizeEntries(); + void UnsetLocalSizeOnEntry(in string entry); }; /*! diff --git a/src/GUI/Makefile.am b/src/GUI/Makefile.am index 4f85c75..b2cbac7 100644 --- a/src/GUI/Makefile.am +++ b/src/GUI/Makefile.am @@ -49,6 +49,7 @@ nodist_libNETGENPluginGUI_la_SOURCES= \ # additionnal information to compil and link file libNETGENPluginGUI_la_CPPFLAGS = \ + $(NETGEN_INCLUDES) \ $(QT_INCLUDES) \ $(CAS_CPPFLAGS) \ $(PYTHON_INCLUDES) \ @@ -66,8 +67,8 @@ libNETGENPluginGUI_la_CPPFLAGS = \ libNETGENPluginGUI_la_LDFLAGS = \ ../NETGENPlugin/libNETGENEngine.la \ ${QT_MT_LIBS} \ - ${GUI_LDFLAGS} -lSalomeApp -lqtx -lsuit \ - ${SMESH_LDFLAGS} -lSMESH \ + ${GUI_LDFLAGS} -lSalomeApp -lqtx -lsuit -lSalomeObject -lLightApp \ + ${SMESH_LDFLAGS} -lSMESH -lGeomSelectionTools \ $(CAS_KERNEL) # resources files diff --git a/src/GUI/NETGENPluginGUI_HypothesisCreator.cxx b/src/GUI/NETGENPluginGUI_HypothesisCreator.cxx index 13aea92..930a5d3 100644 --- a/src/GUI/NETGENPluginGUI_HypothesisCreator.cxx +++ b/src/GUI/NETGENPluginGUI_HypothesisCreator.cxx @@ -32,6 +32,7 @@ #include #include #include +#include #include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) @@ -39,6 +40,8 @@ #include #include +#include +#include #include #include @@ -48,6 +51,9 @@ #include #include #include +#include +#include +#include enum Fineness { @@ -59,10 +65,35 @@ UserDefined }; +enum { + STD_TAB = 0, + LSZ_TAB +}; + +enum { + LSZ_ENTRY_COLUMN = 0, + LSZ_NAME_COLUMN, + LSZ_LOCALSIZE_COLUMN, + LSZ_NB_COLUMNS +}; + +enum { + LSZ_BTNS = 0, + LSZ_VERTEX_BTN, + LSZ_EDGE_BTN, +#ifdef NETGEN_NEW + LSZ_FACE_BTN, +#endif + LSZ_SEPARATOR2, + LSZ_REMOVE_BTN +}; + NETGENPluginGUI_HypothesisCreator::NETGENPluginGUI_HypothesisCreator( const QString& theHypType ) : SMESHGUI_GenericHypothesisCreator( theHypType ), myIs2D(false) { + myGeomSelectionTools = NULL; + myLocalSizeMap.clear(); } NETGENPluginGUI_HypothesisCreator::~NETGENPluginGUI_HypothesisCreator() @@ -92,8 +123,12 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame() lay->setMargin( 5 ); lay->setSpacing( 0 ); - QGroupBox* GroupC1 = new QGroupBox( tr( "SMESH_ARGUMENTS" ), fr ); - lay->addWidget( GroupC1 ); + QTabWidget* tab = new QTabWidget( fr ); + tab->setTabShape( QTabWidget::Rounded ); + tab->setTabPosition( QTabWidget::North ); + lay->addWidget( tab ); + QWidget* GroupC1 = new QWidget(); + tab->insertTab( STD_TAB, GroupC1, tr( "SMESH_ARGUMENTS" ) ); QGridLayout* aGroupLayout = new QGridLayout( GroupC1 ); aGroupLayout->setSpacing( 6 ); @@ -161,7 +196,49 @@ QFrame* NETGENPluginGUI_HypothesisCreator::buildFrame() row++; connect( myFineness, SIGNAL( activated( int ) ), this, SLOT( onFinenessChanged() ) ); + + QWidget* localSizeGroup = new QWidget(); + QGridLayout* localSizeLayout = new QGridLayout(localSizeGroup); + myLocalSizeTable = new QTableWidget(0, LSZ_NB_COLUMNS, localSizeGroup); + localSizeLayout->addWidget(myLocalSizeTable, 1, 0, 8, 1); + QStringList localSizeHeaders; + localSizeHeaders << tr( "LSZ_ENTRY_COLUMN" )<< tr( "LSZ_NAME_COLUMN" ) << tr( "LSZ_LOCALSIZE_COLUMN" ); + myLocalSizeTable->setHorizontalHeaderLabels(localSizeHeaders); + myLocalSizeTable->horizontalHeader()->hideSection(LSZ_ENTRY_COLUMN); + myLocalSizeTable->horizontalHeader()->setResizeMode(QHeaderView::Interactive); + myLocalSizeTable->resizeColumnToContents(LSZ_NAME_COLUMN); + myLocalSizeTable->resizeColumnToContents(LSZ_LOCALSIZE_COLUMN); + myLocalSizeTable->setAlternatingRowColors(true); + myLocalSizeTable->verticalHeader()->hide(); + + QPushButton* addVertexButton = new QPushButton(tr("NETGEN_LSZ_VERTEX"), localSizeGroup); + localSizeLayout->addWidget(addVertexButton, LSZ_VERTEX_BTN, 1, 1, 1); + QPushButton* addEdgeButton = new QPushButton(tr("NETGEN_LSZ_EDGE"), localSizeGroup); + localSizeLayout->addWidget(addEdgeButton, LSZ_EDGE_BTN, 1, 1, 1); +#ifdef NETGEN_NEW + QPushButton* addFaceButton = new QPushButton(tr("NETGEN_LSZ_FACE"), localSizeGroup); + localSizeLayout->addWidget(addFaceButton, LSZ_FACE_BTN, 1, 1, 1); +#endif + + QFrame *line2 = new QFrame(localSizeGroup); + line2->setFrameShape(QFrame::HLine); + line2->setFrameShadow(QFrame::Sunken); + localSizeLayout->addWidget(line2, LSZ_SEPARATOR2, 1, 1, 1); + + QPushButton* removeButton = new QPushButton(tr("NETGEN_LSZ_REMOVE"), localSizeGroup); + localSizeLayout->addWidget(removeButton, LSZ_REMOVE_BTN, 1, 1, 1); + + connect( addVertexButton, SIGNAL(clicked()), this, SLOT(onAddLocalSizeOnVertex())); + connect( addEdgeButton, SIGNAL(clicked()), this, SLOT(onAddLocalSizeOnEdge())); +#ifdef NETGEN_NEW + connect( addFaceButton, SIGNAL(clicked()), this, SLOT(onAddLocalSizeOnFace())); +#endif + connect( removeButton, SIGNAL(clicked()), this, SLOT(onRemoveLocalSizeOnShape())); + connect( myLocalSizeTable, SIGNAL(cellChanged(int, int)), this, SLOT(onSetLocalSize(int, int))); + + tab->insertTab(LSZ_TAB, localSizeGroup, tr("NETGEN_LOCAL_SIZE")); + return fr; } @@ -204,6 +281,26 @@ void NETGENPluginGUI_HypothesisCreator::retrieveParams() const myGrowthRate->setEnabled(isCustom); myNbSegPerEdge->setEnabled(isCustom); myNbSegPerRadius->setEnabled(isCustom); + + NETGENPluginGUI_HypothesisCreator* that = (NETGENPluginGUI_HypothesisCreator*)this; + QMapIterator i(myLocalSizeMap); + GeomSelectionTools* geomSelectionTools = that->getGeomSelectionTools(); + while (i.hasNext()) { + i.next(); + const QString entry = i.key(); + std::string shapeName = geomSelectionTools->getNameFromEntry(entry.toStdString()); + const QString localSize = i.value(); + int row = myLocalSizeTable->rowCount(); + myLocalSizeTable->setRowCount(row+1); + myLocalSizeTable->setItem(row, LSZ_ENTRY_COLUMN, new QTableWidgetItem(entry)); + myLocalSizeTable->item(row, LSZ_ENTRY_COLUMN)->setFlags(0); + myLocalSizeTable->setItem(row, LSZ_NAME_COLUMN, new QTableWidgetItem(QString::fromStdString(shapeName))); + myLocalSizeTable->item(row, LSZ_NAME_COLUMN)->setFlags(0); + myLocalSizeTable->setItem(row, LSZ_LOCALSIZE_COLUMN, new QTableWidgetItem(localSize)); + myLocalSizeTable->item(row, LSZ_LOCALSIZE_COLUMN)->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled); + } + myLocalSizeTable->resizeColumnToContents(LSZ_NAME_COLUMN); + myLocalSizeTable->resizeColumnToContents(LSZ_LOCALSIZE_COLUMN); } QString NETGENPluginGUI_HypothesisCreator::storeParams() const @@ -259,6 +356,25 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromHypo( NetgenHypothesisData h_data.myAllowQuadrangles = h_2d->GetQuadAllowed(); } + NETGENPluginGUI_HypothesisCreator* that = (NETGENPluginGUI_HypothesisCreator*)this; + NETGENPlugin::string_array_var myEntries = h->GetLocalSizeEntries(); + for ( int i=0 ; ilength() ; i++ ) + { + QString entry = myEntries[i].in(); + double val = h->GetLocalSizeOnEntry(entry.toStdString().c_str()); + std::ostringstream tmp; + tmp << val; + QString valstring = QString::fromStdString(tmp.str()); + if (myLocalSizeMap.contains(entry)) + { + if (myLocalSizeMap[entry] == "__TO_DELETE__") + { + continue; + } + } + that->myLocalSizeMap[entry] = valstring; + } + return true; } @@ -307,7 +423,24 @@ bool NETGENPluginGUI_HypothesisCreator::storeParamsToHypo( const NetgenHypothesi h->SetParameters(aVariablesList.join(":").toLatin1().constData()); h->SetParameters(aVariablesList.join(":").toLatin1().constData()); } - + + QMapIterator i(myLocalSizeMap); + while (i.hasNext()) { + i.next(); + const QString entry = i.key(); + const QString localSize = i.value(); + if (localSize == "__TO_DELETE__") + { + h->UnsetLocalSizeOnEntry(entry.toLatin1().constData()); + } + else + { + std::istringstream tmp(localSize.toLatin1().constData()); + double val; + tmp >> val; + h->SetLocalSizeOnEntry(entry.toLatin1().constData(), val); + } + } } catch(const SALOME::SALOME_Exception& ex) { @@ -337,6 +470,15 @@ bool NETGENPluginGUI_HypothesisCreator::readParamsFromWidgets( NetgenHypothesisD if ( myIs2D ) h_data.myAllowQuadrangles = myAllowQuadrangles->isChecked(); + NETGENPluginGUI_HypothesisCreator* that = (NETGENPluginGUI_HypothesisCreator*)this; + int nbRows = myLocalSizeTable->rowCount(); + for(int row=0 ; row < nbRows ; row++) + { + QString entry = myLocalSizeTable->item(row, LSZ_ENTRY_COLUMN)->text(); + QString localSize = myLocalSizeTable->item(row, LSZ_LOCALSIZE_COLUMN)->text().trimmed(); + that->myLocalSizeMap[entry] = localSize; + } + return true; } @@ -388,6 +530,127 @@ void NETGENPluginGUI_HypothesisCreator::onFinenessChanged() } } +void NETGENPluginGUI_HypothesisCreator::onAddLocalSizeOnVertex() +{ + addLocalSizeOnShape(TopAbs_VERTEX); +} + +void NETGENPluginGUI_HypothesisCreator::onAddLocalSizeOnEdge() +{ + addLocalSizeOnShape(TopAbs_EDGE); +} + +void NETGENPluginGUI_HypothesisCreator::onAddLocalSizeOnFace() +{ + addLocalSizeOnShape(TopAbs_FACE); +} + +void NETGENPluginGUI_HypothesisCreator::addLocalSizeOnShape(TopAbs_ShapeEnum typeShapeAsked) +{ + NETGENPlugin::NETGENPlugin_Hypothesis_var h = NETGENPlugin::NETGENPlugin_Hypothesis::_narrow(initParamsHypothesis()); + GeomSelectionTools* geomSelectionTools = getGeomSelectionTools(); + LightApp_SelectionMgr* mySel = geomSelectionTools->selectionMgr(); + SALOME_ListIO ListSelectedObjects; + mySel->selectedObjects(ListSelectedObjects, NULL, false ); + SALOME_ListIteratorOfListIO Object_It(ListSelectedObjects); + for (Object_It ; Object_It.More() ; Object_It.Next()) + { + Handle(SALOME_InteractiveObject) anObject = Object_It.Value(); + std::string entry, shapeName; + entry = geomSelectionTools->getEntryOfObject(anObject); + shapeName = anObject->getName(); + TopAbs_ShapeEnum shapeType; + shapeType = geomSelectionTools->entryToShapeType(entry); + if (shapeType == TopAbs_SHAPE) + { + // E.A. if shapeType == TopAbs_SHAPE, it is NOT a TopoDS_Shape !!! + continue; + } + // -- + if(shapeType != typeShapeAsked) + { + continue; + } + // -- + myLocalSizeTable->setFocus(); + QString shapeEntry; + shapeEntry = QString::fromStdString(entry); + if (myLocalSizeMap.contains(shapeEntry)) + { + if (myLocalSizeMap[shapeEntry] != "__TO_DELETE__") + { + continue; + } + } + double phySize = h->GetMaxSize(); + std::ostringstream oss; + oss << phySize; + QString localSize; + localSize = QString::fromStdString(oss.str()); + // -- + int row = myLocalSizeTable->rowCount() ; + myLocalSizeTable->setRowCount(row+1); + myLocalSizeTable->setItem(row, LSZ_ENTRY_COLUMN, new QTableWidgetItem(shapeEntry)); + myLocalSizeTable->item(row, LSZ_ENTRY_COLUMN )->setFlags(0); + myLocalSizeTable->setItem(row, LSZ_NAME_COLUMN, new QTableWidgetItem(QString::fromStdString(shapeName))); + myLocalSizeTable->item(row, LSZ_NAME_COLUMN )->setFlags(0); + myLocalSizeTable->setItem(row, LSZ_LOCALSIZE_COLUMN, new QTableWidgetItem(localSize)); + myLocalSizeTable->item(row, LSZ_LOCALSIZE_COLUMN )->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|Qt::ItemIsEnabled); + myLocalSizeTable->resizeColumnToContents(LSZ_NAME_COLUMN); + myLocalSizeTable->resizeColumnToContents(LSZ_LOCALSIZE_COLUMN); + myLocalSizeTable->clearSelection(); + myLocalSizeTable->scrollToItem( myLocalSizeTable->item( row, LSZ_LOCALSIZE_COLUMN ) ); + // -- + } +} + +void NETGENPluginGUI_HypothesisCreator::onRemoveLocalSizeOnShape() +{ + QList selectedRows; + QList selected = myLocalSizeTable->selectedItems(); + QTableWidgetItem* item; + int row; + foreach(item, selected) { + row = item->row(); + if (!selectedRows.contains(row)) + selectedRows.append( row ); + } + qSort( selectedRows ); + QListIterator it( selectedRows ); + it.toBack(); + while (it.hasPrevious()) + { + row = it.previous(); + QString entry = myLocalSizeTable->item(row,LSZ_ENTRY_COLUMN)->text(); + if (myLocalSizeMap.contains(entry)) + { + myLocalSizeMap[entry] = "__TO_DELETE__"; + } + myLocalSizeTable->removeRow(row ); + } + myLocalSizeTable->resizeColumnToContents(LSZ_NAME_COLUMN); + myLocalSizeTable->resizeColumnToContents(LSZ_LOCALSIZE_COLUMN); +} + +void NETGENPluginGUI_HypothesisCreator::onSetLocalSize(int row,int col) +{ + if (col == LSZ_LOCALSIZE_COLUMN) { + QString entry = myLocalSizeTable->item(row, LSZ_ENTRY_COLUMN)->text(); + QString localSize = myLocalSizeTable->item(row, LSZ_LOCALSIZE_COLUMN)->text().trimmed(); + myLocalSizeMap[entry] = localSize; + myLocalSizeTable->resizeColumnToContents(LSZ_LOCALSIZE_COLUMN); + } +} + +GeomSelectionTools* NETGENPluginGUI_HypothesisCreator::getGeomSelectionTools() +{ + _PTR(Study) aStudy = SMESH::GetActiveStudyDocument(); + if (myGeomSelectionTools == NULL || myGeomSelectionTools->getMyStudy() != aStudy) { + myGeomSelectionTools = new GeomSelectionTools(aStudy); + } + return myGeomSelectionTools; +} + QString NETGENPluginGUI_HypothesisCreator::caption() const { return tr( QString( "NETGEN_%1_TITLE" ).arg(myIs2D?QString("2D"):QString("3D")).toLatin1().data() ); diff --git a/src/GUI/NETGENPluginGUI_HypothesisCreator.h b/src/GUI/NETGENPluginGUI_HypothesisCreator.h index 2ea4bd1..9706cd6 100644 --- a/src/GUI/NETGENPluginGUI_HypothesisCreator.h +++ b/src/GUI/NETGENPluginGUI_HypothesisCreator.h @@ -33,10 +33,14 @@ #include +#include + class SMESHGUI_SpinBox; +class GeomSelectionTools; class QComboBox; class QCheckBox; class QLineEdit; +class QTableWidget; typedef struct { @@ -72,11 +76,18 @@ protected: protected slots: virtual void onFinenessChanged(); + virtual void onAddLocalSizeOnVertex(); + virtual void onAddLocalSizeOnEdge(); + virtual void onAddLocalSizeOnFace(); + virtual void onRemoveLocalSizeOnShape(); + virtual void onSetLocalSize(int,int); private: bool readParamsFromHypo( NetgenHypothesisData& ) const; bool readParamsFromWidgets( NetgenHypothesisData& ) const; bool storeParamsToHypo( const NetgenHypothesisData& ) const; + GeomSelectionTools* getGeomSelectionTools(); + void addLocalSizeOnShape(TopAbs_ShapeEnum); private: QLineEdit* myName; @@ -90,6 +101,10 @@ private: QCheckBox* myAllowQuadrangles; bool myIs2D; + + QTableWidget* myLocalSizeTable; + GeomSelectionTools* myGeomSelectionTools; + QMap myLocalSizeMap; }; #endif diff --git a/src/GUI/NETGENPlugin_msg_en.ts b/src/GUI/NETGENPlugin_msg_en.ts index 3aea2e3..895686c 100644 --- a/src/GUI/NETGENPlugin_msg_en.ts +++ b/src/GUI/NETGENPlugin_msg_en.ts @@ -133,5 +133,33 @@ NG_LENGTH_FROM_FACES Length from faces + + NETGEN_LOCAL_SIZE + Local sizes + + + NETGEN_LSZ_VERTEX + On Vertex + + + NETGEN_LSZ_EDGE + On Edge + + + NETGEN_LSZ_FACE + On Sub-Face + + + NETGEN_LSZ_REMOVE + Remove + + + LSZ_NAME_COLUMN + Entry + + + LSZ_LOCALSIZE_COLUMN + Value + diff --git a/src/NETGEN/netgen_copy_include_for_salome b/src/NETGEN/netgen_copy_include_for_salome index 841a48c..f54ade7 100755 --- a/src/NETGEN/netgen_copy_include_for_salome +++ b/src/NETGEN/netgen_copy_include_for_salome @@ -14,10 +14,26 @@ fi dest_dir=$install_dir/share/netgen/include mkdir -p $dest_dir > /dev/null 2>&1 -cp -af $src_dir/libsrc/occ/*.hpp $dest_dir -cp -af $src_dir/libsrc/meshing/*.hpp $dest_dir +cp -af $src_dir/libsrc/csg/*.hpp $dest_dir cp -af $src_dir/libsrc/general/*.hpp $dest_dir +cp -af $src_dir/libsrc/geom2d/*.hpp $dest_dir cp -af $src_dir/libsrc/gprim/*.hpp $dest_dir +cp -af $src_dir/libsrc/interface/*.hpp $dest_dir cp -af $src_dir/libsrc/linalg/*.hpp $dest_dir +cp -af $src_dir/libsrc/meshing/*.hpp $dest_dir +cp -af $src_dir/libsrc/stlgeom/*.hpp $dest_dir +cp -af $src_dir/libsrc/visualization/*.hpp $dest_dir + +cp -af $src_dir/libsrc/occ/*.hpp $dest_dir +cp -af $src_dir/libsrc/occ/*.hxx $dest_dir +cp -af $src_dir/libsrc/occ/*.ixx $dest_dir +cp -af $src_dir/libsrc/occ/*.jxx $dest_dir +cp -af $src_dir/libsrc/occ/*.h $dest_dir + cp -af $src_dir/libsrc/include/mystdlib.h $dest_dir cp -af $src_dir/libsrc/include/mydefs.hpp $dest_dir +# cp -af $src_dir/libsrc/include/parallel.hpp $dest_dir + +rm -f $dest_dir/ngexception.hpp +rm -f $dest_dir/paralleltop.hpp +rm -f $dest_dir/soldata.hpp diff --git a/src/NETGENPlugin/Makefile.am b/src/NETGENPlugin/Makefile.am index b43c700..b49bc5e 100644 --- a/src/NETGENPlugin/Makefile.am +++ b/src/NETGENPlugin/Makefile.am @@ -91,6 +91,7 @@ endif libNETGENEngine_la_LDFLAGS += \ ../../idl/libSalomeIDLNETGENPLUGIN.la \ $(CAS_LDPATH) -lTKernel -lTKBRep -lTKShHealing -lTKSTEP -lTKXSBase -lTKIGES -lTKMesh -lTKSTL -lTKG3d -lTKTopAlgo -lTKG2d -lTKBool -lTKGeomAlgo -lTKOffset -lTKGeomBase -lTKBO \ + -lTKMath -lTKFillet -lTKMeshVS -lTKPrim -lTKSTEPBase -lTKSTEPAttr -lTKSTEP209 -lTKXDESTEP -lTKXDEIGES -lTKXCAF -lTKLCAF -lFWOSPlugin \ $(MED_LDFLAGS) -lSalomeIDLMED \ $(SMESH_LDFLAGS) -lSMESHimpl -lSMESHEngine -lStdMeshersEngine -lStdMeshers -lSMESHDS -lSMDS -lSMESHControls \ - $(KERNEL_LDFLAGS) -lSalomeGenericObj -lSALOMELocalTrace -lOpUtil + $(KERNEL_LDFLAGS) -lSalomeGenericObj -lSalomeNS -lSALOMELocalTrace -lOpUtil diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx index b825d07..5455d1b 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx @@ -45,10 +45,12 @@ NETGENPlugin_Hypothesis::NETGENPlugin_Hypothesis (int hypId, int studyId, _nbSegPerRadius(GetDefaultNbSegPerRadius()), _fineness (GetDefaultFineness()), _secondOrder (GetDefaultSecondOrder()), - _optimize (GetDefaultOptimize()) + _optimize (GetDefaultOptimize()), + _localSize (GetDefaultLocalSize()) { _name = "NETGEN_Parameters"; _param_algo_dim = 3; + _localSize.clear(); } //============================================================================= @@ -184,6 +186,45 @@ void NETGENPlugin_Hypothesis::SetNbSegPerRadius(double theVal) } } +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::SetLocalSizeOnEntry(const std::string& entry, double localSize) +{ + if(_localSize[entry] != localSize) + { + _localSize[entry] = localSize; + NotifySubMeshesHypothesisModification(); + } +} + +//============================================================================= +/*! + * + */ +//============================================================================= +double NETGENPlugin_Hypothesis::GetLocalSizeOnEntry(const std::string& entry) +{ + TLocalSize::iterator it = _localSize.find( entry ); + if ( it != _localSize.end() ) + return it->second; + else + return -1.0; +} + +//============================================================================= +/*! + * + */ +//============================================================================= +void NETGENPlugin_Hypothesis::UnsetLocalSizeOnEntry(const std::string& entry) +{ + _localSize.erase(entry); + NotifySubMeshesHypothesisModification(); +} + //============================================================================= /*! * @@ -198,6 +239,16 @@ ostream & NETGENPlugin_Hypothesis::SaveTo(ostream & save) save << " " << (int)_secondOrder << " " << (int)_optimize; + TLocalSize::iterator it_sm = _localSize.begin(); + if (it_sm != _localSize.end()) { + save << " " << "__LOCALSIZE_BEGIN__"; + for ( ; it_sm != _localSize.end(); ++it_sm ) { + save << " " << it_sm->first + << " " << it_sm->second << "%#"; // "%#" is a mark of value end + } + save << " " << "__LOCALSIZE_END__"; + } + return save; } @@ -256,6 +307,31 @@ istream & NETGENPlugin_Hypothesis::LoadFrom(istream & load) _optimize = (bool) is; else load.clear(ios::badbit | load.rdstate()); + + std::string option_or_sm; + bool hasLocalSize = false; + + isOK = (load >> option_or_sm); + if (isOK) + if (option_or_sm == "__LOCALSIZE_BEGIN__") + hasLocalSize = true; + + std::string smEntry, smValue; + while (isOK && hasLocalSize) { + isOK = (load >> smEntry); + if (isOK) { + if (smEntry == "__LOCALSIZE_END__") + break; + isOK = (load >> smValue); + } + if (isOK) { + std::istringstream tmp(smValue); + double val; + tmp >> val; + _localSize[ smEntry ] = val; + } + } + return load; } diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx index 649548e..9d9896c 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx @@ -34,6 +34,8 @@ #include "SMESH_Hypothesis.hxx" #include "Utils_SALOME_Exception.hxx" +#include + // Parameters for work of NETGEN // @@ -78,6 +80,13 @@ public: void SetNbSegPerRadius(double theVal); double GetNbSegPerRadius() const { return _nbSegPerRadius; } + typedef std::map TLocalSize; + static TLocalSize GetDefaultLocalSize() { return TLocalSize(); } + void SetLocalSizeOnEntry(const std::string& entry, double localSize); + double GetLocalSizeOnEntry(const std::string& entry); + const TLocalSize& GetLocalSizesAndEntries() const { return _localSize; } + void UnsetLocalSizeOnEntry(const std::string& entry); + // the default values (taken from NETGEN 4.5 sources) static double GetDefaultMaxSize(); @@ -116,6 +125,7 @@ private: Fineness _fineness; bool _secondOrder; bool _optimize; + TLocalSize _localSize; }; #endif diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx index b9ac782..7fa0b68 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx @@ -272,6 +272,49 @@ CORBA::Double NETGENPlugin_Hypothesis_i::GetNbSegPerRadius() return this->GetImpl()->GetNbSegPerRadius(); } +//============================================================================= + +void NETGENPlugin_Hypothesis_i::SetLocalSizeOnEntry(const char* entry, CORBA::Double localSize) +{ + bool valueChanged = false; + valueChanged = ( this->GetImpl()->GetLocalSizeOnEntry(entry) != localSize ); + if ( valueChanged ) + this->GetImpl()->SetLocalSizeOnEntry(entry, localSize); + if ( valueChanged ) + SMESH::TPythonDump() << _this() << ".SetLocalSizeOnEntry(" << entry << ", " << localSize << ")"; +} + +//============================================================================= + +CORBA::Double NETGENPlugin_Hypothesis_i::GetLocalSizeOnEntry(const char* entry) +{ + return this->GetImpl()->GetLocalSizeOnEntry(entry); +} + +//============================================================================= + +NETGENPlugin::string_array* NETGENPlugin_Hypothesis_i::GetLocalSizeEntries() +{ + NETGENPlugin::string_array_var result = new NETGENPlugin::string_array(); + const ::NETGENPlugin_Hypothesis::TLocalSize localSizes = this->GetImpl()->GetLocalSizesAndEntries(); + result->length(localSizes.size()); + ::NETGENPlugin_Hypothesis::TLocalSize::const_iterator it = localSizes.begin(); + for (int i=0 ; it != localSizes.end() ; i++, it++) + { + string entry = (*it).first; + result[i] = CORBA::string_dup(entry.c_str()); + } + return result._retn(); +} + +//============================================================================= + +void NETGENPlugin_Hypothesis_i::UnsetLocalSizeOnEntry(const char* entry) +{ + this->GetImpl()->UnsetLocalSizeOnEntry(entry); + SMESH::TPythonDump() << _this() << ".UnsetLocalSizeOnEntry(" << entry << ")"; +} + //============================================================================= /*! * NETGENPlugin_Hypothesis_i::GetImpl diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx index 1d02796..c321122 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx @@ -76,6 +76,11 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_i: void SetNbSegPerRadius(CORBA::Double theVal); CORBA::Double GetNbSegPerRadius(); + void SetLocalSizeOnEntry(const char* entry, CORBA::Double localSize); + CORBA::Double GetLocalSizeOnEntry(const char* entry); + NETGENPlugin::string_array* GetLocalSizeEntries(); + void UnsetLocalSizeOnEntry(const char* entry); + // Get implementation ::NETGENPlugin_Hypothesis* GetImpl(); diff --git a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx index 3707a8d..76093a6 100644 --- a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -62,9 +63,13 @@ #include #include #include +#include +#include // Netgen include files +#ifndef OCCGEOMETRY #define OCCGEOMETRY +#endif #include #include //#include @@ -93,6 +98,11 @@ using namespace std; //#define DUMP_TRIANGLES //#define DUMP_TRIANGLES_SCRIPT "/tmp/trias.py" //!< debug addIntVerticesInSolids() +TopTools_IndexedMapOfShape ShapesWithLocalSize; +std::map VertexId2LocalSize; +std::map EdgeId2LocalSize; +std::map FaceId2LocalSize; + //============================================================================= /*! * @@ -109,6 +119,10 @@ NETGENPlugin_Mesher::NETGENPlugin_Mesher (SMESH_Mesh* mesh, _simpleHyp(NULL) { defaultParameters(); + ShapesWithLocalSize.Clear(); + VertexId2LocalSize.clear(); + EdgeId2LocalSize.clear(); + FaceId2LocalSize.clear(); } //================================================================================ @@ -137,6 +151,34 @@ void NETGENPlugin_Mesher::defaultParameters() mparams.quad = NETGENPlugin_Hypothesis_2D::GetDefaultQuadAllowed() ? 1 : 0; } +//============================================================================= +/*! + * + */ +//============================================================================= +void SetLocalSize(TopoDS_Shape GeomShape, double LocalSize) +{ + TopAbs_ShapeEnum GeomType = GeomShape.ShapeType(); + if (GeomType == TopAbs_COMPOUND) { + for (TopoDS_Iterator it (GeomShape); it.More(); it.Next()) { + SetLocalSize(it.Value(), LocalSize); + } + return; + } + int key; + if (! ShapesWithLocalSize.Contains(GeomShape)) + key = ShapesWithLocalSize.Add(GeomShape); + else + key = ShapesWithLocalSize.FindIndex(GeomShape); + if (GeomType == TopAbs_VERTEX) { + VertexId2LocalSize[key] = LocalSize; + } else if (GeomType == TopAbs_EDGE) { + EdgeId2LocalSize[key] = LocalSize; + } else if (GeomType == TopAbs_FACE) { + FaceId2LocalSize[key] = LocalSize; + } +} + //============================================================================= /*! * Pass parameters to NETGEN @@ -165,6 +207,34 @@ void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp) (hyp)->GetQuadAllowed() ? 1 : 0; _optimize = hyp->GetOptimize(); _simpleHyp = NULL; + + SMESH_Gen_i* smeshGen_i = SMESH_Gen_i::GetSMESHGen(); + CORBA::Object_var anObject = smeshGen_i->GetNS()->Resolve("/myStudyManager"); + SALOMEDS::StudyManager_var aStudyMgr = SALOMEDS::StudyManager::_narrow(anObject); + SALOMEDS::Study_var myStudy = aStudyMgr->GetStudyByID(hyp->GetStudyId()); + + const NETGENPlugin_Hypothesis::TLocalSize localSizes = hyp->GetLocalSizesAndEntries(); + NETGENPlugin_Hypothesis::TLocalSize::const_iterator it = localSizes.begin(); + for (it ; it != localSizes.end() ; it++) + { + std::string entry = (*it).first; + double val = (*it).second; + // -- + GEOM::GEOM_Object_var aGeomObj; + TopoDS_Shape S = TopoDS_Shape(); + SALOMEDS::SObject_var aSObj = myStudy->FindObjectID( entry.c_str() ); + SALOMEDS::GenericAttribute_var anAttr; + if (!aSObj->_is_nil() && aSObj->FindAttribute(anAttr, "AttributeIOR")) { + SALOMEDS::AttributeIOR_var anIOR = SALOMEDS::AttributeIOR::_narrow(anAttr); + CORBA::String_var aVal = anIOR->Value(); + CORBA::Object_var obj = myStudy->ConvertIORToObject(aVal); + aGeomObj = GEOM::GEOM_Object::_narrow(obj); + } + if ( !aGeomObj->_is_nil() ) + S = smeshGen_i->GeomObjectToShape( aGeomObj.in() ); + // -- + SetLocalSize(S, val); + } } } @@ -291,6 +361,8 @@ void NETGENPlugin_Mesher::PrepareOCCgeometry(netgen::OCCGeometry& occgeo, #ifdef NETGEN_NEW occgeo.face_maxh.SetSize(occgeo.fmap.Extent()); occgeo.face_maxh = netgen::mparam.maxh; + occgeo.face_maxh_modified.SetSize(occgeo.fmap.Extent()); + occgeo.face_maxh_modified = 0; #endif } @@ -1356,6 +1428,24 @@ bool NETGENPlugin_Mesher::Compute() NETGENPlugin_Internals internals( *_mesh, _shape, _isVolume ); PrepareOCCgeometry( occgeo, _shape, *_mesh, &meshedSM, &internals ); + // ------------------------- + // Local size on faces + // ------------------------- + +#ifdef NETGEN_NEW + if ( ! _simpleHyp ) + { + for(std::map::const_iterator it=FaceId2LocalSize.begin(); it!=FaceId2LocalSize.end(); it++) + { + int key = (*it).first; + double val = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + int faceID = occgeo.fmap.FindIndex(shape); + occgeo.SetFaceMaxH(faceID, val); + } + } +#endif + // ------------------------- // Generate the mesh // ------------------------- @@ -1395,6 +1485,45 @@ bool NETGENPlugin_Mesher::Compute() if (err) comment << "Error in netgen::OCCGenerateMesh() at MESHCONST_ANALYSE step"; ngLib.setMesh(( Ng_Mesh*) ngMesh ); + // -------------------------------- + // Local size on vertices and edges + // -------------------------------- + + if ( ! _simpleHyp ) + { + for(std::map::const_iterator it=EdgeId2LocalSize.begin(); it!=EdgeId2LocalSize.end(); it++) + { + int key = (*it).first; + double hi = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + const TopoDS_Edge& e = TopoDS::Edge(shape); + Standard_Real u1, u2; + Handle(Geom_Curve) curve = BRep_Tool::Curve(e, u1, u2); + GeomAdaptor_Curve AdaptCurve(curve); + double length = GCPnts_AbscissaPoint::Length(AdaptCurve, u1, u2); + int nb = length/hi; + if(nb<2) nb=2; + Standard_Real delta = (u2-u1)/nb; + for(int i=0; iValue(u); + netgen::Point3d pi(p.X(), p.Y(), p.Z()); + ngMesh->RestrictLocalH(pi, hi); + } + } + for(std::map::const_iterator it=VertexId2LocalSize.begin(); it!=VertexId2LocalSize.end(); it++) + { + int key = (*it).first; + double hi = (*it).second; + const TopoDS_Shape& shape = ShapesWithLocalSize.FindKey(key); + const TopoDS_Vertex& v = TopoDS::Vertex(shape); + gp_Pnt p = BRep_Tool::Pnt(v); + netgen::Point3d pi(p.X(), p.Y(), p.Z()); + ngMesh->RestrictLocalH(pi, hi); + } + } + // Precompute internal edges (issue 0020676) in order to // add mesh on them correctly (twice) to netgen mesh if ( !err && internals.hasInternalEdges() )