Merge pull request #336 from KLayout/multiple-files-on-import

Stream import: support multiple files
This commit is contained in:
Matthias Köfferlein 2019-08-30 14:01:38 +02:00 committed by GitHub
commit fde4fd42f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 602 additions and 449 deletions

View File

@ -101,3 +101,6 @@ plugins.depends += lib rdb db
unit_tests.depends += plugins $$MAIN_DEPENDS
RESOURCES += \
plugins/tools/import/lay_plugin/layResources.qrc

File diff suppressed because it is too large Load Diff

View File

@ -61,7 +61,7 @@ public:
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
{
lay::PluginDeclaration::get_menu_entries (menu_entries);
menu_entries.push_back (lay::MenuEntry ("lay::import_stream", "import_stream:edit", "file_menu.import_menu.end", tl::to_string (QObject::tr ("Other File Into Current"))));
menu_entries.push_back (lay::MenuEntry ("lay::import_stream", "import_stream:edit", "file_menu.import_menu.end", tl::to_string (QObject::tr ("Other Files Into Current"))));
}
virtual bool configure (const std::string &name, const std::string &value)

View File

@ -126,7 +126,7 @@ StreamImportData::setup_importer (StreamImporter *importer)
importer->set_reference_points (reference_points);
importer->set_cell_mapping (mode);
importer->set_layer_mapping (layer_mode);
importer->set_file (file);
importer->set_files (files);
importer->set_topcell (topcell);
importer->set_layer_offset (layer_offset);
importer->set_reader_options (options);
@ -136,9 +136,12 @@ static tl::XMLElementList xml_elements ()
{
typedef std::pair <db::DPoint, db::DPoint> ref_point;
typedef std::vector<ref_point> ref_point_v;
typedef std::vector<std::string> string_v;
return
tl::make_member (&StreamImportData::file, "file") +
tl::make_element (&StreamImportData::files, "files",
tl::make_member<std::string, string_v::const_iterator, string_v> (&string_v::begin, &string_v::end, &string_v::push_back, "file")
) +
tl::make_member (&StreamImportData::topcell, "cell-name") +
tl::make_member (&StreamImportData::layer_offset, "layer-offset") +
tl::make_member (&StreamImportData::layer_mode, "layer-mode", LayerModeConverter ()) +
@ -217,10 +220,14 @@ StreamImportDialog::reset_options ()
void
StreamImportDialog::browse_filename ()
{
QString file = mp_ui->file_le->text ();
file = QFileDialog::getOpenFileName (this, QObject::tr ("File To Import"), file, QObject::tr ("All files (*)"));
if (! file.isNull ()) {
mp_ui->file_le->setText (file);
QStringList files = mp_ui->files_te->toPlainText ().split (QString::fromUtf8 ("\n"));
QString file;
if (! files.isEmpty ()) {
file = files.front ();
}
files = QFileDialog::getOpenFileNames (this, QObject::tr ("File To Import"), file, QObject::tr ("All files (*)"));
if (! files.isEmpty ()) {
mp_ui->files_te->setPlainText (files.join (QString::fromUtf8 ("\n")));
}
}
@ -319,7 +326,7 @@ StreamImportDialog::commit_page ()
if (page == 0) {
// --- General page
mp_data->file = tl::to_string (mp_ui->file_le->text ());
mp_data->files = tl::split (tl::to_string (mp_ui->files_te->toPlainText ()), "\n");
mp_data->topcell = tl::to_string (mp_ui->topcell_le->text ());
if (mp_ui->import_simple_rb->isChecked ()) {
mp_data->mode = StreamImportData::Simple;
@ -426,7 +433,7 @@ StreamImportDialog::update ()
mp_ui->section_header_lbl->setText (tl::to_qstring (section_headers [page]));
// --- General page
mp_ui->file_le->setText (tl::to_qstring (mp_data->file));
mp_ui->files_te->setPlainText (tl::to_qstring (tl::join (mp_data->files, "\n")));
mp_ui->topcell_le->setText (tl::to_qstring (mp_data->topcell));
mp_ui->import_simple_rb->setChecked (mp_data->mode == StreamImportData::Simple);
mp_ui->import_extra_rb->setChecked (mp_data->mode == StreamImportData::Extra);

View File

@ -73,7 +73,7 @@ public:
enum layer_mode_type { Original = 0, Offset = 1 };
mode_type mode;
std::string file;
std::vector<std::string> files;
std::string topcell;
std::vector <std::pair <db::DPoint, db::DPoint> > reference_points;
db::DCplxTrans explicit_trans;

View File

@ -126,61 +126,6 @@ StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index,
}
// Prepare the layout to read
db::Layout source;
// Load the layout
{
tl::InputStream stream (m_file);
db::Reader reader (stream);
tl::log << tl::to_string (QObject::tr ("Loading file: ")) << m_file;
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading")));
reader.read (source, m_options);
}
// Locate the top cell in the source file
db::cell_index_type source_topcell;
std::vector <db::cell_index_type> source_cells;
if (m_cell_mapping != StreamImportData::Extra || !m_topcell.empty ()) {
if (m_topcell.empty ()) {
db::Layout::top_down_const_iterator t = source.begin_top_down ();
if (t == source.end_top_down ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout does not have a top cell")));
}
source_topcell = *t;
++t;
if (t != source.end_top_cells ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout does not have a unique top cell - specify one explicitly")));
}
} else {
std::pair<bool, db::cell_index_type> t = source.cell_by_name (m_topcell.c_str ());
if (! t.first) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout does not have a cell named '%s'")), m_topcell);
}
source_topcell = t.second;
}
source_cells.push_back (source_topcell);
} else {
// collect source cells
for (db::Layout::top_down_const_iterator t = source.begin_top_down (); t != source.end_top_cells (); ++t) {
source_cells.push_back (*t);
}
}
// Issue a warning, if the transformation is not ortho etc.
if (fabs (global_trans.mag () - floor (global_trans.mag () + 0.5)) > 1e-6 || ! global_trans.is_ortho ()) {
@ -193,76 +138,141 @@ StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index,
}
}
// Create a layer map
std::map <unsigned int, unsigned int> layer_map;
for (db::Layout::layer_iterator l = source.begin_layers (); l != source.end_layers (); ++l) {
db::LayerProperties lp (*(*l).second);
if (m_layer_mapping == StreamImportData::Offset) {
lp = m_layer_offset.apply (lp);
// TODO: Currently no merging is provided for non-unity transformations
if (m_cell_mapping == StreamImportData::Merge && ! global_trans.equal (db::DCplxTrans ())) {
if (QMessageBox::warning (QApplication::activeWindow (),
QObject::tr ("Merge Mode Is Not Available"),
tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("Merge mode is not supported for the specified transformation (%s).\nSimple mode will be used instead.\nPress 'Ok' to continue.")), global_trans.to_string ())),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok) != QMessageBox::Ok) {
return;
}
bool layer_found = false;
for (db::Layout::layer_iterator ll = target.begin_layers (); ll != target.end_layers () && ! layer_found; ++ll) {
if ((*ll).second->log_equal (lp)) {
layer_map.insert (std::make_pair ((*l).first, (*ll).first));
layer_found = true;
}
}
if (! layer_found) {
unsigned int new_layer = target.insert_layer (lp);
layer_map.insert (std::make_pair ((*l).first, new_layer));
new_layers.push_back (new_layer);
}
m_cell_mapping = StreamImportData::Simple;
}
// Create a cell map
std::map <db::cell_index_type, db::cell_index_type> cell_map;
for (size_t file_index = 0; file_index < m_files.size (); ++file_index) {
if (m_cell_mapping == StreamImportData::Simple) {
std::string file = m_files [file_index];
cell_map.insert (std::make_pair (source_topcell, target_cell_index));
// Prepare the layout to read
db::Layout source;
} else if (m_cell_mapping == StreamImportData::Extra) {
// Load the layout
{
tl::InputStream stream (file);
db::Reader reader (stream);
// create new top cells for each source top cell
for (std::vector<db::cell_index_type>::const_iterator t = source_cells.begin (); t != source_cells.end (); ++t) {
db::cell_index_type new_top = target.add_cell (source.cell_name (*t));
cell_map.insert (std::make_pair (*t, new_top));
tl::log << tl::to_string (QObject::tr ("Loading file: ")) << file;
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading file: ")) + file);
reader.read (source, m_options);
}
} else if (m_cell_mapping == StreamImportData::Instantiate) {
// Locate the top cell in the source file
db::cell_index_type source_topcell;
std::vector <db::cell_index_type> source_cells;
// Create a new top cell for importing into and use the cell reference to produce the first part of the transformation
if (m_cell_mapping != StreamImportData::Extra || !m_topcell.empty ()) {
db::cell_index_type new_top = target.add_cell (source.cell_name (source_topcell));
cell_map.insert (std::make_pair (source_topcell, new_top));
if (m_topcell.empty ()) {
db::ICplxTrans gt_dbu = db::VCplxTrans (1.0 / target.dbu ()) * global_trans * db::CplxTrans (source.dbu ());
target.cell (target_cell_index).insert (db::CellInstArray (new_top, gt_dbu * db::ICplxTrans (1.0 / global_trans.mag ())));
db::Layout::top_down_const_iterator t = source.begin_top_down ();
if (t == source.end_top_down ()) {
throw tl::Exception (tl::sprintf (tl::to_string (QObject::tr ("Source layout '%s' does not have a top cell")), file));
}
global_trans = db::DCplxTrans (global_trans.mag ());
source_topcell = *t;
} else if (m_cell_mapping == StreamImportData::Merge) {
++t;
if (t != source.end_top_cells ()) {
throw tl::Exception (tl::sprintf (tl::to_string (QObject::tr ("Source layout '%s' does not have a unique top cell - specify one explicitly")), file));
}
// Create the cell mapping
// TODO: Currently no merging is provided for non-unity transformations
if (! global_trans.equal (db::DCplxTrans ())) {
} else {
std::pair<bool, db::cell_index_type> t = source.cell_by_name (m_topcell.c_str ());
if (! t.first) {
throw tl::Exception (tl::sprintf (tl::to_string (QObject::tr ("Source layout '%s' does not have a cell named '%s'")), file, m_topcell));
}
source_topcell = t.second;
if (QMessageBox::warning (QApplication::activeWindow (),
QObject::tr ("Merge Mode Is Not Available"),
tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("Merge mode is not supported for the specified transformation (%s).\nSimple mode will be used instead.\nPress 'Ok' to continue.")), global_trans.to_string ())),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok) != QMessageBox::Ok) {
return;
}
source_cells.push_back (source_topcell);
} else {
// collect source cells
for (db::Layout::top_down_const_iterator t = source.begin_top_down (); t != source.end_top_cells (); ++t) {
source_cells.push_back (*t);
}
}
// Create a layer map
std::map <unsigned int, unsigned int> layer_map;
for (db::Layout::layer_iterator l = source.begin_layers (); l != source.end_layers (); ++l) {
db::LayerProperties lp (*(*l).second);
if (m_layer_mapping == StreamImportData::Offset) {
lp = m_layer_offset.apply (lp);
}
bool layer_found = false;
for (db::Layout::layer_iterator ll = target.begin_layers (); ll != target.end_layers () && ! layer_found; ++ll) {
if ((*ll).second->log_equal (lp)) {
layer_map.insert (std::make_pair ((*l).first, (*ll).first));
layer_found = true;
}
}
if (! layer_found) {
unsigned int new_layer = target.insert_layer (lp);
layer_map.insert (std::make_pair ((*l).first, new_layer));
new_layers.push_back (new_layer);
}
}
// Computes the final global transformation
db::DCplxTrans gt = global_trans;
// Create a cell map
std::map <db::cell_index_type, db::cell_index_type> cell_map;
if (m_cell_mapping == StreamImportData::Simple) {
cell_map.insert (std::make_pair (source_topcell, target_cell_index));
} else {
} else if (m_cell_mapping == StreamImportData::Extra) {
// create new top cells for each source top cell
for (std::vector<db::cell_index_type>::const_iterator t = source_cells.begin (); t != source_cells.end (); ++t) {
db::cell_index_type new_top = target.add_cell (source.cell_name (*t));
cell_map.insert (std::make_pair (*t, new_top));
}
} else if (m_cell_mapping == StreamImportData::Instantiate) {
// Create a new top cell for importing into and use the cell reference to produce the first part of the transformation
db::cell_index_type new_top = target.add_cell (source.cell_name (source_topcell));
cell_map.insert (std::make_pair (source_topcell, new_top));
db::ICplxTrans gt_dbu = db::VCplxTrans (1.0 / target.dbu ()) * gt * db::CplxTrans (source.dbu ());
target.cell (target_cell_index).insert (db::CellInstArray (new_top, gt_dbu * db::ICplxTrans (1.0 / gt.mag ())));
gt = db::DCplxTrans (gt.mag ());
} else if (m_cell_mapping == StreamImportData::Merge) {
// Create the cell mapping
// TODO: Currently no merging is provided for non-unity transformations
tl_assert (gt.equal (db::DCplxTrans ()));
db::CellMapping cm;
cm.create_from_geometry (target, target_cell_index, source, source_topcell);
@ -270,11 +280,10 @@ StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index,
}
// And actually merge
db::merge_layouts (target, source, db::VCplxTrans (1.0 / target.dbu ()) * gt * db::CplxTrans (source.dbu ()), source_cells, cell_map, layer_map);
}
// And actually merge
db::merge_layouts (target, source, db::VCplxTrans (1.0 / target.dbu ()) * global_trans * db::CplxTrans (source.dbu ()), source_cells, cell_map, layer_map);
}
}

View File

@ -93,19 +93,19 @@ public:
}
/**
* @brief Set file which is read.
* @brief Set files which are read.
*/
void set_file (const std::string &file)
void set_files (const std::vector<std::string> &files)
{
m_file = file;
m_files = files;
}
/**
* @brief Get the file which is read
*/
const std::string &file () const
const std::vector<std::string> &files () const
{
return m_file;
return m_files;
}
/**
@ -192,7 +192,7 @@ public:
}
private:
std::string m_file;
std::vector<std::string> m_files;
std::string m_topcell;
db::DCplxTrans m_global_trans;
std::vector <std::pair <db::DPoint, db::DPoint> > m_reference_points;