diff --git a/src/buddies/src/bd/bdWriterOptions.cc b/src/buddies/src/bd/bdWriterOptions.cc index 8d9ccf24f..7118af13d 100644 --- a/src/buddies/src/bd/bdWriterOptions.cc +++ b/src/buddies/src/bd/bdWriterOptions.cc @@ -84,6 +84,7 @@ GenericWriterOptions::init_from_options (const db::SaveLayoutOptions &save_optio m_magic_lambda = 1.0; m_dxf_polygon_mode = save_options.get_option_by_name ("dxf_polygon_mode").to_int (); + m_dxf_use_layer_names = save_options.get_option_by_name ("dxf_use_layer_names").to_bool (); m_lstream_compression_level = save_options.get_option_by_name ("lstream_compression_level").to_int (); m_lstream_recompress = save_options.get_option_by_name ("lstream_recompress").to_bool (); @@ -347,6 +348,11 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin "* 3: create HATCH\n" "* 4: create LINE" ) + << tl::arg (group + + "#--use-layer-names", &m_dxf_use_layer_names, "Uses layer names instead of numbers", + "If this option is given, the DXF writer will use layer names rather than prepending " + "layer and datatype numbers." + ) ; } @@ -489,6 +495,7 @@ GenericWriterOptions::configure (db::SaveLayoutOptions &save_options, const db:: save_options.set_option_by_name ("cif_blank_separator", m_cif_blank_separator); save_options.set_option_by_name ("dxf_polygon_mode", m_dxf_polygon_mode); + save_options.set_option_by_name ("dxf_use_layer_names", m_dxf_use_layer_names); save_options.set_option_by_name ("lstream_compression_level", m_lstream_compression_level); save_options.set_option_by_name ("lstream_recompress", m_lstream_recompress); diff --git a/src/buddies/src/bd/bdWriterOptions.h b/src/buddies/src/bd/bdWriterOptions.h index b0831044a..e8e41c2ac 100644 --- a/src/buddies/src/bd/bdWriterOptions.h +++ b/src/buddies/src/bd/bdWriterOptions.h @@ -155,6 +155,7 @@ class BD_PUBLIC GenericWriterOptions std::string m_magic_tech; int m_dxf_polygon_mode; + bool m_dxf_use_layer_names; int m_lstream_compression_level; bool m_lstream_recompress; diff --git a/src/buddies/unit_tests/bdBasicTests.cc b/src/buddies/unit_tests/bdBasicTests.cc index 3f82829c3..06268d6ef 100644 --- a/src/buddies/unit_tests/bdBasicTests.cc +++ b/src/buddies/unit_tests/bdBasicTests.cc @@ -49,6 +49,7 @@ TEST(1) "--dummy-calls", // DXF "-op=2", + "--use-layer-names", // GDS2 "-ov=250", "--multi-xy-records", @@ -77,6 +78,7 @@ TEST(1) EXPECT_EQ (stream_opt.get_option_by_name ("cif_blank_separator").to_bool (), false); EXPECT_EQ (stream_opt.get_option_by_name ("cif_dummy_calls").to_bool (), false); EXPECT_EQ (stream_opt.get_option_by_name ("dxf_polygon_mode").to_int (), 0); + EXPECT_EQ (stream_opt.get_option_by_name ("dxf_use_layer_names").to_bool (), false); EXPECT_EQ (stream_opt.get_option_by_name ("libname").to_string (), ""); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_max_vertex_count").to_uint (), (unsigned int) 8000); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_multi_xy_records").to_bool (), false); @@ -105,6 +107,7 @@ TEST(1) EXPECT_EQ (stream_opt.get_option_by_name ("cif_blank_separator").to_bool (), true); EXPECT_EQ (stream_opt.get_option_by_name ("cif_dummy_calls").to_bool (), true); EXPECT_EQ (stream_opt.get_option_by_name ("dxf_polygon_mode").to_int (), 2); + EXPECT_EQ (stream_opt.get_option_by_name ("dxf_use_layer_names").to_bool (), true); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_max_vertex_count").to_uint (), (unsigned int) 250); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_multi_xy_records").to_bool (), true); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_write_timestamps").to_bool (), false); diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXF.cc b/src/plugins/streamers/dxf/db_plugin/dbDXF.cc index 0e63d4e6a..000d27303 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXF.cc +++ b/src/plugins/streamers/dxf/db_plugin/dbDXF.cc @@ -165,8 +165,9 @@ class DXFFormatDeclaration virtual tl::XMLElementBase *xml_writer_options_element () const { - return new db::WriterOptionsXMLElement ("cif", - tl::make_member (&db::DXFWriterOptions::polygon_mode, "polygon-mode") + return new db::WriterOptionsXMLElement ("dxf", + tl::make_member (&db::DXFWriterOptions::polygon_mode, "polygon-mode") + + tl::make_member (&db::DXFWriterOptions::use_layer_names, "use-layer-names") ); } }; diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFFormat.h b/src/plugins/streamers/dxf/db_plugin/dbDXFFormat.h index f81a48fb3..a46997d7b 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFFormat.h +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFFormat.h @@ -201,7 +201,8 @@ class DB_PLUGIN_PUBLIC DXFWriterOptions * @brief The constructor */ DXFWriterOptions () - : polygon_mode (0) + : polygon_mode (0), + use_layer_names (false) { // .. nothing yet .. } @@ -217,6 +218,14 @@ class DB_PLUGIN_PUBLIC DXFWriterOptions */ int polygon_mode; + /** + * @brief A flag indicating whether to use layer names instead of layer/datatype numbers + * + * If this flag is true, the writer will use the layer name (if present) as the DXF layer name + * rather than prepending layer and datatype numbers (e.g., "PAD" instead of "L18D0_PAD"). + */ + bool use_layer_names; + /** * @brief Implementation of FormatSpecificWriterOptions */ diff --git a/src/plugins/streamers/dxf/db_plugin/dbDXFWriter.cc b/src/plugins/streamers/dxf/db_plugin/dbDXFWriter.cc index 6fdf09c07..033b9947a 100644 --- a/src/plugins/streamers/dxf/db_plugin/dbDXFWriter.cc +++ b/src/plugins/streamers/dxf/db_plugin/dbDXFWriter.cc @@ -127,7 +127,7 @@ DXFWriter::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLa double sf = options.scale_factor () * layout.dbu (); std::vector > layers; - options.get_valid_layers (layout, layers, db::SaveLayoutOptions::LP_AssignName); + options.get_valid_layers (layout, layers, m_options.use_layer_names ? db::SaveLayoutOptions::LP_AssignNameWithPriority : db::SaveLayoutOptions::LP_AssignName); std::set cell_set; options.get_cells (layout, cell_set, layers); diff --git a/src/plugins/streamers/dxf/db_plugin/gsiDeclDbDXF.cc b/src/plugins/streamers/dxf/db_plugin/gsiDeclDbDXF.cc index be2bf57f2..841e66880 100755 --- a/src/plugins/streamers/dxf/db_plugin/gsiDeclDbDXF.cc +++ b/src/plugins/streamers/dxf/db_plugin/gsiDeclDbDXF.cc @@ -366,6 +366,16 @@ static int get_dxf_polygon_mode (const db::SaveLayoutOptions *options) return options->get_options ().polygon_mode; } +static void set_dxf_use_layer_names (db::SaveLayoutOptions *options, bool flag) +{ + options->get_options ().use_layer_names = flag; +} + +static bool get_dxf_use_layer_names (const db::SaveLayoutOptions *options) +{ + return options->get_options ().use_layer_names; +} + // extend lay::SaveLayoutOptions with the DXF options static gsi::ClassExt dxf_writer_options ( @@ -379,6 +389,17 @@ gsi::ClassExt dxf_writer_options ( "@brief Specifies how to write polygons.\n" "See \\dxf_polygon_mode= for a description of this property.\n" "\nThis property has been added in version 0.21.3.\n" + ) + + gsi::method_ext ("dxf_use_layer_names=", &set_dxf_use_layer_names, gsi::arg ("flag"), + "@brief Specifies whether to use layer names.\n" + "If this property is set to true, layer names will be used instead of layer/datatype numbers " + "when available (e.g. 'PAD' instead of 'L18D0_PAD').\n" + "\nThis property has been added in version 0.30.13.\n" + ) + + gsi::method_ext ("dxf_use_layer_names?|#dxf_use_layer_names", &get_dxf_use_layer_names, + "@brief Specifies whether to use layer names.\n" + "See \\dxf_use_layer_names= for a description of this property.\n" + "\nThis property has been added in version 0.30.13.\n" ), "" ); diff --git a/src/plugins/streamers/dxf/lay_plugin/DXFWriterOptionPage.ui b/src/plugins/streamers/dxf/lay_plugin/DXFWriterOptionPage.ui index b3a1f217e..93071240c 100644 --- a/src/plugins/streamers/dxf/lay_plugin/DXFWriterOptionPage.ui +++ b/src/plugins/streamers/dxf/lay_plugin/DXFWriterOptionPage.ui @@ -80,6 +80,13 @@ + + + + Use layer names (don't prefix with layer/datatype numbers) + + + diff --git a/src/plugins/streamers/dxf/lay_plugin/layDXFWriterPlugin.cc b/src/plugins/streamers/dxf/lay_plugin/layDXFWriterPlugin.cc index e045584fa..77e239d18 100644 --- a/src/plugins/streamers/dxf/lay_plugin/layDXFWriterPlugin.cc +++ b/src/plugins/streamers/dxf/lay_plugin/layDXFWriterPlugin.cc @@ -53,6 +53,7 @@ DXFWriterOptionPage::setup (const db::FormatSpecificWriterOptions *o, const db:: const db::DXFWriterOptions *options = dynamic_cast (o); if (options) { mp_ui->polygon_mode_cbx->setCurrentIndex (options->polygon_mode); + mp_ui->use_layer_names_cbx->setChecked (options->use_layer_names); } } @@ -62,6 +63,7 @@ DXFWriterOptionPage::commit (db::FormatSpecificWriterOptions *o, const db::Techn db::DXFWriterOptions *options = dynamic_cast (o); if (options) { options->polygon_mode = mp_ui->polygon_mode_cbx->currentIndex (); + options->use_layer_names = mp_ui->use_layer_names_cbx->isChecked (); } } diff --git a/src/plugins/streamers/dxf/unit_tests/dbDXFWriterTests.cc b/src/plugins/streamers/dxf/unit_tests/dbDXFWriterTests.cc index 70c332dbe..c83d2bc6a 100644 --- a/src/plugins/streamers/dxf/unit_tests/dbDXFWriterTests.cc +++ b/src/plugins/streamers/dxf/unit_tests/dbDXFWriterTests.cc @@ -290,3 +290,51 @@ TEST(FullSpinWithLayer0) std::string fn_au = tl::testdata () + std::string ("/dxf/") + "dxf5_au.dxf"; compare_text_files (tmp2, fn_au); } + +TEST(LayerNames) +{ + db::Layout l; + db::cell_index_type top = l.add_cell ("TOP"); + + unsigned int l1 = l.insert_layer (db::LayerProperties (18, 0, "PAD")); + unsigned int l2 = l.insert_layer (db::LayerProperties (19, 0)); + + l.cell (top).shapes (l1).insert (db::Box (0, 0, 1000, 1000)); + l.cell (top).shapes (l2).insert (db::Box (1000, 1000, 2000, 2000)); + + // Test 1: default (use_layer_names = false): layer 18/0 with name "PAD" becomes L18D0_PAD + { + std::string tmp = tmp_file ("tmp_default.dxf"); + db::SaveLayoutOptions options; + options.set_format ("DXF"); + + tl::OutputStream stream (tmp); + db::Writer writer (options); + writer.write (l, stream); + + tl::InputStream is (tmp); + std::string content = is.read_all (); + EXPECT_EQ (content.find ("L18D0_PAD") != std::string::npos, true); + EXPECT_EQ (content.find ("L19D0") != std::string::npos, true); + } + + // Test 2: use_layer_names = true: layer 18/0 with name "PAD" becomes PAD + { + std::string tmp = tmp_file ("tmp_named.dxf"); + db::SaveLayoutOptions options; + db::DXFWriterOptions dxf_opt; + dxf_opt.use_layer_names = true; + options.set_options (new db::DXFWriterOptions (dxf_opt)); + options.set_format ("DXF"); + + tl::OutputStream stream (tmp); + db::Writer writer (options); + writer.write (l, stream); + + tl::InputStream is (tmp); + std::string content = is.read_all (); + EXPECT_EQ (content.find ("\nPAD\n") != std::string::npos || content.find ("\r\nPAD\r\n") != std::string::npos, true); + EXPECT_EQ (content.find ("L18D0_PAD") == std::string::npos, true); + EXPECT_EQ (content.find ("L19D0") != std::string::npos, true); + } +} diff --git a/src/pymod/distutils_src/klayout/dbcore.pyi b/src/pymod/distutils_src/klayout/dbcore.pyi index 89f516e97..9dde46bf0 100644 --- a/src/pymod/distutils_src/klayout/dbcore.pyi +++ b/src/pymod/distutils_src/klayout/dbcore.pyi @@ -65045,6 +65045,20 @@ class SaveLayoutOptions: This property has been added in version 0.21.3. '4', in version 0.25.6. """ + dxf_use_layer_names: bool + r""" + Getter: + @brief Specifies whether to use layer names. + See \dxf_use_layer_names= for a description of this property. + + This property has been added in version 0.30.13. + + Setter: + @brief Specifies whether to use layer names. + If this property is set to true, layer names will be used instead of layer/datatype numbers when available (e.g. 'PAD' instead of 'L18D0_PAD'). + + This property has been added in version 0.30.13. + """ format: str r""" Getter: diff --git a/testdata/ruby/laySaveLayoutOptions.rb b/testdata/ruby/laySaveLayoutOptions.rb index 685a2e771..42a424d80 100644 --- a/testdata/ruby/laySaveLayoutOptions.rb +++ b/testdata/ruby/laySaveLayoutOptions.rb @@ -89,6 +89,11 @@ def test_1 opt.dxf_polygon_mode = 2 assert_equal(opt.dxf_polygon_mode, 2) + opt.dxf_use_layer_names = true + assert_equal(opt.dxf_use_layer_names?, true) + opt.dxf_use_layer_names = false + assert_equal(opt.dxf_use_layer_names?, false) + opt.gds2_libname = "MYLIB" assert_equal(opt.gds2_libname, "MYLIB") @@ -135,6 +140,7 @@ def test_1 assert_equal(opt.gds2_write_timestamps?, false) assert_equal(opt.dxf_polygon_mode, 2) + assert_equal(opt.dxf_use_layer_names?, false) opt.oasis_compression_level = 5 assert_equal(opt.oasis_compression_level, 5)