diff --git a/src/buddies/src/bd/bdWriterOptions.cc b/src/buddies/src/bd/bdWriterOptions.cc index 509c468dd..b863a7bb0 100644 --- a/src/buddies/src/bd/bdWriterOptions.cc +++ b/src/buddies/src/bd/bdWriterOptions.cc @@ -50,6 +50,8 @@ GenericWriterOptions::GenericWriterOptions () m_gds2_write_timestamps = save_options.get_option_by_name ("gds2_write_timestamps").to_bool (); m_gds2_write_cell_properties = save_options.get_option_by_name ("gds2_write_cell_properties").to_bool (); m_gds2_write_file_properties = save_options.get_option_by_name ("gds2_write_file_properties").to_bool (); + tl::Variant def_text_size = save_options.get_option_by_name ("gds2_default_text_size"); + m_gds2_default_text_size = def_text_size.is_nil () ? -1.0 : def_text_size.to_double (); m_oasis_compression_level = save_options.get_option_by_name ("oasis_compression_level").to_int (); m_oasis_write_cblocks = save_options.get_option_by_name ("oasis_write_cblocks").to_bool (); @@ -201,6 +203,13 @@ GenericWriterOptions::add_options (tl::CommandLineOptions &cmd, const std::strin "This option enables a GDS2 extension that allows writing of file properties to GDS2 files. " "Consumers that don't support this feature, may not be able to read such a GDS2 files." ) + << tl::arg (group + + "#--default-text-size", &m_gds2_default_text_size, "Default text size", + "This text size (given in micrometers) is applied to text objects not coming with their " + "own text size (technically: with a zero text size). It can be set to 0 to preserve an original " + "text size of zero. This option is also handy to give text objects from OASIS files a " + "specific size. By default, text objects without a size (i.e. with a zero size) do not receive one." + ) ; } @@ -379,6 +388,7 @@ GenericWriterOptions::configure (db::SaveLayoutOptions &save_options, const db:: save_options.set_option_by_name ("gds2_write_timestamps", m_gds2_write_timestamps); save_options.set_option_by_name ("gds2_write_cell_properties", m_gds2_write_cell_properties); save_options.set_option_by_name ("gds2_write_file_properties", m_gds2_write_file_properties); + save_options.set_option_by_name ("gds2_default_text_size", m_gds2_default_text_size < 0.0 ? tl::Variant () : tl::Variant (m_gds2_default_text_size)); save_options.set_option_by_name ("oasis_compression_level", m_oasis_compression_level); save_options.set_option_by_name ("oasis_write_cblocks", m_oasis_write_cblocks); diff --git a/src/buddies/src/bd/bdWriterOptions.h b/src/buddies/src/bd/bdWriterOptions.h index 3c4e5439a..0d03c411b 100644 --- a/src/buddies/src/bd/bdWriterOptions.h +++ b/src/buddies/src/bd/bdWriterOptions.h @@ -123,6 +123,7 @@ class BD_PUBLIC GenericWriterOptions bool m_gds2_write_timestamps; bool m_gds2_write_cell_properties; bool m_gds2_write_file_properties; + double m_gds2_default_text_size; int m_oasis_compression_level; bool m_oasis_write_cblocks; diff --git a/src/buddies/unit_tests/bdBasicTests.cc b/src/buddies/unit_tests/bdBasicTests.cc index a74128ffd..4c3fb38bd 100644 --- a/src/buddies/unit_tests/bdBasicTests.cc +++ b/src/buddies/unit_tests/bdBasicTests.cc @@ -82,9 +82,10 @@ TEST(1) EXPECT_EQ (stream_opt.get_option_by_name ("gds2_multi_xy_records").to_bool (), false); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_write_timestamps").to_bool (), true); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_no_zero_length_paths").to_bool (), false); - EXPECT_EQ (tl::to_string (stream_opt.get_option_by_name ("gds2_user_units").to_double ()), "1"); + EXPECT_EQ (stream_opt.get_option_by_name ("gds2_user_units").to_double (), 1.0); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_write_cell_properties").to_bool (), false); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_write_file_properties").to_bool (), false); + EXPECT_EQ (stream_opt.get_option_by_name ("gds2_default_text_size").to_string (), "nil"); EXPECT_EQ (stream_opt.get_option_by_name ("oasis_write_cblocks").to_bool (), true); EXPECT_EQ (stream_opt.get_option_by_name ("oasis_compression_level").to_int (), 2); EXPECT_EQ (stream_opt.get_option_by_name ("oasis_strict_mode").to_bool (), true); @@ -107,9 +108,10 @@ TEST(1) 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); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_no_zero_length_paths").to_bool (), true); - EXPECT_EQ (tl::to_string (stream_opt.get_option_by_name ("gds2_user_units").to_double ()), "2.5"); + EXPECT_EQ (stream_opt.get_option_by_name ("gds2_user_units").to_double (), 2.5); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_write_cell_properties").to_bool (), true); EXPECT_EQ (stream_opt.get_option_by_name ("gds2_write_file_properties").to_bool (), true); + EXPECT_EQ (stream_opt.get_option_by_name ("gds2_default_text_size").to_string (), "nil"); EXPECT_EQ (stream_opt.get_option_by_name ("oasis_write_cblocks").to_bool (), false); EXPECT_EQ (stream_opt.get_option_by_name ("oasis_compression_level").to_int (), 9); EXPECT_EQ (stream_opt.get_option_by_name ("oasis_strict_mode").to_bool (), false); @@ -118,6 +120,52 @@ TEST(1) EXPECT_EQ (stream_opt.get_option_by_name ("oasis_write_std_properties_ext").to_int (), 2); } +// Testing writer options (default_text_size) +TEST(2) +{ + bd::GenericWriterOptions opt; + tl::CommandLineOptions cmd; + + opt.add_options (cmd); + + const char *argv[] = { + "x", + "--default-text-size=1.25", + }; + + cmd.parse (sizeof (argv) / sizeof (argv[0]), const_cast (argv)); + + db::Layout layout; + + db::SaveLayoutOptions stream_opt; + EXPECT_EQ (stream_opt.get_option_by_name ("gds2_default_text_size").to_string (), "nil"); + opt.configure (stream_opt, layout); + EXPECT_EQ (stream_opt.get_option_by_name ("gds2_default_text_size").to_string (), "1.25"); +} + +// Testing writer options (default_text_size) +TEST(3) +{ + bd::GenericWriterOptions opt; + tl::CommandLineOptions cmd; + + opt.add_options (cmd); + + const char *argv[] = { + "x", + "--default-text-size=-1", + }; + + cmd.parse (sizeof (argv) / sizeof (argv[0]), const_cast (argv)); + + db::Layout layout; + + db::SaveLayoutOptions stream_opt; + EXPECT_EQ (stream_opt.get_option_by_name ("gds2_default_text_size").to_string (), "nil"); + opt.configure (stream_opt, layout); + EXPECT_EQ (stream_opt.get_option_by_name ("gds2_default_text_size").to_string (), "nil"); +} + static std::string cells2string (const db::Layout &layout, const std::set &cells) { std::string res; @@ -131,7 +179,7 @@ static std::string cells2string (const db::Layout &layout, const std::set A, B diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2.cc index 411db183a..f296c2204 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2.cc @@ -73,6 +73,7 @@ class GDS2FormatDeclaration tl::make_member (&db::GDS2WriterOptions::write_cell_properties, "write-cell-properties") + tl::make_member (&db::GDS2WriterOptions::write_file_properties, "write-file-properties") + tl::make_member (&db::GDS2WriterOptions::no_zero_length_paths, "no-zero-length-paths") + + tl::make_member (&db::GDS2WriterOptions::default_text_size, "default-text-size") + tl::make_member (&db::GDS2WriterOptions::multi_xy_records, "multi-xy-records") + tl::make_member (&db::GDS2WriterOptions::resolve_skew_arrays, "resolve-skew-arrays") + tl::make_member (&db::GDS2WriterOptions::max_vertex_count, "max-vertex-count") + diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2Format.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2Format.h index f17efbfbd..94a8419f6 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2Format.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2Format.h @@ -115,7 +115,8 @@ class DB_PLUGIN_PUBLIC GDS2WriterOptions user_units (1.0), write_timestamps (true), write_cell_properties (false), - write_file_properties (false) + write_file_properties (false), + default_text_size (-1.0) { // .. nothing yet .. } @@ -191,6 +192,14 @@ class DB_PLUGIN_PUBLIC GDS2WriterOptions */ bool write_file_properties; + /** + * @brief The default text size if none is given (in fact, if the text size is zero) + * + * You can set to option to 0 to preserve the zero text size on writing. + * A negative value means the text size is not set if missing. + */ + double default_text_size; + /** * @brief Implementation of FormatSpecificWriterOptions */ diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc index 6373f951f..50429eb08 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.cc @@ -155,7 +155,7 @@ static uint16_t safe_convert_to_uint16 (uint64_t value) GDS2WriterBase::GDS2WriterBase () : m_dbu (0.0), m_resolve_skew_arrays (false), m_multi_xy (false), m_no_zero_length_paths (false), - m_max_vertex_count (0), m_write_cell_properties (false), m_keep_instances (false) + m_max_vertex_count (0), m_write_cell_properties (false), m_keep_instances (false), m_default_text_size (-1.0) { // .. nothing yet .. } @@ -481,6 +481,7 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S m_no_zero_length_paths = gds2_options.no_zero_length_paths; m_resolve_skew_arrays = gds2_options.resolve_skew_arrays; m_write_cell_properties = gds2_options.write_cell_properties; + m_default_text_size = gds2_options.default_text_size; size_t max_cellname_length = std::max (gds2_options.max_cellname_length, (unsigned int)8); @@ -902,7 +903,7 @@ GDS2WriterBase::write_text (int layer, int datatype, double sf, double dbu, cons write_short (ha + va * 4 + f * 16); } - if (trans.rot () != 0 || shape.text_size () != 0) { + if (trans.rot () != 0 || shape.text_size () != 0 || m_default_text_size >= 0.0) { write_record_size (6); write_record (sSTRANS); @@ -912,6 +913,10 @@ GDS2WriterBase::write_text (int layer, int datatype, double sf, double dbu, cons write_record_size (4 + 8); write_record (sMAG); write_double (shape.text_size () * sf * dbu); + } else if (m_default_text_size >= 0.0) { + write_record_size (4 + 8); + write_record (sMAG); + write_double (m_default_text_size * sf); } if ((trans.rot () % 4) != 0) { diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h index 29c0deb37..ff1b2898c 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2WriterBase.h @@ -174,6 +174,7 @@ class DB_PLUGIN_PUBLIC GDS2WriterBase size_t m_max_vertex_count; bool m_write_cell_properties; bool m_keep_instances; + double m_default_text_size; void write_properties (const db::Layout &layout, db::properties_id_type prop_id); void write_context_cell (db::Layout &layout, const short *time_data, const std::vector &cells); diff --git a/src/plugins/streamers/gds2/db_plugin/gsiDeclDbGDS2.cc b/src/plugins/streamers/gds2/db_plugin/gsiDeclDbGDS2.cc index f68389709..3898ddb73 100644 --- a/src/plugins/streamers/gds2/db_plugin/gsiDeclDbGDS2.cc +++ b/src/plugins/streamers/gds2/db_plugin/gsiDeclDbGDS2.cc @@ -115,6 +115,17 @@ static bool get_gds2_write_timestamps (const db::SaveLayoutOptions *options) return options->get_options ().write_timestamps; } +static void set_gds2_default_text_size (db::SaveLayoutOptions *options, const tl::Variant &v) +{ + options->get_options ().default_text_size = v.is_nil () ? -1.0 : v.to_double (); +} + +static tl::Variant get_gds2_default_text_size (const db::SaveLayoutOptions *options) +{ + double ts = options->get_options ().default_text_size; + return ts < 0.0 ? tl::Variant () : tl::Variant (ts); +} + static void set_gds2_libname (db::SaveLayoutOptions *options, const std::string &n) { options->get_options ().libname = n; @@ -189,6 +200,22 @@ gsi::ClassExt gds2_writer_options ( "@brief Gets a value indicating whether the current time is written into the GDS2 timestamp fields\n" "\nThis property has been added in version 0.21.16.\n" ) + + gsi::method_ext ("gds2_default_text_size=", &set_gds2_default_text_size, gsi::arg ("size"), + "@brief Specifies the default text size to use when a text does not have a size\n" + "\n" + "Text object can have no size, e.g. when they are read from OASIS files. Technically such texts\n" + "are represented by text object with a zero size. You can configure the GDS writer to use a specific\n" + "text size in this case. This property specifies the default text size in micrometer units. This\n" + "size can be set to 0 to preserve a zero size in GDS files read.\n" + "\n" + "Set this attribute to nil to disable writing of a text size if none is specified.\n" + "\n" + "\nThis property has been added in version 0.30.4.\n" + ) + + gsi::method_ext ("gds2_default_text_size", &get_gds2_default_text_size, + "@brief Gets the default text size to use when a text does not have a size\n" + "\nThis property has been added in version 0.30.4.\n" + ) + gsi::method_ext ("gds2_no_zero_length_paths=", &set_gds2_no_zero_length_paths, gsi::arg ("flag"), "@brief Eliminates zero-length paths if true\n" "\n" diff --git a/src/plugins/streamers/gds2/lay_plugin/GDS2WriterOptionPage.ui b/src/plugins/streamers/gds2/lay_plugin/GDS2WriterOptionPage.ui index 72c6020f4..ac838890e 100644 --- a/src/plugins/streamers/gds2/lay_plugin/GDS2WriterOptionPage.ui +++ b/src/plugins/streamers/gds2/lay_plugin/GDS2WriterOptionPage.ui @@ -6,8 +6,8 @@ 0 0 - 656 - 315 + 673 + 360 @@ -50,12 +50,8 @@ 6 - - - - Write current time to time stamps (BGNLIB, BGNSTR) - - + + @@ -64,6 +60,16 @@ + + + + + + + Eliminate zero-length paths (convert to BOUNDARY) + + + @@ -71,10 +77,53 @@ - - + + + + Resolve skew (non-orthogonal) arrays into single instances + + - + + + + Write current time to time stamps (BGNLIB, BGNSTR) + + + + + + + Library name + + + + + + + Multi-XY record mode for boundaries +(enables infinitely large polygons/paths at the cost of compatibility) + + + + + + + (keep empty for unspecified limit) + + + + + + + Max. vertices + + + + + + + QFrame::NoFrame @@ -139,52 +188,20 @@ - - - - - - - (keep empty for unspecified limit) - - - - - - - Multi-XY record mode for boundaries -(enables infinitely large polygons/paths at the cost of compatibility) - - - - - - - Library name - - - - - - - Max. vertices - - - - - + + - - + + - Eliminate zero-length paths (convert to BOUNDARY) + Default text size - - + + - Resolve skew (non-orthogonal) arrays into single instances + µm (empty for no size) diff --git a/src/plugins/streamers/gds2/lay_plugin/layGDS2WriterPlugin.cc b/src/plugins/streamers/gds2/lay_plugin/layGDS2WriterPlugin.cc index ac4302cf5..760906cd1 100644 --- a/src/plugins/streamers/gds2/lay_plugin/layGDS2WriterPlugin.cc +++ b/src/plugins/streamers/gds2/lay_plugin/layGDS2WriterPlugin.cc @@ -65,6 +65,7 @@ GDS2WriterOptionPage::setup (const db::FormatSpecificWriterOptions *o, const db: mp_ui->max_vertex_le->setEnabled (! options->multi_xy_records); mp_ui->max_vertex_le->setText (tl::to_qstring (tl::to_string (options->max_vertex_count))); mp_ui->cell_name_length_le->setText (tl::to_qstring (tl::to_string (options->max_cellname_length))); + mp_ui->default_text_size_le->setText (tl::to_qstring (options->default_text_size >= 0.0 ? tl::to_string (options->default_text_size) : std::string ())); mp_ui->libname_le->setText (tl::to_qstring (tl::to_string (options->libname))); } } @@ -83,6 +84,19 @@ GDS2WriterOptionPage::commit (db::FormatSpecificWriterOptions *o, const db::Tech options->write_file_properties = mp_ui->write_file_properties->isChecked (); options->no_zero_length_paths = mp_ui->no_zero_length_paths->isChecked (); + std::string ts_str = tl::to_string (mp_ui->default_text_size_le->text ()); + { + double ts = -1; + tl::Extractor ex (ts_str.c_str ()); + if (! ex.at_end ()) { + tl::from_string_ext (ts_str, ts); + if (ts < 0.0) { + throw tl::Exception (tl::to_string (QObject::tr ("Default text size cannot be negative"))); + } + } + options->default_text_size = ts; + } + tl::from_string_ext (tl::to_string (mp_ui->max_vertex_le->text ()), n); if (! options->multi_xy_records) { if (n > 8191) { diff --git a/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc b/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc index c921fc242..1dda53c35 100644 --- a/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc +++ b/src/plugins/streamers/gds2/unit_tests/dbGDS2WriterTests.cc @@ -1509,6 +1509,66 @@ TEST(143) EXPECT_EQ (run_test_with_error (23.0, layout), "Scaling failed: coordinate underflow, writing layer 1/0, writing cell 'TOP'"); } +void run_text_size_test (tl::TestBase *_this, db::Coord size, double def_size, db::Coord exp_size) +{ + db::Layout layout; + db::cell_index_type top_index = layout.add_cell ("TOP"); + db::Cell &top = layout.cell (top_index); + unsigned int l1 = layout.insert_layer (db::LayerProperties (1, 0)); + db::Text text ("TEXT", db::Trans ()); + text.size (size); + top.shapes (l1).insert (text); + + db::GDS2WriterOptions opt; + opt.default_text_size = def_size; + + std::string tmp_file = _this->tmp_file ("tmp.gds"); + + { + tl::OutputStream stream (tmp_file); + db::SaveLayoutOptions options; + options.set_format ("GDS2"); + options.set_options (new db::GDS2WriterOptions (opt)); + db::Writer writer (options); + writer.write (layout, stream); + } + + db::Layout layout_read; + { + tl::InputStream file (tmp_file); + db::Reader reader (file); + reader.read (layout_read); + } + + l1 = layout_read.get_layer (db::LayerProperties (1, 0)); + const db::Cell &top_read = layout_read.cell (*layout_read.begin_top_down ()); + db::Shape text_read = *top_read.shapes (l1).begin (db::ShapeIterator::All); + + EXPECT_EQ (text_read.text_string (), "TEXT"); + EXPECT_EQ (text_read.text_size (), exp_size); +} + +// default text size +TEST(144a) +{ + run_text_size_test (_this, 0, 1.25, 1250); +} + +TEST(144b) +{ + run_text_size_test (_this, 500, 1.25, 500); +} + +TEST(144c) +{ + run_text_size_test (_this, 0, 0.0, 0); +} + +TEST(144d) +{ + run_text_size_test (_this, 0, -1.0, 0); +} + // Extreme fracturing by max. points TEST(166) { @@ -1518,4 +1578,3 @@ TEST(166) } - diff --git a/testdata/ruby/laySaveLayoutOptions.rb b/testdata/ruby/laySaveLayoutOptions.rb index 8ccbe7340..277edb7df 100644 --- a/testdata/ruby/laySaveLayoutOptions.rb +++ b/testdata/ruby/laySaveLayoutOptions.rb @@ -113,6 +113,14 @@ def test_1 opt.gds2_write_file_properties = false assert_equal(opt.gds2_write_file_properties?, false) + assert_equal(opt.gds2_default_text_size.inspect, "nil") + opt.gds2_default_text_size = nil + assert_equal(opt.gds2_default_text_size.inspect, "nil") + opt.gds2_default_text_size = -1.0 + assert_equal(opt.gds2_default_text_size.inspect, "nil") + opt.gds2_default_text_size = 1.0 + assert_equal(opt.gds2_default_text_size, 1.0) + opt.gds2_write_timestamps = true assert_equal(opt.gds2_write_timestamps?, true) opt.gds2_write_timestamps = false