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 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 virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
{ {
lay::PluginDeclaration::get_menu_entries (menu_entries); 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) 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_reference_points (reference_points);
importer->set_cell_mapping (mode); importer->set_cell_mapping (mode);
importer->set_layer_mapping (layer_mode); importer->set_layer_mapping (layer_mode);
importer->set_file (file); importer->set_files (files);
importer->set_topcell (topcell); importer->set_topcell (topcell);
importer->set_layer_offset (layer_offset); importer->set_layer_offset (layer_offset);
importer->set_reader_options (options); 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::pair <db::DPoint, db::DPoint> ref_point;
typedef std::vector<ref_point> ref_point_v; typedef std::vector<ref_point> ref_point_v;
typedef std::vector<std::string> string_v;
return 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::topcell, "cell-name") +
tl::make_member (&StreamImportData::layer_offset, "layer-offset") + tl::make_member (&StreamImportData::layer_offset, "layer-offset") +
tl::make_member (&StreamImportData::layer_mode, "layer-mode", LayerModeConverter ()) + tl::make_member (&StreamImportData::layer_mode, "layer-mode", LayerModeConverter ()) +
@ -217,10 +220,14 @@ StreamImportDialog::reset_options ()
void void
StreamImportDialog::browse_filename () StreamImportDialog::browse_filename ()
{ {
QString file = mp_ui->file_le->text (); QStringList files = mp_ui->files_te->toPlainText ().split (QString::fromUtf8 ("\n"));
file = QFileDialog::getOpenFileName (this, QObject::tr ("File To Import"), file, QObject::tr ("All files (*)")); QString file;
if (! file.isNull ()) { if (! files.isEmpty ()) {
mp_ui->file_le->setText (file); 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) { if (page == 0) {
// --- General page // --- 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 ()); mp_data->topcell = tl::to_string (mp_ui->topcell_le->text ());
if (mp_ui->import_simple_rb->isChecked ()) { if (mp_ui->import_simple_rb->isChecked ()) {
mp_data->mode = StreamImportData::Simple; mp_data->mode = StreamImportData::Simple;
@ -426,7 +433,7 @@ StreamImportDialog::update ()
mp_ui->section_header_lbl->setText (tl::to_qstring (section_headers [page])); mp_ui->section_header_lbl->setText (tl::to_qstring (section_headers [page]));
// --- General 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->topcell_le->setText (tl::to_qstring (mp_data->topcell));
mp_ui->import_simple_rb->setChecked (mp_data->mode == StreamImportData::Simple); mp_ui->import_simple_rb->setChecked (mp_data->mode == StreamImportData::Simple);
mp_ui->import_extra_rb->setChecked (mp_data->mode == StreamImportData::Extra); 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 }; enum layer_mode_type { Original = 0, Offset = 1 };
mode_type mode; mode_type mode;
std::string file; std::vector<std::string> files;
std::string topcell; std::string topcell;
std::vector <std::pair <db::DPoint, db::DPoint> > reference_points; std::vector <std::pair <db::DPoint, db::DPoint> > reference_points;
db::DCplxTrans explicit_trans; db::DCplxTrans explicit_trans;

View File

@ -126,16 +126,48 @@ StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index,
} }
// 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 ()) {
if (QMessageBox::warning (QApplication::activeWindow (),
QObject::tr ("Complex Transformation"),
tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("The specified transformation (%s) is complex.\nGrid snapping to the database unit grid can occur and\neffectively alter the geometry of the layout.\nPress 'Ok' to continue.")), global_trans.to_string ())),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok) != QMessageBox::Ok) {
return;
}
}
// 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;
}
m_cell_mapping = StreamImportData::Simple;
}
for (size_t file_index = 0; file_index < m_files.size (); ++file_index) {
std::string file = m_files [file_index];
// Prepare the layout to read // Prepare the layout to read
db::Layout source; db::Layout source;
// Load the layout // Load the layout
{ {
tl::InputStream stream (m_file); tl::InputStream stream (file);
db::Reader reader (stream); db::Reader reader (stream);
tl::log << tl::to_string (QObject::tr ("Loading file: ")) << m_file; tl::log << tl::to_string (QObject::tr ("Loading file: ")) << file;
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading"))); tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Loading file: ")) + file);
reader.read (source, m_options); reader.read (source, m_options);
} }
@ -149,21 +181,21 @@ StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index,
db::Layout::top_down_const_iterator t = source.begin_top_down (); db::Layout::top_down_const_iterator t = source.begin_top_down ();
if (t == source.end_top_down ()) { if (t == source.end_top_down ()) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout does not have a top cell"))); throw tl::Exception (tl::sprintf (tl::to_string (QObject::tr ("Source layout '%s' does not have a top cell")), file));
} }
source_topcell = *t; source_topcell = *t;
++t; ++t;
if (t != source.end_top_cells ()) { 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"))); throw tl::Exception (tl::sprintf (tl::to_string (QObject::tr ("Source layout '%s' does not have a unique top cell - specify one explicitly")), file));
} }
} else { } else {
std::pair<bool, db::cell_index_type> t = source.cell_by_name (m_topcell.c_str ()); std::pair<bool, db::cell_index_type> t = source.cell_by_name (m_topcell.c_str ());
if (! t.first) { if (! t.first) {
throw tl::Exception (tl::to_string (QObject::tr ("Source layout does not have a cell named '%s'")), m_topcell); 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; source_topcell = t.second;
@ -181,19 +213,6 @@ StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index,
} }
// 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 ()) {
if (QMessageBox::warning (QApplication::activeWindow (),
QObject::tr ("Complex Transformation"),
tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("The specified transformation (%s) is complex.\nGrid snapping to the database unit grid can occur and\neffectively alter the geometry of the layout.\nPress 'Ok' to continue.")), global_trans.to_string ())),
QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::Ok) != QMessageBox::Ok) {
return;
}
}
// Create a layer map // Create a layer map
std::map <unsigned int, unsigned int> layer_map; std::map <unsigned int, unsigned int> layer_map;
for (db::Layout::layer_iterator l = source.begin_layers (); l != source.end_layers (); ++l) { for (db::Layout::layer_iterator l = source.begin_layers (); l != source.end_layers (); ++l) {
@ -219,6 +238,9 @@ StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index,
} }
// Computes the final global transformation
db::DCplxTrans gt = global_trans;
// Create a cell map // Create a cell map
std::map <db::cell_index_type, db::cell_index_type> cell_map; std::map <db::cell_index_type, db::cell_index_type> cell_map;
@ -241,28 +263,16 @@ StreamImporter::read (db::Layout &target, db::cell_index_type target_cell_index,
db::cell_index_type new_top = target.add_cell (source.cell_name (source_topcell)); db::cell_index_type new_top = target.add_cell (source.cell_name (source_topcell));
cell_map.insert (std::make_pair (source_topcell, new_top)); cell_map.insert (std::make_pair (source_topcell, new_top));
db::ICplxTrans gt_dbu = db::VCplxTrans (1.0 / target.dbu ()) * global_trans * db::CplxTrans (source.dbu ()); 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 / global_trans.mag ()))); target.cell (target_cell_index).insert (db::CellInstArray (new_top, gt_dbu * db::ICplxTrans (1.0 / gt.mag ())));
global_trans = db::DCplxTrans (global_trans.mag ()); gt = db::DCplxTrans (gt.mag ());
} else if (m_cell_mapping == StreamImportData::Merge) { } else if (m_cell_mapping == StreamImportData::Merge) {
// Create the cell mapping // Create the cell mapping
// TODO: Currently no merging is provided for non-unity transformations // TODO: Currently no merging is provided for non-unity transformations
if (! global_trans.equal (db::DCplxTrans ())) { tl_assert (gt.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;
}
cell_map.insert (std::make_pair (source_topcell, target_cell_index));
} else {
db::CellMapping cm; db::CellMapping cm;
cm.create_from_geometry (target, target_cell_index, source, source_topcell); 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 // 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); db::merge_layouts (target, source, db::VCplxTrans (1.0 / target.dbu ()) * gt * 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 * @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: private:
std::string m_file; std::vector<std::string> m_files;
std::string m_topcell; std::string m_topcell;
db::DCplxTrans m_global_trans; db::DCplxTrans m_global_trans;
std::vector <std::pair <db::DPoint, db::DPoint> > m_reference_points; std::vector <std::pair <db::DPoint, db::DPoint> > m_reference_points;