/* KLayout Layout Viewer Copyright (C) 2006-2025 Matthias Koefferlein This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "dbGerberImportData.h" #include "dbGerberImporter.h" #include "dbPoint.h" #include "dbConverters.h" #include "tlFileUtils.h" #include "tlXMLParser.h" namespace db { // ----------------------------------------------------------------------------------------- // GerberImportData implementation GerberImportData::GerberImportData () : invert_negative_layers (false), border (5000), free_layer_mapping (false), mode (ModeSamePanel), mounting (MountingTop), num_metal_layers (0), num_via_types (0), num_circle_points (-1), merge_flag (false), dbu (0.001), topcell_name ("PCB") { // .. nothing yet .. } void GerberImportData::reset () { double dbu_saved = dbu; std::string base_dir_saved = base_dir; bool free_layer_mapping_saved = free_layer_mapping; mode_type mode_saved = mode; *this = GerberImportData (); dbu = dbu_saved; base_dir = base_dir_saved; free_layer_mapping = free_layer_mapping_saved; mode = mode_saved; } std::string GerberImportData::get_layer_properties_file () const { std::string lyp_file = layer_properties_file; if (! lyp_file.empty ()) { if (! base_dir.empty () && ! tl::is_absolute (lyp_file)) { lyp_file = tl::absolute_file_path (tl::combine_path (base_dir, lyp_file)); } } return lyp_file; } void GerberImportData::setup_importer (db::GerberImporter *importer) { if (num_circle_points >= 4) { importer->set_circle_points (num_circle_points); } importer->set_dbu (dbu); importer->set_cell_name (topcell_name); importer->set_dir (base_dir); importer->set_global_trans (explicit_trans); importer->set_reference_points (reference_points); importer->set_merge (merge_flag); importer->set_invert_negative_layers (invert_negative_layers); importer->set_border (border); if (free_layer_mapping) { for (std::vector::iterator file = free_files.begin (); file != free_files.end (); ++file) { if (! file->filename.empty ()) { db::GerberFile file_spec; file_spec.set_filename (file->filename); for (std::vector ::const_iterator i = file->layout_layers.begin (); i != file->layout_layers.end (); ++i) { if (*i >= 0 && *i < int (layout_layers.size ())) { file_spec.add_layer_spec (layout_layers [*i]); } } importer->add_file (file_spec); } } } else { for (std::vector::iterator file = artwork_files.begin (); file != artwork_files.end (); ++file) { if (! file->filename.empty ()) { size_t n; if (mounting == MountingTop) { n = std::distance (artwork_files.begin (), file); } else { n = std::distance (file, artwork_files.end ()) - 1; } if (n * 2 < layout_layers.size ()) { db::GerberFile file_spec; file_spec.set_filename (file->filename); file_spec.add_layer_spec (layout_layers [n * 2]); importer->add_file (file_spec); } } } for (std::vector::iterator file = drill_files.begin (); file != drill_files.end (); ++file) { if (! file->filename.empty ()) { size_t nstart, nstop; if (mounting == MountingTop) { nstart = std::distance (artwork_files.begin (), artwork_files.begin () + file->start); nstop = std::distance (artwork_files.begin (), artwork_files.begin () + file->stop); } else { nstop = std::distance (artwork_files.begin () + file->start, artwork_files.end ()) - 1; nstart = std::distance (artwork_files.begin () + file->stop, artwork_files.end ()) - 1; } db::GerberFile file_spec; file_spec.set_filename (file->filename); for (size_t n = nstart; n < nstop; ++n) { if (n * 2 + 1 < layout_layers.size ()) { file_spec.add_layer_spec (layout_layers [n * 2 + 1]); } } importer->add_file (file_spec); } } } } struct MountingConverter { typedef GerberImportData::mounting_type value_type; std::string to_string (GerberImportData::mounting_type m) const { return m == GerberImportData::MountingTop ? "top" : "bottom"; } void from_string (const std::string &s, GerberImportData::mounting_type &m) const { if (s == "top") { m = GerberImportData::MountingTop; } else if (s == "bottom") { m = GerberImportData::MountingBottom; } else { throw tl::Exception (tl::to_string (tr ("Invalid mounting specification: %s")), s); } } }; // declaration of the layer properties file XML structure static const tl::XMLStruct pcb_project_structure ("pcb-project", tl::make_member (&GerberImportData::invert_negative_layers, "invert-negative-layers") + tl::make_member (&GerberImportData::border, "border") + tl::make_member (&GerberImportData::free_layer_mapping, "free-layer-mapping") + tl::make_element (&GerberImportData::layout_layers, "layout-layers", tl::make_member::const_iterator, std::vector > (&std::vector::begin, &std::vector::end, &std::vector::push_back, "layout-layer", tl::XMLStringBasedConverter ()) ) + tl::make_member (&GerberImportData::mounting, "mounting", tl::XMLStringBasedConverter ()) + tl::make_member (&GerberImportData::num_metal_layers, "num-metal-layers") + tl::make_member (&GerberImportData::num_via_types, "num-via-types") + tl::make_element (&GerberImportData::artwork_files, "artwork-files", tl::make_element::const_iterator, std::vector > (&std::vector::begin, &std::vector::end, &std::vector::push_back, "artwork-file", tl::make_member (&GerberArtworkFileDescriptor::filename, "filename") ) ) + tl::make_element (&GerberImportData::drill_files, "drill-files", tl::make_element::const_iterator, std::vector > (&std::vector::begin, &std::vector::end, &std::vector::push_back, "drill-file", tl::make_member (&GerberDrillFileDescriptor::start, "start") + tl::make_member (&GerberDrillFileDescriptor::stop, "stop") + tl::make_member (&GerberDrillFileDescriptor::filename, "filename") ) ) + tl::make_element (&GerberImportData::free_files, "free-files", tl::make_element::const_iterator, std::vector > (&std::vector::begin, &std::vector::end, &std::vector::push_back, "free-file", tl::make_member (&GerberFreeFileDescriptor::filename, "filename") + tl::make_element (&GerberFreeFileDescriptor::layout_layers, "layout-layers", tl::make_member::const_iterator, std::vector > (&std::vector::begin, &std::vector::end, &std::vector::push_back, "index") ) ) ) + tl::make_element (&GerberImportData::reference_points, "reference-points", tl::make_element, std::vector >::const_iterator, std::vector > > (&std::vector >::begin, &std::vector >::end, &std::vector >::push_back, "reference-point", tl::make_member (&std::pair ::first, "pcb", tl::XMLStringBasedConverter > ()) + tl::make_member (&std::pair ::second, "layout", tl::XMLStringBasedConverter > ()) ) ) + tl::make_member (&GerberImportData::explicit_trans, "explicit-trans", tl::XMLStringBasedConverter > ()) + tl::make_member (&GerberImportData::layer_properties_file, "layer-properties-file") + tl::make_member (&GerberImportData::num_circle_points, "num-circle-points") + tl::make_member (&GerberImportData::merge_flag, "merge-flag") + tl::make_member (&GerberImportData::dbu, "dbu") + tl::make_member (&GerberImportData::topcell_name, "cell-name") ); void GerberImportData::load (const std::string &file) { reset (); current_file = file; tl::XMLFileSource in (file); pcb_project_structure.parse (in, *this); } void GerberImportData::load (tl::InputStream &stream) { reset (); current_file = std::string (); tl::XMLStreamSource in (stream); pcb_project_structure.parse (in, *this); } void GerberImportData::save (const std::string &file) { tl::OutputStream os (file, tl::OutputStream::OM_Plain); pcb_project_structure.write (os, *this); current_file = file; } void GerberImportData::from_string (const std::string &s) { tl::Extractor ex (s.c_str ()); while (! ex.at_end ()) { if (ex.test ("free-layer-mapping")) { ex.test ("="); ex.read (free_layer_mapping); ex.test (";"); } else if (ex.test ("invert-negative-layers")) { ex.test ("="); ex.read (invert_negative_layers); ex.test (";"); } else if (ex.test ("border")) { ex.test ("="); ex.read (border); ex.test (";"); } else if (ex.test ("import-mode")) { ex.test ("="); int m = 0; ex.read (m); mode = (mode_type) m; ex.test (";"); } else if (ex.test ("base-dir")) { ex.test ("="); ex.read_word_or_quoted (base_dir); ex.test (";"); } else if (ex.test ("layout-layers")) { ex.test ("="); layout_layers.clear (); while (! ex.test (";") && ! ex.at_end ()) { layout_layers.push_back (db::LayerProperties ()); layout_layers.back ().read (ex); ex.test (","); } ex.test (";"); } else if (ex.test ("mounting")) { ex.test ("="); std::string m; ex.read_word (m); mounting = (m == "top") ? MountingTop : MountingBottom; ex.test (";"); } else if (ex.test ("num-metal-layers")) { ex.test ("="); ex.read (num_metal_layers); ex.test (";"); } else if (ex.test ("num-via-types")) { ex.test ("="); ex.read (num_via_types); ex.test (";"); } else if (ex.test ("artwork-files")) { ex.test ("="); artwork_files.clear (); while (! ex.test (";") && ! ex.at_end ()) { ex.test ("("); artwork_files.push_back (db::GerberArtworkFileDescriptor ()); ex.read_word_or_quoted (artwork_files.back ().filename); ex.test (")"); ex.test (","); } ex.test (";"); } else if (ex.test ("drill-files")) { ex.test ("="); drill_files.clear (); while (! ex.test (";") && ! ex.at_end ()) { ex.test ("("); drill_files.push_back (db::GerberDrillFileDescriptor ()); ex.read (drill_files.back ().start); ex.test (","); ex.read (drill_files.back ().stop); ex.test (","); ex.read_word_or_quoted (drill_files.back ().filename); ex.test (")"); ex.test (","); } ex.test (";"); } else if (ex.test ("free-files")) { ex.test ("="); free_files.clear (); while (! ex.test (";") && ! ex.at_end ()) { ex.test ("("); free_files.push_back (db::GerberFreeFileDescriptor ()); ex.read_word_or_quoted (free_files.back ().filename); ex.test (","); while (! ex.test (")") && ! ex.at_end ()) { int i = -1; ex.read (i); free_files.back ().layout_layers.push_back (i); ex.test (","); } ex.test (","); } ex.test (";"); } else if (ex.test ("reference-points")) { ex.test ("="); reference_points.clear (); while (! ex.test (";") && ! ex.at_end ()) { double x1, y1, x2, y2; ex.test ("("); ex.test ("("); ex.read (x1); ex.test (","); ex.read (y1); ex.test (")"); ex.test (","); ex.test ("("); ex.read (x2); ex.test (","); ex.read (y2); ex.test (")"); ex.test (")"); ex.test (","); reference_points.push_back (std::make_pair (db::DPoint (x1, y1), db::DPoint (x2, y2))); } ex.test (";"); } else if (ex.test ("explicit-trans")) { ex.test ("="); ex.read (explicit_trans); ex.test (";"); } else if (ex.test ("layer-properties-file")) { ex.test ("="); ex.read_word_or_quoted (layer_properties_file); ex.test (";"); } else if (ex.test ("num-circle-points")) { ex.test ("="); ex.read (num_circle_points); ex.test (";"); } else if (ex.test ("merge-flag")) { ex.test ("="); ex.read (merge_flag); ex.test (";"); } else if (ex.test ("dbu")) { ex.test ("="); ex.read (dbu); ex.test (";"); } else if (ex.test ("cell-name")) { ex.test ("="); ex.read_word_or_quoted (topcell_name); ex.test (";"); } else { ex.expect_end (); } } } std::string GerberImportData::to_string () const { std::string s; s += "free-layer-mapping=" + tl::to_string(free_layer_mapping) + ";"; s += "import-mode=" + tl::to_string(int (mode)) + ";"; s += "base-dir=" + tl::to_quoted_string (base_dir) + ";"; s += "invert-negative-layers=" + tl::to_string (invert_negative_layers) + ";"; s += "border=" + tl::to_string (border) + ";"; s += "layout-layers="; for (std::vector ::const_iterator ll = layout_layers.begin (); ll != layout_layers.end (); ++ll) { if (ll != layout_layers.begin ()) { s += ","; } s += ll->to_string (); } s += ";"; s += "mounting=" + std::string (mounting == MountingTop ? "top" : "bottom") + ";"; s += "num-metal-layers=" + tl::to_string (num_metal_layers) + ";"; s += "num-via-types=" + tl::to_string (num_via_types) + ";"; s += "artwork-files="; for (std::vector ::const_iterator f = artwork_files.begin (); f != artwork_files.end (); ++f) { if (f != artwork_files.begin ()) { s += ","; } s += "(" + tl::to_quoted_string (f->filename) + ")"; } s += ";"; s += "drill-files="; for (std::vector ::const_iterator f = drill_files.begin (); f != drill_files.end (); ++f) { if (f != drill_files.begin ()) { s += ","; } s += "(" + tl::to_string (f->start) + "," + tl::to_string (f->stop) + "," + tl::to_quoted_string (f->filename) + ")"; } s += ";"; s += "free-files="; for (std::vector ::const_iterator f = free_files.begin (); f != free_files.end (); ++f) { if (f != free_files.begin ()) { s += ","; } s += "(" + tl::to_quoted_string (f->filename); for (std::vector ::const_iterator i = f->layout_layers.begin (); i != f->layout_layers.end (); ++i) { s += "," + tl::to_string (*i); } s += ")"; } s += ";"; s += "reference-points="; for (std::vector >::const_iterator rp = reference_points.begin (); rp != reference_points.end (); ++rp) { if (rp != reference_points.begin ()) { s += ","; } s += "((" + tl::to_string (rp->first.x ()) + "," + tl::to_string (rp->first.y ()) + "),(" + tl::to_string (rp->second.x ()) + "," + tl::to_string (rp->second.y ()) + "))"; } s += ";"; s += "explicit-trans=" + explicit_trans.to_string () + ";"; s += "layer-properties-file=" + tl::to_quoted_string (layer_properties_file) + ";"; s += "num-circle-points=" + tl::to_string (num_circle_points) + ";"; s += "merge-flag=" + tl::to_string (merge_flag) + ";"; s += "dbu=" + tl::to_string (dbu) + ";"; s += "cell-name=" + tl::to_quoted_string (topcell_name) + ";"; return s; } }