From a0911be50a2d564b295d805e4f163c04148aa5a3 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sun, 26 Mar 2023 21:15:15 +0200 Subject: [PATCH] Add complete support for Equipotential selection in the Controller. --- tramontana/src/CMakeLists.txt | 9 +- tramontana/src/Equipotential.cpp | 71 +++++- tramontana/src/EquipotentialsModel.cpp | 124 ++++++++++ tramontana/src/EquipotentialsWidget.cpp | 230 ++++++++++++++++++ tramontana/src/GraphicTramontanaEngine.cpp | 10 +- tramontana/src/SweepLine.cpp | 1 + tramontana/src/TabEquipotentials.cpp | 144 +++++++++++ tramontana/src/Tile.cpp | 6 +- tramontana/src/TramontanaEngine.cpp | 10 + tramontana/src/tramontana/Equipotential.h | 17 +- .../src/tramontana/EquipotentialsModel.h | 62 +++++ .../src/tramontana/EquipotentialsWidget.h | 163 +++++++++++++ tramontana/src/tramontana/TabEquipotentials.h | 62 +++++ tramontana/src/tramontana/TramontanaEngine.h | 5 + 14 files changed, 905 insertions(+), 9 deletions(-) create mode 100644 tramontana/src/EquipotentialsModel.cpp create mode 100644 tramontana/src/EquipotentialsWidget.cpp create mode 100644 tramontana/src/TabEquipotentials.cpp create mode 100644 tramontana/src/tramontana/EquipotentialsModel.h create mode 100644 tramontana/src/tramontana/EquipotentialsWidget.h create mode 100644 tramontana/src/tramontana/TabEquipotentials.h diff --git a/tramontana/src/CMakeLists.txt b/tramontana/src/CMakeLists.txt index abc8f8c5..b916b224 100644 --- a/tramontana/src/CMakeLists.txt +++ b/tramontana/src/CMakeLists.txt @@ -18,12 +18,19 @@ set( pyIncludes tramontana/PyTramontanaEngine.h tramontana/PyGraphicTramontanaEngine.h ) - set( mocIncludes tramontana/GraphicTramontanaEngine.h ) + set( mocIncludes tramontana/GraphicTramontanaEngine.h + tramontana/EquipotentialsModel.h + tramontana/EquipotentialsWidget.h + tramontana/TabEquipotentials.h + ) set( cpps Tile.cpp SweepLine.cpp Equipotential.cpp TramontanaEngine.cpp GraphicTramontanaEngine.cpp + EquipotentialsModel.cpp + EquipotentialsWidget.cpp + TabEquipotentials.cpp ) set( pyCpps PyTramontana.cpp PyTramontanaEngine.cpp diff --git a/tramontana/src/Equipotential.cpp b/tramontana/src/Equipotential.cpp index 8a1df31c..b2c5141e 100644 --- a/tramontana/src/Equipotential.cpp +++ b/tramontana/src/Equipotential.cpp @@ -17,6 +17,7 @@ #include +#include #include "hurricane/utilities/Path.h" #include "hurricane/DebugSession.h" #include "hurricane/UpdateSession.h" @@ -39,6 +40,32 @@ #include "tramontana/TramontanaEngine.h" +namespace { + + using Hurricane::Net; + + + class NetCompareByName { + public: + bool operator() ( const Net* lhs, const Net* rhs ) const; + }; + + + bool NetCompareByName::operator() ( const Net* lhs, const Net* rhs ) const + { + if (lhs->isFused () != rhs->isFused ()) return rhs->isFused(); + if (lhs->isAutomatic() != rhs->isAutomatic()) return rhs->isAutomatic(); + if (lhs->isGlobal () != rhs->isGlobal ()) return rhs->isGlobal(); + + if (lhs->getName().size() != rhs->getName().size()) + return lhs->getName().size() < rhs->getName().size(); + return lhs->getName() < rhs->getName(); + } + + +} // Anonymous namespace. + + namespace Tramontana { using std::cout; @@ -54,6 +81,7 @@ namespace Tramontana { using std::ostringstream; using std::setprecision; using std::vector; + using std::set; using std::make_pair; using Hurricane::dbo_ptr; using Hurricane::UpdateSession; @@ -66,6 +94,7 @@ namespace Tramontana { using Hurricane::Box; using Hurricane::Layer; using Hurricane::Entity; + using Hurricane::Net; using Hurricane::Horizontal; using Hurricane::Vertical; using Hurricane::RoutingPad; @@ -77,11 +106,20 @@ namespace Tramontana { // Class : "Tramontana::Equipotential". + const char* defaultName = "Unamed (please call consolidate())"; + + Equipotential::Equipotential ( Cell* owner ) : _owner (owner) , _boundingBox() , _components () , _childs () + , _name (defaultName) + , _type (Net::Type::UNDEFINED) + , _direction (Net::Direction::DirUndefined) + , _isExternal (false) + , _isGlobal (false) + , _isAutomatic(false) { } @@ -154,6 +192,34 @@ namespace Tramontana { } + void Equipotential::consolidate () + { + int containsFused = 0; + set nets; + for ( Component* component : getComponents() ) { + Net* net = component->getNet(); + if (net->isFused ()) containsFused = 1; + if (net->isExternal ()) _isExternal = true; + if (net->isGlobal ()) _isGlobal = true; + if (net->isAutomatic()) _isAutomatic = true; + _type = net->getType(); + _direction |= net->getDirection(); + nets.insert( component->getNet() ); + } + _name = getString( (*nets.begin())->getName() ); + _name += " [" + getString(nets.size() - containsFused); + if (containsFused) + _name += "+fused"; + _name += "] "; + _name += ((_isExternal ) ? "e" : "-"); + _name += ((_isGlobal ) ? "g" : "-"); + _name += ((_isAutomatic) ? "a" : "-"); + _name += " "; + _name += getString(_type ) + " "; + _name += getString(_direction); + } + + void Equipotential::clear () { _components.clear(); @@ -168,7 +234,9 @@ namespace Tramontana { string Equipotential::_getString () const { ostringstream os; - os << "getName() << ">"; + os << "getName() << ">"; return os.str(); } @@ -181,6 +249,7 @@ namespace Tramontana { record->add( getSlot( "_boundingBox", &_boundingBox ) ); record->add( getSlot( "_components" , &_components ) ); record->add( getSlot( "_childs" , &_childs ) ); + //record->add( getSlot( "_name" , &_name ) ); } return record; } diff --git a/tramontana/src/EquipotentialsModel.cpp b/tramontana/src/EquipotentialsModel.cpp new file mode 100644 index 00000000..b27817ab --- /dev/null +++ b/tramontana/src/EquipotentialsModel.cpp @@ -0,0 +1,124 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./EquipotentialsModel.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Name.h" +#include "hurricane/Net.h" +#include "hurricane/Cell.h" +#include "hurricane/viewer/Graphics.h" +#include "tramontana/EquipotentialsModel.h" + + +namespace Tramontana { + + using Hurricane::Graphics; + + + EquipotentialsModel::EquipotentialsModel ( QObject* parent ) + : QAbstractTableModel(parent) + , _cell (nullptr) + , _equipotentials () + { } + + + QVariant EquipotentialsModel::data ( const QModelIndex& index, int role ) const + { + static QFont nameFont = Graphics::getFixedFont ( QFont::Bold ); + static QFont valueFont = Graphics::getFixedFont ( QFont::Normal, true ); + + if (role == Qt::FontRole) { + if (index.row() == 0) return QVariant(); + switch (index.column()) { + case 0: return nameFont; + default: return valueFont; + } + return QVariant(); + } + + if (not index.isValid()) return QVariant (); + + if (role == Qt::DisplayRole) { + int row = index.row (); + return QString::fromStdString( _equipotentials[row]->getName() ); + } + return QVariant(); + } + + + QVariant EquipotentialsModel::headerData ( int section + , Qt::Orientation orientation + , int role ) const + { + if (orientation == Qt::Vertical) return QVariant(); + + static QFont headerFont = Graphics::getFixedFont( QFont::Bold, false, false, +0 ); + + if (role == Qt::FontRole ) return headerFont; + if (role != Qt::DisplayRole) return QVariant(); + + if (section == 0) return QVariant("Equipotential"); + // if (section < _equipotentials->getColumnCount()) + // return _equipotentials->getColumnName( section ); + + return QVariant(); + } + + + int EquipotentialsModel::rowCount ( const QModelIndex& parent ) const + { + return _equipotentials.size(); + } + + + int EquipotentialsModel::columnCount ( const QModelIndex& parent ) const + { + return 1; + //return (_equipotentials) ? _equipotentials->getColumnCount() : 1; + } + + + const Equipotential* EquipotentialsModel::getEqui ( int row ) + { + if (row >= (int)_equipotentials.size()) return nullptr; + return _equipotentials[ row ]; + } + + + void EquipotentialsModel::setCell ( Cell* cell ) + { + if (_cell != cell) { + emit layoutAboutToBeChanged (); + + if (_cell) _equipotentials.clear(); + _cell = cell; + + if (_cell) { + TramontanaEngine* tramontana = TramontanaEngine::get( _cell ); + if (tramontana) { + for ( Equipotential* equi : tramontana->getEquipotentials() ) + _equipotentials.push_back( equi ); + } + } + + emit layoutChanged (); + } + } + + +} // Tramontana namespace. diff --git a/tramontana/src/EquipotentialsWidget.cpp b/tramontana/src/EquipotentialsWidget.cpp new file mode 100644 index 00000000..f6ec7a57 --- /dev/null +++ b/tramontana/src/EquipotentialsWidget.cpp @@ -0,0 +1,230 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./EquipotentialsWidget.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hurricane/Commons.h" +#include "hurricane/viewer/Graphics.h" +#include "tramontana/EquipotentialsModel.h" +#include "tramontana/EquipotentialsWidget.h" + + +namespace Tramontana { + + using std::cerr; + using std::endl; + using Hurricane::Bug; + using Hurricane::Graphics; + + + EquipotentialsWidget::EquipotentialsWidget ( QWidget* parent ) + : QWidget (parent) + , _cellWidget (NULL) + , _cell (NULL) + , _baseModel (new EquipotentialsModel(this)) + , _sortModel (new QSortFilterProxyModel(this)) + , _view (new QTableView(this)) + , _rowHeight (20) + , _selecteds () + , _forceReselect(false) + { + setAttribute( Qt::WA_DeleteOnClose ); + setAttribute( Qt::WA_QuitOnClose, false ); + setContextMenuPolicy( Qt::ActionsContextMenu ); + + _rowHeight = QFontMetrics( Graphics::getFixedFont() ).height() + 4; + + _sortModel->setSourceModel ( _baseModel ); + _sortModel->setDynamicSortFilter( true ); + _sortModel->setFilterKeyColumn ( 0 ); + + _view->setShowGrid ( false ); + _view->setAlternatingRowColors( true ); + _view->setSelectionBehavior ( QAbstractItemView::SelectRows ); + _view->setSortingEnabled ( true ); + _view->setModel ( _sortModel ); + + QHeaderView* horizontalHeader = _view->horizontalHeader(); + horizontalHeader->setDefaultAlignment ( Qt::AlignHCenter ); + horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 300 : 150 ); + horizontalHeader->setStretchLastSection( true ); + + QHeaderView* verticalHeader = _view->verticalHeader(); + verticalHeader->setVisible( false ); + verticalHeader->setDefaultSectionSize( _rowHeight ); + + // verticalHeader->setStyleSheet( "QHeaderView::section {" + // "padding-bottom: 0px;" + // "padding-top: 0px;" + // "padding-left: 0px;" + // "padding-right: 1px;" + // "margin: 0px;" + // "}" + // ); + + _filterPatternLineEdit = new QLineEdit( this ); + QLabel* filterPatternLabel = new QLabel( tr("&Filter pattern:"), this ); + filterPatternLabel->setBuddy( _filterPatternLineEdit ); + + QGridLayout* gLayout = new QGridLayout(); + gLayout->addWidget( _view , 1, 0, 1, 2 ); + gLayout->addWidget( filterPatternLabel , 2, 0 ); + gLayout->addWidget( _filterPatternLineEdit, 2, 1 ); + + setLayout( gLayout ); + + QAction* fitAction = new QAction( tr("&Fit to Equi"), this ); + fitAction->setShortcut ( QKeySequence(tr("CTRL+F")) ); + fitAction->setStatusTip( tr("Fit the view to the Equipotentials's bounding box") ); + addAction( fitAction ); + + connect( _filterPatternLineEdit , SIGNAL(textChanged(const QString &)) + , this , SLOT (textFilterChanged()) ); + connect( _view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)) + , this , SLOT (updateSelecteds (const QItemSelection&,const QItemSelection&)) ); + //connect( fitAction, SIGNAL(triggered()), this, SLOT(fitToEqui()) ); + + resize( 300, 300 ); + } + + + void EquipotentialsWidget::goTo ( int delta ) + { + if ( delta == 0 ) return; + + QModelIndex newIndex = _sortModel->index( _view->currentIndex().row()+delta, 0, QModelIndex() ); + if (newIndex.isValid()) + _view->selectRow( newIndex.row() ); + } + + + void EquipotentialsWidget::updateSelecteds () + { + _forceReselect = true; + + QItemSelection dummy; + updateSelecteds( dummy, dummy ); + } + + + void EquipotentialsWidget::updateSelecteds ( const QItemSelection& , const QItemSelection& ) + { + if (_cellWidget) _cellWidget->openRefreshSession (); + + _selecteds.resetAccesses (); + + const Equipotential* equi = nullptr; + QModelIndexList iList = _view->selectionModel()->selectedRows(); + for ( int i=0 ; igetEqui( _sortModel->mapToSource(iList[i]).row() ); + if ( equi ) + _selecteds.insert( equi ); + } + + if (_forceReselect) { + _selecteds.forceInserteds(); + _forceReselect = false; + } + + SelectedEquiSet::iterator remove; + SelectedEquiSet::iterator isel = _selecteds.begin (); + while ( isel != _selecteds.end() ) { + switch ( isel->getAccesses() ) { + case 1: break; + case 64: + emit equipotentialSelect ( isel->getEqui()->getComponents() ); + break; + case 0: + emit equipotentialUnselect ( isel->getEqui()->getComponents() ); + remove = isel; + ++isel; + _selecteds.erase( remove ); + continue; + default: + cerr << Bug( "EquipotentialsWidget::updateSelecteds(): invalid code %d" + , isel->getAccesses()) << endl; + } + ++isel; + } + + if (_cellWidget) _cellWidget->closeRefreshSession (); + } + + + void EquipotentialsWidget::textFilterChanged () + { + _sortModel->setFilterRegExp( _filterPatternLineEdit->text() ); + //updateSelecteds (); + } + + + // void EquipotentialsWidget::fitToNet () + // { + // const Equipotential* equi = _baseModel->getEqui( _sortModel->mapToSource(_view->currentIndex()).row() ); + // if (equi) emit netFitted ( equi ); + // } + + + void EquipotentialsWidget::setCellWidget ( CellWidget* cw ) + { + if (_cellWidget) { + disconnect( this, 0, _cellWidget, 0 ); + } + + _cellWidget = cw; + if (_cellWidget) { + setCell( _cellWidget->getCell() ); + //connect( this, SIGNAL(netFitted(const Equi*)), _cellWidget, SLOT(fitToEqui (const Equi*)) ); + } else + setCell( nullptr ); + } + + + void EquipotentialsWidget::setCell ( Cell* cell ) + { + _cell = cell; + _view->setVisible( false ); + _view->selectionModel()->clear(); + _baseModel->setCell( cell ); + + string windowTitle = "Equis" + getString(cell); + setWindowTitle( tr(windowTitle.c_str()) ); + + QHeaderView* header = _view->horizontalHeader(); + + _view->selectRow( 0 ); + for ( int i=0 ; i<_baseModel->columnCount() ; ++i ) { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + header->setSectionResizeMode( i, QHeaderView::Interactive ); +#else + header->setResizeMode( i, QHeaderView::Interactive ); +#endif + _view->resizeColumnToContents( i ); + } + _view->setVisible( true ); + } + + +} diff --git a/tramontana/src/GraphicTramontanaEngine.cpp b/tramontana/src/GraphicTramontanaEngine.cpp index 093b7be5..05bedb8f 100644 --- a/tramontana/src/GraphicTramontanaEngine.cpp +++ b/tramontana/src/GraphicTramontanaEngine.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -100,7 +101,6 @@ namespace Tramontana { fontScale = -5; halfHeight = 9; halfWidth = 39; - } painter.setPen ( pen ); @@ -188,6 +188,14 @@ namespace Tramontana { , "Run the extractor" , std::bind(&GraphicTramontanaEngine::_extract,this) ); + + ControllerWidget* controller = viewer->getControllerWidget(); + if (controller) { + TabEquipotentials* tabEqui = new TabEquipotentials (); + tabEqui->setObjectName( "controller.tabEquipotentials" ); + tabEqui->setCellWidget( viewer->getCellWidget() ); + controller->insertTabAfter( "controller.tabNetlist", tabEqui, "Equipotentials" ); + } } diff --git a/tramontana/src/SweepLine.cpp b/tramontana/src/SweepLine.cpp index 8ee8ba09..45011625 100644 --- a/tramontana/src/SweepLine.cpp +++ b/tramontana/src/SweepLine.cpp @@ -133,6 +133,7 @@ namespace Tramontana { void SweepLine::mergeEquipotentials () { + cerr << "Tramontana::mergeEquipotentials()" << endl; Tile::timeTick(); for ( Tile* tile : Tile::getAllTiles() ) { tile->getRoot( Tile::MergeEqui ); diff --git a/tramontana/src/TabEquipotentials.cpp b/tramontana/src/TabEquipotentials.cpp new file mode 100644 index 00000000..78829b4f --- /dev/null +++ b/tramontana/src/TabEquipotentials.cpp @@ -0,0 +1,144 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./TabEquipotentials.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include +#include +#include "tramontana/TabEquipotentials.h" + + +namespace Tramontana { + + using Hurricane::Graphics; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::TabEquipotentials". + + + TabEquipotentials::TabEquipotentials ( QWidget* parent ) + : ControllerTab (parent) + , _browser (new EquipotentialsWidget()) + , _syncEquipotentials (new QCheckBox()) + , _syncSelection (new QCheckBox()) + , _cwCumulativeSelection(false) + { + _browser->setObjectName ( "controller.tabEquipotentials.browser" ); + + QVBoxLayout* wLayout = new QVBoxLayout (); + wLayout->setContentsMargins( 10, 0, 10, 0 ); + wLayout->setSpacing( 0 ); + + _syncEquipotentials->setText ( tr("Sync Equipotentials") ); + _syncEquipotentials->setChecked( false ); + _syncEquipotentials->setFont ( Graphics::getFixedFont(QFont::Bold,false,false) ); + connect( _syncEquipotentials, SIGNAL(toggled(bool)), this, SLOT(setSyncEquipotentials(bool)) ); + + _syncSelection->setText ( tr("Sync Selection") ); + _syncSelection->setChecked( false ); + _syncSelection->setFont ( Graphics::getFixedFont(QFont::Bold,false,false) ); + connect( _syncSelection, SIGNAL(toggled(bool)), this, SLOT(setSyncSelection(bool)) ); + + QHBoxLayout* commands = new QHBoxLayout (); + commands->setContentsMargins( 0, 0, 0, 0 ); + commands->addStretch(); + commands->addWidget ( _syncEquipotentials ); + commands->addStretch(); + commands->addWidget ( _syncSelection ); + commands->addStretch(); + wLayout->addLayout ( commands ); + + QFrame* separator = new QFrame (); + separator->setFrameShape ( QFrame::HLine ); + separator->setFrameShadow( QFrame::Sunken ); + wLayout->addWidget( separator ); + wLayout->addWidget( _browser ); + + setLayout( wLayout ); + } + + + void TabEquipotentials::setSyncEquipotentials ( bool state ) + { + if (state and getCellWidget()) { + _browser->setCell( getCellWidget()->getCell() ); + } else { + _browser->setCell( nullptr ); + } + } + + + void TabEquipotentials::setSyncSelection ( bool state ) + { + if (state and getCellWidget() and _syncEquipotentials->isChecked()) { + _cwCumulativeSelection = getCellWidget()->cumulativeSelection(); + if (not _cwCumulativeSelection) { + getCellWidget()->openRefreshSession (); + getCellWidget()->unselectAll (); + getCellWidget()->closeRefreshSession (); + } + getCellWidget()->setShowSelection( true ); + connect( _browser, SIGNAL(equipotentialSelect (const ComponentSet&)), getCellWidget(), SLOT(selectSet (const ComponentSet&)) ); + connect( _browser, SIGNAL(equipotentialUnselect(const ComponentSet&)), getCellWidget(), SLOT(unselectSet(const ComponentSet&)) ); + _browser->updateSelecteds(); + } else { + getCellWidget()->setShowSelection( false ); + getCellWidget()->setCumulativeSelection( _cwCumulativeSelection ); + _browser->disconnect( getCellWidget(), SLOT(selectSet (const ComponentSet&)) ); + _browser->disconnect( getCellWidget(), SLOT(unselectSet(const ComponentSet&)) ); + } + } + + + void TabEquipotentials::setCell ( Cell* cell ) + { + setSyncEquipotentials( _syncEquipotentials->isChecked() ); + } + + + void TabEquipotentials::setCellWidget ( CellWidget* cellWidget ) + { + if (getCellWidget() != cellWidget) { + ControllerTab::setCellWidget( cellWidget ); + _browser->setCellWidget( cellWidget ); + if (getCellWidget()) { + connect( getCellWidget(), SIGNAL(cellChanged(Cell*)), this, SLOT(setCell(Cell*)) ); + } + setSyncEquipotentials( _syncEquipotentials->isChecked() ); + } + } + + + void TabEquipotentials::cellPreModificate () + { + _browser->setCell( nullptr ); + } + + + void TabEquipotentials::cellPostModificate () + { + setSyncEquipotentials( _syncEquipotentials->isChecked() ); + } + + + + +} diff --git a/tramontana/src/Tile.cpp b/tramontana/src/Tile.cpp index e28e8725..4cf692e6 100644 --- a/tramontana/src/Tile.cpp +++ b/tramontana/src/Tile.cpp @@ -157,15 +157,17 @@ namespace Tramontana { if (flags & MergeEqui) { Equipotential* rootEqui = root->getEquipotential(); - if (not rootEqui) + if (not rootEqui) { rootEqui = root->newEquipotential(); + } Tile* current = this; while ( current ) { if (current->isUpToDate()) break; if (current->getEquipotential()) { - if (current->getEquipotential() != rootEqui) + if (current->getEquipotential() != rootEqui) { rootEqui->merge( current->getEquipotential() ); + } } else { rootEqui->add( current->getOccurrence() ); } diff --git a/tramontana/src/TramontanaEngine.cpp b/tramontana/src/TramontanaEngine.cpp index 629ec10c..852f8d62 100644 --- a/tramontana/src/TramontanaEngine.cpp +++ b/tramontana/src/TramontanaEngine.cpp @@ -148,6 +148,7 @@ namespace Tramontana { cerr << "TramontanaEngine::extract() called on " << getCell() << endl; SweepLine sweepLine ( this ); sweepLine.run(); + consolidate(); showEquipotentials(); } @@ -163,6 +164,15 @@ namespace Tramontana { } } + + void TramontanaEngine::consolidate () + { + cerr << "Tramontana::consolidate()" << endl; + for ( Equipotential* equi : _equipotentials ) + equi->consolidate(); + } + + void TramontanaEngine::add ( Equipotential* equi ) { _equipotentials.insert( equi ); diff --git a/tramontana/src/tramontana/Equipotential.h b/tramontana/src/tramontana/Equipotential.h index 672fc866..57c95500 100644 --- a/tramontana/src/tramontana/Equipotential.h +++ b/tramontana/src/tramontana/Equipotential.h @@ -38,6 +38,7 @@ namespace Tramontana { using Hurricane::Net; using Hurricane::Cell; using Hurricane::Component; + using Hurricane::ComponentSet; using Hurricane::Occurrence; @@ -47,16 +48,17 @@ namespace Tramontana { class Equipotential : public Entity { public: typedef Entity Super; - typedef std::set ComponentSet; public: static Equipotential* create ( Cell* ); inline bool isEmpty () const; virtual Cell* getCell () const; virtual Box getBoundingBox () const; + inline std::string getName () const; inline bool hasComponent ( Component* ) const; void add ( Component* ); void add ( Occurrence ); void merge ( Equipotential* ); + void consolidate (); void clear (); inline const ComponentSet& getComponents () const; inline const std::vector& getChilds () const; @@ -77,13 +79,20 @@ namespace Tramontana { Box _boundingBox; ComponentSet _components; std::vector _childs; + std::string _name; + Net::Type _type; + Net::Direction _direction; + bool _isExternal; + bool _isGlobal; + bool _isAutomatic; }; - inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } - inline const Equipotential::ComponentSet& Equipotential::getComponents () const { return _components; } - inline const std::vector& Equipotential::getChilds () const { return _childs; } + inline bool Equipotential::isEmpty () const { return _components.empty() and _childs.empty(); } + inline const ComponentSet& Equipotential::getComponents () const { return _components; } + inline std::string Equipotential::getName () const { return _name; } + inline const std::vector& Equipotential::getChilds () const { return _childs; } inline bool Equipotential::hasComponent ( Component* component ) const { return _components.find( component ) != _components.end(); } diff --git a/tramontana/src/tramontana/EquipotentialsModel.h b/tramontana/src/tramontana/EquipotentialsModel.h new file mode 100644 index 00000000..0a277e11 --- /dev/null +++ b/tramontana/src/tramontana/EquipotentialsModel.h @@ -0,0 +1,62 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/EquipotentialsModel.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include +#include +#include +#include "hurricane/Commons.h" +#include "hurricane/Name.h" +#include "hurricane/Net.h" +#include "hurricane/Cell.h" +#include "hurricane/viewer/Graphics.h" +#include "tramontana/Equipotential.h" +#include "tramontana/TramontanaEngine.h" + + +namespace Tramontana { + + using Hurricane::Cell; + + + class EquipotentialsModel : public QAbstractTableModel { + Q_OBJECT; + + public: + EquipotentialsModel ( QObject* parent=NULL ); + void setCell ( Cell* cell ); + int rowCount ( const QModelIndex& parent=QModelIndex() ) const; + int columnCount ( const QModelIndex& parent=QModelIndex() ) const; + QVariant data ( const QModelIndex& index, int role=Qt::DisplayRole ) const; + QVariant headerData ( int section, Qt::Orientation orientation, int role=Qt::DisplayRole ) const; + inline Cell* getCell (); + const Equipotential* getEqui ( int row ); + + private: + Cell* _cell; + std::vector _equipotentials; + }; + + +// Inline Functions. + + inline Cell* EquipotentialsModel::getCell () { return _cell; } + + +} // Hurricane namespace. diff --git a/tramontana/src/tramontana/EquipotentialsWidget.h b/tramontana/src/tramontana/EquipotentialsWidget.h new file mode 100644 index 00000000..4ebdcb04 --- /dev/null +++ b/tramontana/src/tramontana/EquipotentialsWidget.h @@ -0,0 +1,163 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/EquipotentialsWidget.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include +#include +#include +#include +#include +#include +#include "hurricane/Commons.h" +#include "hurricane/Bug.h" +#include "hurricane/viewer/CellWidget.h" +#include "hurricane/viewer/CellWidget.h" +#include "tramontana/EquipotentialsModel.h" + + +class QSortFilterProxyModel; +class QModelIndex; +class QTableView; +class QLineEdit; +class QComboBox; +class QHeaderView; + + +namespace Tramontana { + + using std::string; + using std::set; + using Hurricane::Cell; + using Hurricane::CellWidget; + + +// ------------------------------------------------------------------- +// Class : "SelectedEqui". + + + class SelectedEqui { + public: + inline SelectedEqui (); + inline SelectedEqui ( const Equipotential*, size_t access=0 ); + inline const Equipotential* getEqui () const; + inline size_t getAccesses () const; + inline void incAccesses () const; + inline void setInserted () const; + inline void resetAccesses () const; + private: + const Equipotential* _equi; + mutable size_t _accesses; + }; + + + inline SelectedEqui::SelectedEqui () : _equi(nullptr), _accesses(0) { } + inline SelectedEqui::SelectedEqui ( const Equipotential* equi, size_t accesses ) : _equi(equi), _accesses(accesses) { } + inline const Equipotential* SelectedEqui::getEqui () const { return _equi; } + inline void SelectedEqui::setInserted () const { _accesses = 64; } + inline size_t SelectedEqui::getAccesses () const { return _accesses; } + inline void SelectedEqui::incAccesses () const { ++_accesses; } + inline void SelectedEqui::resetAccesses () const { _accesses = 0; } + + + struct SelectedEquiCompare { + inline bool operator() ( const SelectedEqui& lhs, const SelectedEqui& rhs ) const; + }; + + + inline bool SelectedEquiCompare::operator() ( const SelectedEqui& lhs, const SelectedEqui& rhs ) const + { + return lhs.getEqui()->getId() < rhs.getEqui()->getId(); + } + + +// ------------------------------------------------------------------- +// Class : "SelectedEquiSet". + + + class SelectedEquiSet : public set{ + public: + void insert ( const Equipotential* ); + void forceInserteds (); + void resetAccesses (); + }; + + + inline void SelectedEquiSet::insert ( const Equipotential* equi ) + { + iterator iselected = find(SelectedEqui(equi)); + if (iselected != end()) + iselected->incAccesses(); + else + set::insert( SelectedEqui(equi,64) ); + } + + + inline void SelectedEquiSet::forceInserteds () + { + for ( iterator iselected=begin() ; iselected != end() ; ++iselected ) + iselected->setInserted(); + } + + + inline void SelectedEquiSet::resetAccesses () + { + for ( iterator iselected=begin() ; iselected != end() ; ++iselected ) + iselected->resetAccesses(); + } + + +// ------------------------------------------------------------------- +// Class : "EquipotentialsWidget". + + + class EquipotentialsWidget : public QWidget { + Q_OBJECT; + + public: + EquipotentialsWidget ( QWidget* parent=nullptr ); + inline Cell* getCell (); + void setCellWidget ( CellWidget* ); + void setCell ( Cell* ); + void goTo ( int ); + void updateSelecteds (); + signals: + void equipotentialSelect ( const ComponentSet& ); + void equipotentialUnselect ( const ComponentSet& ); + void netFitted ( const Equipotential* ); + private slots: + void textFilterChanged (); + void updateSelecteds ( const QItemSelection& , const QItemSelection& ); + // void fitToEqui (); + + private: + CellWidget* _cellWidget; + Cell* _cell; + EquipotentialsModel* _baseModel; + QSortFilterProxyModel* _sortModel; + QTableView* _view; + QLineEdit* _filterPatternLineEdit; + int _rowHeight; + SelectedEquiSet _selecteds; + bool _forceReselect; + }; + + + inline Cell* EquipotentialsWidget::getCell () { return _cell; } + + +} // Hurricane namespace. diff --git a/tramontana/src/tramontana/TabEquipotentials.h b/tramontana/src/tramontana/TabEquipotentials.h new file mode 100644 index 00000000..075a2783 --- /dev/null +++ b/tramontana/src/tramontana/TabEquipotentials.h @@ -0,0 +1,62 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) Sorbonne Université 2007-2023, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | T r a m o n t a n a - Extractor & LVX | +// | | +// | Algorithm : Christian MASSON | +// | First impl. : Yifei WU | +// | Second impl. : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Header : "./tramontana/TabEquipotentials.h" | +// +-----------------------------------------------------------------+ + + +#pragma once +#include "hurricane/viewer/ControllerWidget.h" +#include "tramontana/EquipotentialsWidget.h" + + +namespace Tramontana { + + using Hurricane::ControllerTab; + + +// ------------------------------------------------------------------- +// Class : "Tramontana::TabEquipotentials". + + + class TabEquipotentials : public ControllerTab { + Q_OBJECT; + + public: + TabEquipotentials ( QWidget* parent=NULL ); + inline QCheckBox* getSyncEquipotentials (); + inline QCheckBox* getSyncSelection (); + inline EquipotentialsWidget* getBrowser (); + virtual void cellPreModificate (); + virtual void cellPostModificate (); + public slots: + virtual void setCell ( Cell* ); + virtual void setCellWidget ( CellWidget* ); + virtual void setSyncEquipotentials ( bool ); + virtual void setSyncSelection ( bool ); + + protected: + EquipotentialsWidget* _browser; + QCheckBox* _syncEquipotentials; + QCheckBox* _syncSelection; + bool _cwCumulativeSelection; + }; + + + inline EquipotentialsWidget* TabEquipotentials::getBrowser () { return _browser; } + inline QCheckBox* TabEquipotentials::getSyncEquipotentials () { return _syncEquipotentials; } + inline QCheckBox* TabEquipotentials::getSyncSelection () { return _syncSelection; } + + +} diff --git a/tramontana/src/tramontana/TramontanaEngine.h b/tramontana/src/tramontana/TramontanaEngine.h index 46212665..95c07e68 100644 --- a/tramontana/src/tramontana/TramontanaEngine.h +++ b/tramontana/src/tramontana/TramontanaEngine.h @@ -53,9 +53,12 @@ namespace Tramontana { static TramontanaEngine* get ( const Cell* ); public: const Name& getName () const; + inline const std::set + getEquipotentials () const; inline void setViewer ( CellViewer* ); inline CellViewer* getViewer (); void extract (); + void consolidate (); void showEquipotentials () const; void add ( Equipotential* ); virtual Record* _getRecord () const; @@ -81,6 +84,8 @@ namespace Tramontana { inline void TramontanaEngine::setViewer ( CellViewer* viewer ) { _viewer=viewer; } inline CellViewer* TramontanaEngine::getViewer () { return _viewer; } + inline const std::set + TramontanaEngine::getEquipotentials () const { return _equipotentials; } } // Tramontana namespace.