From 0ea2610bf48f315a77681dbe9cbdb8c946e2f2b3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 25 Nov 2023 16:22:44 +0100 Subject: [PATCH 01/18] Reworking technology API a little: providing a way to register a new technology object, clarification of doc --- src/db/db/dbTechnology.cc | 29 +++++------ src/db/db/dbTechnology.h | 28 +++++++---- src/db/db/gsiDeclDbTechnologies.cc | 48 ++++++++++++++++--- src/lay/lay/layTechSetupDialog.cc | 19 +++----- src/lay/lay/layTechnologyController.cc | 10 ++-- src/rba/unit_tests/rbaTests.cc | 2 +- .../{layTechnologies.rb => dbTechnologies.rb} | 10 ++++ 7 files changed, 96 insertions(+), 50 deletions(-) rename testdata/ruby/{layTechnologies.rb => dbTechnologies.rb} (95%) diff --git a/src/db/db/dbTechnology.cc b/src/db/db/dbTechnology.cc index 2ed47818d..ad4eb63cf 100644 --- a/src/db/db/dbTechnology.cc +++ b/src/db/db/dbTechnology.cc @@ -80,7 +80,7 @@ Technologies::instance () static tl::XMLElementList xml_elements () { - return make_element ((Technologies::const_iterator (Technologies::*) () const) &Technologies::begin, (Technologies::const_iterator (Technologies::*) () const) &Technologies::end, &Technologies::add, "technology", + return make_element ((Technologies::const_iterator (Technologies::*) () const) &Technologies::begin, (Technologies::const_iterator (Technologies::*) () const) &Technologies::end, &Technologies::add_void, "technology", Technology::xml_elements () ); } @@ -92,7 +92,7 @@ Technologies::to_xml () const db::Technologies copy; for (const_iterator t = begin (); t != end (); ++t) { if (t->is_persisted ()) { - copy.add (new Technology (*t)); + copy.add (*t); } } @@ -110,7 +110,7 @@ Technologies::load_from_xml (const std::string &s) db::Technologies copy; for (const_iterator t = begin (); t != end (); ++t) { if (! t->is_persisted ()) { - copy.add (new Technology (*t)); + copy.add (*t); } } @@ -121,34 +121,31 @@ Technologies::load_from_xml (const std::string &s) *this = copy; } -void -Technologies::add_tech (Technology *tech, bool replace_same) +db::Technology * +Technologies::add_tech (const Technology &tech, bool replace_same) { - if (! tech) { - return; - } - - std::unique_ptr tech_ptr (tech); - Technology *t = 0; for (tl::stable_vector::iterator i = m_technologies.begin (); !t && i != m_technologies.end (); ++i) { - if (i->name () == tech->name ()) { + if (i->name () == tech.name ()) { t = i.operator-> (); } } if (t) { if (replace_same) { - *t = *tech; + *t = tech; } else { - throw tl::Exception (tl::to_string (tr ("A technology with this name already exists: ")) + tech->name ()); + throw tl::Exception (tl::to_string (tr ("A technology with this name already exists: ")) + tech.name ()); } } else { - m_technologies.push_back (tech_ptr.release ()); - tech->technology_changed_with_sender_event.add (this, &Technologies::technology_changed); + t = new Technology (tech); + m_technologies.push_back (t); + t->technology_changed_with_sender_event.add (this, &Technologies::technology_changed); } technologies_changed (); + + return t; } void diff --git a/src/db/db/dbTechnology.h b/src/db/db/dbTechnology.h index 9d68d93cf..9327b6d2d 100644 --- a/src/db/db/dbTechnology.h +++ b/src/db/db/dbTechnology.h @@ -121,24 +121,34 @@ public: /** * @brief Adds a technology to the setup * - * The container becomes owner of the technology object. - * Replaces a technology with the name of the given technology. + * @return A reference to the new Technology object + * + * If a technology with the given name already exists, it is replaced. */ - void add (Technology *technology) + db::Technology *add (const Technology &technology) { - add_tech (technology, true /*replace*/); + return add_tech (technology, true /*replace*/); } /** * @brief Adds a technology with a new name * + * @return A reference to the new Technology object + * * Like \add, but throws an exception if a technology with this name - * already exists. Takes over ownership over the technology object. - * The technology object is discarded if an exception is thrown. + * already exists. */ - void add_new (Technology *technology) + db::Technology *add_new (const Technology &technology) { - add_tech (technology, false /*throws exception on same name*/); + return add_tech (technology, false /*throws exception on same name*/); + } + + /** + * @brief Same as add, but no return value (for XML binding) + */ + void add_void (const Technology &technology) + { + add (technology); } /** @@ -244,7 +254,7 @@ private: bool m_changed; bool m_in_update; - void add_tech (Technology *technology, bool replace_same); + Technology *add_tech(const Technology &technology, bool replace_same); }; /** diff --git a/src/db/db/gsiDeclDbTechnologies.cc b/src/db/db/gsiDeclDbTechnologies.cc index 7b442971f..e9d045526 100644 --- a/src/db/db/gsiDeclDbTechnologies.cc +++ b/src/db/db/gsiDeclDbTechnologies.cc @@ -45,10 +45,14 @@ static db::Technology *technology_by_name (const std::string &name) static db::Technology *create_technology (const std::string &name) { - db::Technology *tech = new db::Technology (); - tech->set_name (name); - db::Technologies::instance ()->add_new (tech); - return tech; + db::Technology tech; + tech.set_name (name); + return db::Technologies::instance ()->add_new (tech); +} + +static db::Technology *register_technology (const db::Technology &tech) +{ + return db::Technologies::instance ()->add_new (tech); } static void remove_technology (const std::string &name) @@ -291,10 +295,24 @@ gsi::Class technology_decl ("db", "Technology", gsi::method ("create_technology", &create_technology, gsi::arg ("name"), "@brief Creates a new (empty) technology with the given name\n" "\n" + "The new technology is already registered in the system.\n" + "\n" "This method returns a reference to the new technology." ) + + gsi::method ("register_technology", ®ister_technology, gsi::arg ("tech"), + "@brief Registers a technology in the system\n" + "\n" + "Only after a technology is registered, it can be used in the system, e.g. by " + "specifying its name in \\Layout#technology_name. While \\create_technology already registers " + "the technology, this method allows registering a Technology object that has created in other ways.\n" + "\n" + "This method returns a reference to the new technology object which is a copy of the argument. " + "\\remove_technology can be used to remove a technology registered by this method.\n" + "\n" + "This method has been introduced in version 0.28.14." + ) + gsi::method ("remove_technology", &remove_technology, gsi::arg ("name"), - "@brief Removes the technology with the given name\n" + "@brief Removes the technology with the given name from the system\n" ) + gsi::method ("technologies_to_xml", &technologies_to_xml, "@brief Returns a XML representation of all technologies registered in the system\n" @@ -317,12 +335,13 @@ gsi::Class technology_decl ("db", "Technology", gsi::method ("technologies_from_xml", &technologies_from_xml, gsi::arg ("xml"), "@brief Loads the technologies from a XML representation\n" "\n" - "See \\technologies_to_xml for details. This method is the corresponding setter." + "See \\technologies_to_xml for details." ) + gsi::method ("technology_from_xml", &technology_from_xml, gsi::arg ("xml"), "@brief Loads the technology from a XML representation\n" "\n" - "See \\technology_to_xml for details." + "See \\technology_to_xml for details. Note that this function will create " + "a new Technology object which is not registered in the system. See \\Technology#register for details." ) + gsi::method_ext ("component_names", &get_component_names, "@brief Gets the names of all components available for \\component" @@ -338,6 +357,21 @@ gsi::Class technology_decl ("db", "Technology", "definitions are returned with \\technology_by_name. Use \\create_technology to register " "new technologies and \\remove_technology to delete technologies.\n" "\n" + "Note that a Technology object needs to be registered in the system, before its name " + "can be used to specify a technology, for example in \\Layout#technology_name. " + "Technology objects created by \\create_technology are automatically registered. " + "If you create a Technology object directly, you need to register it explicitly:" + "\n" + "@code\n" + "tech = RBA::Technology::new\n" + "tech.load(\"mytech.lyt\")\n" + "RBA::Technology::register(tech)\n" + "@/code\n" + "\n" + "Note that in the latter example, an exception will be thrown if a technology with the same " + "name already exists. Also note, that \\Technology#register will register a copy of the " + "object, so modifying it after registration will not have any effect.\n" + "\n" "The Technology class has been introduced in version 0.25.\n" ); diff --git a/src/lay/lay/layTechSetupDialog.cc b/src/lay/lay/layTechSetupDialog.cc index ae62c3ab4..8700a9416 100644 --- a/src/lay/lay/layTechSetupDialog.cc +++ b/src/lay/lay/layTechSetupDialog.cc @@ -775,13 +775,13 @@ BEGIN_PROTECTED } } - db::Technology *nt = new db::Technology (*t); + db::Technology nt (*t); - nt->set_tech_file_path (tl::to_string (tech_dir.absoluteFilePath (tn + QString::fromUtf8 (".lyt")))); - nt->set_default_base_path (tl::to_string (tech_dir.absolutePath ())); - nt->set_persisted (false); - nt->set_name (tl::to_string (tn)); - nt->set_description (std::string ()); + nt.set_tech_file_path (tl::to_string (tech_dir.absoluteFilePath (tn + QString::fromUtf8 (".lyt")))); + nt.set_default_base_path (tl::to_string (tech_dir.absolutePath ())); + nt.set_persisted (false); + nt.set_name (tl::to_string (tn)); + nt.set_description (std::string ()); m_technologies.add (nt); update_tech_tree (); @@ -900,12 +900,7 @@ BEGIN_PROTECTED db::Technology t; t.load (fn); - - if (m_technologies.has_technology (t.name ())) { - *m_technologies.technology_by_name (t.name ()) = t; - } else { - m_technologies.add (new db::Technology (t)); - } + m_technologies.add (t); update_tech_tree (); select_tech (*m_technologies.technology_by_name (t.name ())); diff --git a/src/lay/lay/layTechnologyController.cc b/src/lay/lay/layTechnologyController.cc index 212e2a7df..7fcfb0f85 100644 --- a/src/lay/lay/layTechnologyController.cc +++ b/src/lay/lay/layTechnologyController.cc @@ -536,7 +536,7 @@ TechnologyController::rescan (db::Technologies &technologies) technologies.clear (); for (db::Technologies::const_iterator t = current.begin (); t != current.end (); ++t) { if (t->is_persisted ()) { - technologies.add (new db::Technology (*t)); + technologies.add (*t); } } @@ -596,7 +596,7 @@ TechnologyController::rescan (db::Technologies &technologies) t.set_persisted (false); // don't save that one in the configuration t.set_readonly (readonly || ! QFileInfo (dir.filePath (*lf)).isWritable ()); t.set_grain_name (grain_name); - technologies.add (new db::Technology (t)); + technologies.add (t); } catch (tl::Exception &ex) { tl::warn << tl::to_string (QObject::tr ("Unable to auto-import technology file ")) << tl::to_string (*lf) << ": " << ex.msg (); @@ -608,14 +608,14 @@ TechnologyController::rescan (db::Technologies &technologies) for (std::vector::const_iterator t = m_temp_tech.begin (); t != m_temp_tech.end (); ++t) { - db::Technology *tech = new db::Technology (*t); if (tl::verbosity () >= 20) { - tl::info << "Registering special technology from " << tech->tech_file_path () << " as " << tech->name (); + tl::info << "Registering special technology from " << t->tech_file_path () << " as " << t->name (); } + + db::Technology *tech = technologies.add (*t); tech->set_persisted (false); // don't save that one in the configuration tech->set_tech_file_path (std::string ()); // don't save to a file either tech->set_readonly (true); // don't edit - technologies.add (tech); } } diff --git a/src/rba/unit_tests/rbaTests.cc b/src/rba/unit_tests/rbaTests.cc index ec0fcb24a..b5c5f4162 100644 --- a/src/rba/unit_tests/rbaTests.cc +++ b/src/rba/unit_tests/rbaTests.cc @@ -137,6 +137,7 @@ RUBYTEST (dbTilingProcessorTest, "dbTilingProcessorTest.rb") RUBYTEST (dbTransTest, "dbTransTest.rb") RUBYTEST (dbVectorTest, "dbVectorTest.rb") RUBYTEST (dbUtilsTests, "dbUtilsTests.rb") +RUBYTEST (dbTechnologies, "dbTechnologies.rb") RUBYTEST (edtTest, "edtTest.rb") RUBYTEST (extNetTracer, "extNetTracer.rb") RUBYTEST (imgObject, "imgObject.rb") @@ -147,7 +148,6 @@ RUBYTEST (layMacro, "layMacro.rb") RUBYTEST (layMenuTest, "layMenuTest.rb") RUBYTEST (layPixelBuffer, "layPixelBuffer.rb") RUBYTEST (laySession, "laySession.rb") -RUBYTEST (layTechnologies, "layTechnologies.rb") RUBYTEST (laySaveLayoutOptions, "laySaveLayoutOptions.rb") #if defined(HAVE_QT) && defined(HAVE_QTBINDINGS) RUBYTEST (qtbinding, "qtbinding.rb") diff --git a/testdata/ruby/layTechnologies.rb b/testdata/ruby/dbTechnologies.rb similarity index 95% rename from testdata/ruby/layTechnologies.rb rename to testdata/ruby/dbTechnologies.rb index 29ab17734..d4f6e9a66 100644 --- a/testdata/ruby/layTechnologies.rb +++ b/testdata/ruby/dbTechnologies.rb @@ -73,6 +73,16 @@ END RBA::Technology::remove_technology("MINE2") assert_equal(RBA::Technology::technology_names.inspect, '[""]') + # registration + tech = RBA::Technology::new + tech.name = "NEW" + tech.dbu = 0.5 + tech_new = RBA::Technology::register_technology(tech) + tech._destroy + assert_equal(RBA::Technology::technology_names.inspect, '["", "NEW"]') + assert_equal(tech_new.dbu, 0.5) + assert_equal(tech_new.name, "NEW") + end def test_2 From 0efdbd4ebea6f975f3ea6a0188adbbf7f2c74edf Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 26 Nov 2023 10:32:26 +0100 Subject: [PATCH 02/18] Doc updates --- src/db/db/gsiDeclDbTechnologies.cc | 4 +- src/doc/doc/programming/ruby_binding.xml | 55 ++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/db/db/gsiDeclDbTechnologies.cc b/src/db/db/gsiDeclDbTechnologies.cc index e9d045526..81bc2ca48 100644 --- a/src/db/db/gsiDeclDbTechnologies.cc +++ b/src/db/db/gsiDeclDbTechnologies.cc @@ -306,7 +306,7 @@ gsi::Class technology_decl ("db", "Technology", "specifying its name in \\Layout#technology_name. While \\create_technology already registers " "the technology, this method allows registering a Technology object that has created in other ways.\n" "\n" - "This method returns a reference to the new technology object which is a copy of the argument. " + "This method returns a reference to the new technology object, which is a copy of the argument. " "\\remove_technology can be used to remove a technology registered by this method.\n" "\n" "This method has been introduced in version 0.28.14." @@ -365,7 +365,7 @@ gsi::Class technology_decl ("db", "Technology", "@code\n" "tech = RBA::Technology::new\n" "tech.load(\"mytech.lyt\")\n" - "RBA::Technology::register(tech)\n" + "RBA::Technology::register_technology(tech)\n" "@/code\n" "\n" "Note that in the latter example, an exception will be thrown if a technology with the same " diff --git a/src/doc/doc/programming/ruby_binding.xml b/src/doc/doc/programming/ruby_binding.xml index 6ff93b20c..655f395de 100644 --- a/src/doc/doc/programming/ruby_binding.xml +++ b/src/doc/doc/programming/ruby_binding.xml @@ -408,6 +408,61 @@ A::new.f(x) omitted, the default value is used instead.

+

Implicit conversions

+ +

String arguments

+ +

+ If a method expects a string argument, other types are converted to strings + using the "to_s" method. In Python, the equivalent is "str(...)". +

+ +

+ Example: +

+ +
# Also accepts a float value for the first string argument - 
+# it is converted to "2.5"
+t = RBA::Text::new(2.5, RBA::Trans::new)
+ +

Conversion constructors

+ +

Conversion constructors are constructors that take an object of a +different class and convert it to the target class. +Conversion constructors are used implicitly in applicable cases +to convert one type to the type requested by the argument.

+ +

+ For example, in the following code, the Region object's "+" operator + is used. This expects a Region object as the second parameter, but as + there is conversion constructor available which converts a Box to + a Region, it is possible to use a Box directly: +

+ +
r = RBA::Region::new(RBA::Box::new(0, 0, 1000, 2000))
+r += RBA::Box::new(3000, 0, 4000, 2000)
+ +

Implicit constructor from lists

+ +

+ When an object is expected for an argument and a list is given, + the object constructor is called with the arguments from the list. + This specifically allows using size-2 lists instead of Point or + Vector arguments. In Python, a "list" can also be a tuple. +

+ +

+ In the following example, this mechanism is used for + the polygon point list which is expected to be an array + of Point objects, but can use size-2 arrays instead. + Also, the "moved" method expects a Vector, but here + as well, size-2 arrays can be used instead: +

+ +
pts = [ [ 0, 0 ], [ 0, 1000 ], [ 1000, 0 ] ]
+poly = RBA::Polygon::new(pts)
+poly = poly.moved([ 100, 200 ])
+

Constness

From 3dc3349d88ee05f367f4e9bc5929a74c5f3659a7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 1 Dec 2023 22:02:26 +0100 Subject: [PATCH 03/18] 'Trace all nets': provide a selection dialog for the stack. --- src/layui/layui/layNetlistBrowserDialog.cc | 8 +- src/layui/layui/layNetlistBrowserPage.cc | 4 +- .../lay_plugin/layNetTracerDialog.cc | 100 ++++++++++++++++-- .../lay_plugin/layNetTracerDialog.h | 1 + 4 files changed, 102 insertions(+), 11 deletions(-) diff --git a/src/layui/layui/layNetlistBrowserDialog.cc b/src/layui/layui/layNetlistBrowserDialog.cc index 9f393573a..10c798adb 100644 --- a/src/layui/layui/layNetlistBrowserDialog.cc +++ b/src/layui/layui/layNetlistBrowserDialog.cc @@ -677,7 +677,13 @@ NetlistBrowserDialog::l2ndbs_changed () for (unsigned int i = 0; i < view ()->num_l2ndbs (); ++i) { const db::LayoutToNetlist *l2ndb = view ()->get_l2ndb (i); - mp_ui->l2ndb_cb->addItem (tl::to_qstring (l2ndb->name ())); + std::string text = l2ndb->name (); + if (! l2ndb->description ().empty ()) { + text += " ("; + text += l2ndb->description (); + text += ")"; + } + mp_ui->l2ndb_cb->addItem (tl::to_qstring (text)); if (l2ndb->name () == m_l2ndb_name) { l2n_index = i; } diff --git a/src/layui/layui/layNetlistBrowserPage.cc b/src/layui/layui/layNetlistBrowserPage.cc index e8c3947ed..3c24089ae 100644 --- a/src/layui/layui/layNetlistBrowserPage.cc +++ b/src/layui/layui/layNetlistBrowserPage.cc @@ -1345,7 +1345,7 @@ bbox_for_circuit (const db::Layout *layout, const db::Circuit *circuit) void NetlistBrowserPage::adjust_view () { - if (! mp_database.get () || ! mp_view) { + if (! mp_database.get () || ! mp_database->netlist () || ! mp_view) { return; } @@ -1666,7 +1666,7 @@ NetlistBrowserPage::update_highlights () } clear_markers (); - if (! mp_database.get () || ! mp_view) { + if (! mp_database.get () || ! mp_database->netlist () || ! mp_view) { return; } diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc index 42c5c86b4..c3248abf6 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc @@ -348,10 +348,10 @@ END_PROTECTED } bool -NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerData &data) +NetTracerDialog::get_net_tracer_setup_from_tech (const std::string &tech_name, const std::string &stack_name, const db::Layout &layout, db::NetTracerData &data) { // fetch the net tracer data from the technology and apply to the current layout - const db::Technology *tech = cv->technology (); + const db::Technology *tech = db::Technologies::instance ()->technology_by_name (tech_name); if (! tech) { return false; } @@ -361,8 +361,6 @@ NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerDat return false; } - std::string stack_name = tl::to_string (stack_selector->itemData (stack_selector->currentIndex ()).toString ()); - const db::NetTracerConnectivity *connectivity = 0; for (auto d = tech_component->begin (); d != tech_component->end () && ! connectivity; ++d) { if (d->name () == stack_name) { @@ -375,10 +373,25 @@ NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerDat } // Set up the net tracer environment - data = connectivity->get_tracer_data (cv->layout ()); + data = connectivity->get_tracer_data (layout); return true; } +bool +NetTracerDialog::get_net_tracer_setup (const lay::CellView &cv, db::NetTracerData &data) +{ + // fetch the net tracer data from the technology and apply to the current layout + const db::Technology *tech = cv->technology (); + if (! tech) { + return false; + } + + const std::string &tech_name = tech->name (); + std::string stack_name = tl::to_string (stack_selector->itemData (stack_selector->currentIndex ()).toString ()); + + return get_net_tracer_setup_from_tech (tech_name, stack_name, cv->layout (), data); +} + db::NetTracerNet * NetTracerDialog::do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path) { @@ -652,11 +665,16 @@ NetTracerDialog::menu_activated (const std::string &symbol) const lay::CellView &cv = view ()->cellview (view ()->active_cellview_index ()); if (cv.is_valid ()) { + db::RecursiveShapeIterator si (cv->layout (), *cv.cell (), std::vector ()); std::unique_ptr l2ndb (new db::LayoutToNetlist (si)); trace_all_nets (l2ndb.get (), cv, flat); - unsigned int l2ndb_index = view ()->add_l2ndb (l2ndb.release ()); - view ()->open_l2ndb_browser (l2ndb_index, view ()->index_of_cellview (&cv)); + + if (l2ndb->netlist ()) { + unsigned int l2ndb_index = view ()->add_l2ndb (l2ndb.release ()); + view ()->open_l2ndb_browser (l2ndb_index, view ()->index_of_cellview (&cv)); + } + } } else { @@ -1781,13 +1799,79 @@ NetTracerDialog::clear_markers () void NetTracerDialog::trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView &cv, bool flat) { + const db::Technology *tech = cv->technology (); + if (! tech) { + return; + } + + static std::string current_stack; + + QStringList stacks; + std::vector raw_stacks; + int current = 0; + + const db::NetTracerTechnologyComponent *tech_component = dynamic_cast (tech->component_by_name (db::net_tracer_component_name ())); + if (tech_component) { + for (auto d = tech_component->begin (); d != tech_component->end (); ++d) { + raw_stacks.push_back (d->name ()); + if (d->name () == current_stack) { + current = stacks.size (); + } + if (d->name ().empty ()) { + stacks.push_back (tr ("(default)")); + } else { + stacks.push_back (tl::to_qstring (d->name ())); + } + } + } + + if (raw_stacks.empty ()) { + return; + } + + current_stack = raw_stacks.front (); + + if (stacks.size () >= 2) { + bool ok = true; + QString sel = QInputDialog::getItem (parentWidget (), tr ("Select Stack for Net Tracing (All Nets)"), tr ("Stack"), stacks, current, false, &ok); + if (! ok) { + return; + } + current = stacks.indexOf (sel); + if (current < 0) { + return; + } + current_stack = raw_stacks [current]; + } + db::NetTracerData tracer_data; - if (! get_net_tracer_setup (cv, tracer_data)) { + if (! get_net_tracer_setup_from_tech (tech->name (), current_stack, cv->layout (), tracer_data)) { return; } tracer_data.configure_l2n (*l2ndb); + std::string description = flat ? tl::to_string (tr ("Flat nets")) : tl::to_string (tr ("Hierarchical nets")); + std::string name = flat ? "Flat_Nets" : "Hierarchical_Nets"; + if (! tech->name ().empty ()) { + description += ", "; + description += tl::to_string (tr ("Technology")); + description += ": "; + description += tech->name (); + name += "_"; + name += tech->name (); + } + if (! current_stack.empty ()) { + description += ", "; + description += tl::to_string (tr ("Stack")); + description += ": "; + description += current_stack; + name += "_"; + name += current_stack; + } + l2ndb->set_description (description); + l2ndb->set_name (name); + l2ndb->clear_join_nets (); l2ndb->clear_join_net_names (); diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h index 8d304c0ba..61306de66 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.h @@ -127,6 +127,7 @@ private: void release_mouse (); db::NetTracerNet *do_trace (const db::DBox &start_search_box, const db::DBox &stop_search_box, bool trace_path); bool get_net_tracer_setup (const lay::CellView &cv, db::NetTracerData &data); + static bool get_net_tracer_setup_from_tech (const std::string &tech_name, const std::string &stack_name, const db::Layout &layout, db::NetTracerData &data); void trace_all_nets (db::LayoutToNetlist *l2ndb, const lay::CellView &cv, bool flat); lay::LayoutViewBase *view () From a9694b5fb36d047a60d7e33bcdf20d7152daf9ae Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 1 Dec 2023 22:18:29 +0100 Subject: [PATCH 04/18] Trace all nets: do not trace nets on symbols that are not used in connections --- src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc b/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc index 84738ddd8..776f6c07d 100644 --- a/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc +++ b/src/plugins/tools/net_tracer/db_plugin/dbNetTracer.cc @@ -378,8 +378,10 @@ NetTracerData::configure_l2n (db::LayoutToNetlist &l2n) // make all connections (intra and inter-layer) for (std::map >::const_iterator r = m_l2n_regions.begin (); r != m_l2n_regions.end (); ++r) { - l2n.connect (*r->second->get ()); const std::set &connections_to = log_connections (r->first); + if (! connections_to.empty ()) { + l2n.connect (*r->second->get ()); + } for (std::set::const_iterator c = connections_to.begin (); c != connections_to.end (); ++c) { std::map >::const_iterator rc = m_l2n_regions.find (*c); if (rc != m_l2n_regions.end ()) { From 832d29d2e01cf2014bbc0e99a06e3364fe9ef20d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 1 Dec 2023 22:24:49 +0100 Subject: [PATCH 05/18] Trace all nets: open the layer stack config dialog on the right screen --- src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc index c3248abf6..a3fba85bc 100644 --- a/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc +++ b/src/plugins/tools/net_tracer/lay_plugin/layNetTracerDialog.cc @@ -1337,7 +1337,7 @@ BEGIN_PROTECTED db::Technology tech = *db::Technologies::instance ()->technology_by_name (tech_name); // call the dialog and if successful, install the new technology - lay::TechComponentSetupDialog dialog (this, &tech, db::net_tracer_component_name ()); + lay::TechComponentSetupDialog dialog (isVisible () ? this : parentWidget (), &tech, db::net_tracer_component_name ()); if (dialog.exec ()) { *db::Technologies::instance ()->technology_by_name (tech.name ()) = tech; update_list_of_stacks (); From ebb35b1f2b0dd67bf2793194de0a9fdb50f9a6c5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 3 Dec 2023 16:51:53 +0100 Subject: [PATCH 06/18] Makes macro editor search feature less jumpy --- src/lay/lay/layMacroEditorDialog.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lay/lay/layMacroEditorDialog.cc b/src/lay/lay/layMacroEditorDialog.cc index 193de09cd..788a7a8e3 100644 --- a/src/lay/lay/layMacroEditorDialog.cc +++ b/src/lay/lay/layMacroEditorDialog.cc @@ -2092,7 +2092,6 @@ MacroEditorDialog::search_editing () } apply_search (); - page->find_reset (); // search from the initial position if (! page->has_multi_block_selection ()) { page->find_next (); } @@ -2119,7 +2118,6 @@ MacroEditorDialog::search_edited () } apply_search (); - page->find_reset (); // search from the initial position if (! page->has_multi_block_selection ()) { page->find_next (); } From 7b4a5c3878600a622db3f65f0efbc5a794f88b68 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 3 Dec 2023 17:22:48 +0100 Subject: [PATCH 07/18] More consistent behavior of Marker Browser / Scan Shapes * Scan Shapes Hierarchical will scan from current cell, not all cells * Marker browser shows markers propertly also in descended mode * Marker database description of shown in selection box --- src/layui/layui/rdbMarkerBrowserDialog.cc | 38 ++++++++++++++++++----- src/layui/layui/rdbMarkerBrowserPage.cc | 6 ++-- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/layui/layui/rdbMarkerBrowserDialog.cc b/src/layui/layui/rdbMarkerBrowserDialog.cc index ed0dd5c45..ccfa15386 100644 --- a/src/layui/layui/rdbMarkerBrowserDialog.cc +++ b/src/layui/layui/rdbMarkerBrowserDialog.cc @@ -582,7 +582,13 @@ MarkerBrowserDialog::rdbs_changed () for (unsigned int i = 0; i < view ()->num_rdbs (); ++i) { const rdb::Database *rdb = view ()->get_rdb (i); - mp_ui->rdb_cb->addItem (tl::to_qstring (rdb->name ())); + std::string text = rdb->name (); + if (! rdb->description ().empty ()) { + text += " ("; + text += rdb->description (); + text += ")"; + } + mp_ui->rdb_cb->addItem (tl::to_qstring (text)); if (rdb->name () == m_rdb_name) { rdb_index = i; } @@ -761,23 +767,35 @@ MarkerBrowserDialog::scan_layer () std::string desc; for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { - if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) { + if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) { if (! desc.empty ()) { desc += ", "; } desc += layout.get_properties ((*l)->layer_index ()).to_string (); } } - rdb->set_description ("Shapes of layer(s) " + desc); + desc = tl::to_string (tr ("Hierarchical shapes of layer(s) ")) + desc; + desc += " "; + desc += tl::to_string (tr ("from cell ")); + desc += cv->layout ().cell_name (cv.cell_index ()); + rdb->set_description (desc); + + std::set called_cells; + called_cells.insert (cv.cell_index ()); + cv->layout ().cell (cv.cell_index ()).collect_called_cells (called_cells); for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { - if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) { + if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) { - rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ()); + rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ()); for (db::Layout::const_iterator cid = layout.begin (); cid != layout.end (); ++cid) { + if (called_cells.find (cid->cell_index ()) == called_cells.end ()) { + continue; + } + const db::Cell &cell = *cid; if (cell.shapes ((*l)->layer_index ()).size () > 0) { @@ -855,18 +873,22 @@ MarkerBrowserDialog::scan_layer_flat () std::string desc; for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { - if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) { + if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) { if (! desc.empty ()) { desc += ", "; } desc += layout.get_properties ((*l)->layer_index ()).to_string (); } } - rdb->set_description ("Shapes of layer(s) " + desc); + desc = tl::to_string (tr ("Flat shapes of layer(s) ")) + desc; + desc += " "; + desc += tl::to_string (tr ("from cell ")); + desc += cv->layout ().cell_name (cv.cell_index ()); + rdb->set_description (desc); for (std::vector::const_iterator l = layers.begin (); l != layers.end (); ++l) { - if (!(*l)->has_children () && (*l)->cellview_index () >= 0 && layout.is_valid_layer ((*l)->layer_index ())) { + if (!(*l)->has_children () && (*l)->cellview_index () == cv_index && layout.is_valid_layer ((*l)->layer_index ())) { rdb::Category *cat = rdb->create_category (layout.get_properties ((*l)->layer_index ()).to_string ()); diff --git a/src/layui/layui/rdbMarkerBrowserPage.cc b/src/layui/layui/rdbMarkerBrowserPage.cc index 0b795ccab..0aff85df3 100644 --- a/src/layui/layui/rdbMarkerBrowserPage.cc +++ b/src/layui/layui/rdbMarkerBrowserPage.cc @@ -2148,7 +2148,7 @@ MarkerBrowserPage::do_update_markers () lay::CellView cv = mp_view->cellview (m_cv_index); if (! current_cell && cv.is_valid ()) { - current_cell = mp_database->cell_by_qname (cv->layout ().cell_name (cv.cell_index ())); + current_cell = mp_database->cell_by_qname (cv->layout ().cell_name (cv.ctx_cell_index ())); } std::vector tv = mp_view->cv_transform_variants (m_cv_index); @@ -2182,7 +2182,7 @@ MarkerBrowserPage::do_update_markers () // If we could not find a transformation in the RDB, try to find one in the layout DB: std::pair cc = cv->layout ().cell_by_name (c->name ().c_str ()); if (cc.first) { - std::pair ic = db::find_layout_context (cv->layout (), cc.second, cv.cell_index ()); + std::pair ic = db::find_layout_context (cv->layout (), cc.second, cv.ctx_cell_index ()); if (ic.first) { context.first = true; context.second = db::DCplxTrans (cv->layout ().dbu ()) * db::DCplxTrans (ic.second) * db::DCplxTrans (1.0 / cv->layout ().dbu ()); @@ -2197,7 +2197,7 @@ MarkerBrowserPage::do_update_markers () context = std::pair (true, db::DCplxTrans ()); } else if (! current_cell) { m_error_text = tl::sprintf (tl::to_string (QObject::tr ("Current layout cell '%s' not found in marker database and no path found from marker's cell '%s' to current cell in the layout database.")), - cv->layout ().cell_name (cv.cell_index ()), c->name ()); + cv->layout ().cell_name (cv.ctx_cell_index ()), c->name ()); } else { m_error_text = tl::sprintf (tl::to_string (QObject::tr ("No example instantiation given in marker database for marker's cell '%s' to current cell '%s' and no such path in the layout database either.")), c->name (), current_cell->name ()); From b701390e6afc38fdfbf47ba89ba7e27714ffcc2c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 3 Dec 2023 21:50:03 +0100 Subject: [PATCH 08/18] Enabling cheats for edges and (implicit) polygon merges DRC "cheats" have not been effective on "size" for example. Also they have not been effective at all for edges. --- src/db/db/dbDeepEdges.cc | 43 +++++--- src/db/db/dbDeepEdges.h | 5 +- src/db/db/dbDeepRegion.cc | 12 ++- src/db/db/dbDeepRegion.h | 1 + src/db/db/dbDeepShapeStore.cc | 43 ++++++-- src/db/db/dbDeepShapeStore.h | 17 ++- src/db/unit_tests/dbDeepEdgesTests.cc | 138 +++++++++++++++++++++++++ src/db/unit_tests/dbDeepRegionTests.cc | 95 +++++++++++++++++ 8 files changed, 324 insertions(+), 30 deletions(-) diff --git a/src/db/db/dbDeepEdges.cc b/src/db/db/dbDeepEdges.cc index 12b9a1774..d81032b0b 100644 --- a/src/db/db/dbDeepEdges.cc +++ b/src/db/db/dbDeepEdges.cc @@ -176,6 +176,7 @@ DeepEdges::~DeepEdges () DeepEdges::DeepEdges (const DeepEdges &other) : MutableEdges (other), DeepShapeCollectionDelegateBase (other), m_merged_edges_valid (other.m_merged_edges_valid), + m_merged_edges_boc_hash (other.m_merged_edges_boc_hash), m_is_merged (other.m_is_merged) { if (m_merged_edges_valid) { @@ -192,6 +193,7 @@ DeepEdges::operator= (const DeepEdges &other) DeepShapeCollectionDelegateBase::operator= (other); m_merged_edges_valid = other.m_merged_edges_valid; + m_merged_edges_boc_hash = other.m_merged_edges_boc_hash; m_is_merged = other.m_is_merged; if (m_merged_edges_valid) { m_merged_edges = other.m_merged_edges.copy (); @@ -205,6 +207,7 @@ DeepEdges::operator= (const DeepEdges &other) void DeepEdges::init () { m_merged_edges_valid = false; + m_merged_edges_boc_hash = 0; m_merged_edges = db::DeepLayer (); m_is_merged = false; } @@ -458,6 +461,7 @@ void DeepEdges::apply_property_translator (const db::PropertiesTranslator &pt) DeepShapeCollectionDelegateBase::apply_property_translator (pt); m_merged_edges_valid = false; + m_merged_edges_boc_hash = 0; m_merged_edges = db::DeepLayer (); } @@ -637,10 +641,16 @@ DeepEdges::merged_deep_layer () const } } +bool +DeepEdges::merged_edges_available () const +{ + return m_is_merged || (m_merged_edges_valid && m_merged_edges_boc_hash == deep_layer ().breakout_cells_hash ()); +} + void DeepEdges::ensure_merged_edges_valid () const { - if (! m_merged_edges_valid) { + if (! m_merged_edges_valid || (! m_is_merged && m_merged_edges_boc_hash != deep_layer ().breakout_cells_hash ())) { if (m_is_merged) { @@ -659,7 +669,7 @@ DeepEdges::ensure_merged_edges_valid () const db::Connectivity conn; conn.connect (deep_layer ()); hc.set_base_verbosity (base_verbosity() + 10); - hc.build (layout, deep_layer ().initial_cell (), conn); + hc.build (layout, deep_layer ().initial_cell (), conn, 0, deep_layer ().breakout_cells ()); // collect the clusters and merge them into larger edges // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is @@ -683,6 +693,7 @@ DeepEdges::ensure_merged_edges_valid () const } m_merged_edges_valid = true; + m_merged_edges_boc_hash = deep_layer ().breakout_cells_hash (); } } @@ -692,6 +703,7 @@ DeepEdges::set_is_merged (bool f) { m_is_merged = f; m_merged_edges_valid = false; + m_merged_edges_boc_hash = 0; m_merged_edges = db::DeepLayer (); } @@ -909,7 +921,7 @@ DeepEdges::and_or_not_with (const DeepEdges *other, EdgeBoolOp op) const db::EdgeBoolAndOrNotLocalOperation local_op (op); - db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (deep_layer ().store ()->threads ()); proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); @@ -936,7 +948,7 @@ DeepEdges::edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t mode, db::EdgeToPolygonLocalOperation op (mode, include_borders); - db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&deep_layer ().layout ()), const_cast (&deep_layer ().initial_cell ()), &other->deep_layer ().layout (), &other->deep_layer ().initial_cell (), deep_layer ().breakout_cells (), other->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (deep_layer ().store ()->threads ()); proc.set_area_ratio (deep_layer ().store ()->max_area_ratio ()); @@ -1253,7 +1265,6 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t std::unique_ptr res (new db::DeepRegion (edges.derived ())); db::Layout &layout = const_cast (edges.layout ()); - db::Cell &top_cell = const_cast (edges.initial_cell ()); // TODO: there is a special case when we'd need a MagnificationAndOrientationReducer: // dots formally don't have an orientation, hence the interpretation is x and y. @@ -1271,7 +1282,7 @@ RegionDelegate *DeepEdges::extended (coord_type ext_b, coord_type ext_e, coord_t db::Connectivity conn (db::Connectivity::EdgesConnectByPoints); conn.connect (edges); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, edges.initial_cell (), conn); + hc.build (layout, edges.initial_cell (), conn, 0, edges.breakout_cells ()); // TODO: iterate only over the called cells? for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { @@ -1714,7 +1725,7 @@ DeepEdges::selected_interacting_generic (const Region &other, EdgeInteractionMod db::Edge2PolygonInteractingLocalOperation op (mode, inverse ? db::Edge2PolygonInteractingLocalOperation::Inverse : db::Edge2PolygonInteractingLocalOperation::Normal); - db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); @@ -1746,7 +1757,7 @@ DeepEdges::selected_interacting_pair_generic (const Region &other, EdgeInteracti db::Edge2PolygonInteractingLocalOperation op (mode, db::Edge2PolygonInteractingLocalOperation::Both); - db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); @@ -1772,7 +1783,7 @@ DeepEdges::selected_interacting_generic (const Edges &other, EdgeInteractionMode db::Edge2EdgeInteractingLocalOperation op (mode, inverse ? db::Edge2EdgeInteractingLocalOperation::Inverse : db::Edge2EdgeInteractingLocalOperation::Normal); - db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); @@ -1804,7 +1815,7 @@ DeepEdges::selected_interacting_pair_generic (const Edges &other, EdgeInteractio db::Edge2EdgeInteractingLocalOperation op (mode, db::Edge2EdgeInteractingLocalOperation::Both); - db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); @@ -1830,7 +1841,7 @@ RegionDelegate *DeepEdges::pull_generic (const Region &other) const db::Edge2PolygonPullLocalOperation op; - db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell ()); + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_polygons.layout (), &other_polygons.initial_cell (), edges.breakout_cells (), other_polygons.breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); @@ -1856,7 +1867,7 @@ EdgesDelegate *DeepEdges::pull_generic (const Edges &other) const db::Edge2EdgePullLocalOperation op; - db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_edges.layout (), &other_edges.initial_cell ()); + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_edges.layout (), &other_edges.initial_cell (), edges.breakout_cells (), other_edges.breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); @@ -1885,7 +1896,7 @@ EdgesDelegate *DeepEdges::in (const Edges &other, bool invert) const db::ContainedEdgesLocalOperation op (invert ? Negative : Positive); - db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); @@ -1916,7 +1927,7 @@ std::pair DeepEdges::in_and_out (const Edges & db::ContainedEdgesLocalOperation op (PositiveAndNegative); - db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell ()); + db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), &other_deep->deep_layer ().layout (), &other_deep->deep_layer ().initial_cell (), edges.breakout_cells (), other_deep->deep_layer ().breakout_cells ()); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); @@ -2049,7 +2060,9 @@ DeepEdges::run_check (db::edge_relation_type rel, const Edges *other, db::Coord db::local_processor proc (const_cast (&edges.layout ()), const_cast (&edges.initial_cell ()), other_deep ? &other_deep->deep_layer ().layout () : const_cast (&edges.layout ()), - other_deep ? &other_deep->deep_layer ().initial_cell () : const_cast (&edges.initial_cell ())); + other_deep ? &other_deep->deep_layer ().initial_cell () : const_cast (&edges.initial_cell ()), + edges.breakout_cells (), + other_deep ? other_deep->deep_layer ().breakout_cells () : 0); proc.set_base_verbosity (base_verbosity ()); proc.set_threads (edges.store ()->threads ()); diff --git a/src/db/db/dbDeepEdges.h b/src/db/db/dbDeepEdges.h index 78fb04935..bdd7ea947 100644 --- a/src/db/db/dbDeepEdges.h +++ b/src/db/db/dbDeepEdges.h @@ -170,6 +170,9 @@ public: void set_is_merged (bool f); + bool merged_edges_available () const; + const DeepLayer &merged_deep_layer () const; + protected: virtual void merged_semantics_changed (); @@ -180,11 +183,11 @@ private: mutable DeepLayer m_merged_edges; mutable bool m_merged_edges_valid; + mutable size_t m_merged_edges_boc_hash; bool m_is_merged; void init (); void ensure_merged_edges_valid () const; - const DeepLayer &merged_deep_layer () const; DeepLayer and_or_not_with(const DeepEdges *other, EdgeBoolOp op) const; std::pair edge_region_op (const DeepRegion *other, EdgePolygonOp::mode_t op, bool include_borders) const; EdgePairsDelegate *run_check (db::edge_relation_type rel, const Edges *other, db::Coord d, const db::EdgesCheckOptions &options) const; diff --git a/src/db/db/dbDeepRegion.cc b/src/db/db/dbDeepRegion.cc index b6e04023a..11780bfd6 100644 --- a/src/db/db/dbDeepRegion.cc +++ b/src/db/db/dbDeepRegion.cc @@ -179,6 +179,7 @@ DeepRegion::~DeepRegion () DeepRegion::DeepRegion (const DeepRegion &other) : MutableRegion (other), DeepShapeCollectionDelegateBase (other), m_merged_polygons_valid (other.m_merged_polygons_valid), + m_merged_polygons_boc_hash (other.m_merged_polygons_boc_hash), m_is_merged (other.m_is_merged) { if (m_merged_polygons_valid) { @@ -195,6 +196,7 @@ DeepRegion::operator= (const DeepRegion &other) DeepShapeCollectionDelegateBase::operator= (other); m_merged_polygons_valid = other.m_merged_polygons_valid; + m_merged_polygons_boc_hash = other.m_merged_polygons_boc_hash; m_is_merged = other.m_is_merged; if (m_merged_polygons_valid) { m_merged_polygons = other.m_merged_polygons.copy (); @@ -208,6 +210,7 @@ DeepRegion::operator= (const DeepRegion &other) void DeepRegion::init () { m_merged_polygons_valid = false; + m_merged_polygons_boc_hash = 0; m_merged_polygons = db::DeepLayer (); m_is_merged = false; } @@ -484,6 +487,7 @@ void DeepRegion::apply_property_translator (const db::PropertiesTranslator &pt) DeepShapeCollectionDelegateBase::apply_property_translator (pt); m_merged_polygons_valid = false; + m_merged_polygons_boc_hash = 0; m_merged_polygons = db::DeepLayer (); } @@ -683,13 +687,13 @@ DeepRegion::merged_deep_layer () const bool DeepRegion::merged_polygons_available () const { - return m_is_merged || m_merged_polygons_valid; + return m_is_merged || (m_merged_polygons_valid && m_merged_polygons_boc_hash == deep_layer ().breakout_cells_hash ()); } void DeepRegion::ensure_merged_polygons_valid () const { - if (! m_merged_polygons_valid) { + if (! m_merged_polygons_valid || (! m_is_merged && m_merged_polygons_boc_hash != deep_layer ().breakout_cells_hash ())) { if (m_is_merged) { @@ -708,7 +712,7 @@ DeepRegion::ensure_merged_polygons_valid () const db::Connectivity conn; conn.connect (deep_layer ()); hc.set_base_verbosity (base_verbosity () + 10); - hc.build (layout, deep_layer ().initial_cell (), conn, 0, 0, true /*separate_attributes*/); + hc.build (layout, deep_layer ().initial_cell (), conn, 0, deep_layer ().breakout_cells (), true /*separate_attributes*/); // collect the clusters and merge them into big polygons // NOTE: using the ClusterMerger we merge bottom-up forming bigger and bigger polygons. This is @@ -732,6 +736,7 @@ DeepRegion::ensure_merged_polygons_valid () const } m_merged_polygons_valid = true; + m_merged_polygons_boc_hash = deep_layer ().breakout_cells_hash (); } } @@ -741,6 +746,7 @@ DeepRegion::set_is_merged (bool f) { m_is_merged = f; m_merged_polygons_valid = false; + m_merged_polygons_boc_hash = 0; m_merged_polygons = db::DeepLayer (); } diff --git a/src/db/db/dbDeepRegion.h b/src/db/db/dbDeepRegion.h index df40fec49..cc05259b7 100644 --- a/src/db/db/dbDeepRegion.h +++ b/src/db/db/dbDeepRegion.h @@ -173,6 +173,7 @@ private: mutable DeepLayer m_merged_polygons; mutable bool m_merged_polygons_valid; + mutable size_t m_merged_polygons_boc_hash; bool m_is_merged; void init (); diff --git a/src/db/db/dbDeepShapeStore.cc b/src/db/db/dbDeepShapeStore.cc index 81ff9c327..70005e136 100644 --- a/src/db/db/dbDeepShapeStore.cc +++ b/src/db/db/dbDeepShapeStore.cc @@ -184,6 +184,12 @@ DeepLayer::breakout_cells () const return store ()->breakout_cells (layout_index ()); } +size_t +DeepLayer::breakout_cells_hash () const +{ + return store ()->breakout_cells_hash (layout_index ()); +} + void DeepLayer::insert_into (db::Layout *into_layout, db::cell_index_type into_cell, unsigned int into_layer) const { @@ -409,36 +415,51 @@ DeepShapeStoreState::text_property_name () const const std::set * DeepShapeStoreState::breakout_cells (unsigned int layout_index) const { - const std::set &boc = (const_cast (this))->ensure_breakout_cells (layout_index); - if (boc.empty ()) { + const std::pair, size_t> &boc = (const_cast (this))->ensure_breakout_cells (layout_index); + if (boc.first.empty ()) { return 0; } else { - return &boc; + return &boc.first; } } +size_t +DeepShapeStoreState::breakout_cells_hash (unsigned int layout_index) const +{ + const std::pair, size_t> &boc = (const_cast (this))->ensure_breakout_cells (layout_index); + return boc.second; +} + void DeepShapeStoreState::clear_breakout_cells (unsigned int layout_index) { - ensure_breakout_cells (layout_index).clear (); + std::pair, size_t> &boc = ensure_breakout_cells (layout_index); + boc.first.clear (); + boc.second = std::hash >() (boc.first); } void -DeepShapeStoreState::set_breakout_cells (unsigned int layout_index, const std::set &boc) +DeepShapeStoreState::set_breakout_cells (unsigned int layout_index, const std::set &boc_in) { - ensure_breakout_cells (layout_index) = boc; + std::pair, size_t> &boc = ensure_breakout_cells (layout_index); + boc.first = boc_in; + boc.second = std::hash >() (boc.first); } void DeepShapeStoreState::add_breakout_cell (unsigned int layout_index, db::cell_index_type ci) { - ensure_breakout_cells (layout_index).insert (ci); + std::pair, size_t> &boc = ensure_breakout_cells (layout_index); + boc.first.insert (ci); + boc.second = std::hash >() (boc.first); } void DeepShapeStoreState::add_breakout_cells (unsigned int layout_index, const std::set &cc) { - ensure_breakout_cells (layout_index).insert (cc.begin (), cc.end ()); + std::pair, size_t> &boc = ensure_breakout_cells (layout_index); + boc.first.insert (cc.begin (), cc.end ()); + boc.second = std::hash >() (boc.first); } void @@ -726,6 +747,12 @@ DeepShapeStore::breakout_cells (unsigned int layout_index) const return m_state.breakout_cells (layout_index); } +size_t +DeepShapeStore::breakout_cells_hash (unsigned int layout_index) const +{ + return m_state.breakout_cells_hash (layout_index); +} + void DeepShapeStore::clear_breakout_cells (unsigned int layout_index) { diff --git a/src/db/db/dbDeepShapeStore.h b/src/db/db/dbDeepShapeStore.h index 1e6e0aaaa..ab2f2336b 100644 --- a/src/db/db/dbDeepShapeStore.h +++ b/src/db/db/dbDeepShapeStore.h @@ -165,6 +165,11 @@ public: */ const std::set *breakout_cells () const; + /** + * @brief Gets a hash value representing the breakout cells + */ + size_t breakout_cells_hash () const; + /** * @brief Inserts the layer into the given layout, starting from the given cell and into the given layer */ @@ -251,6 +256,7 @@ public: bool reject_odd_polygons () const; const std::set *breakout_cells (unsigned int layout_index) const; + size_t breakout_cells_hash (unsigned int layout_index) const; void clear_breakout_cells (unsigned int layout_index); void set_breakout_cells (unsigned int layout_index, const std::set &boc); void add_breakout_cell (unsigned int layout_index, db::cell_index_type ci); @@ -265,14 +271,14 @@ private: size_t m_max_vertex_count; bool m_reject_odd_polygons; tl::Variant m_text_property_name; - std::vector > m_breakout_cells; + std::vector, size_t> > m_breakout_cells; int m_text_enlargement; bool m_subcircuit_hierarchy_for_nets; - std::set &ensure_breakout_cells (unsigned int layout_index) + std::pair, size_t> &ensure_breakout_cells (unsigned int layout_index) { if (m_breakout_cells.size () <= size_t (layout_index)) { - m_breakout_cells.resize (layout_index + 1, std::set ()); + m_breakout_cells.resize (layout_index + 1, std::pair, size_t> ()); } return m_breakout_cells [layout_index]; } @@ -782,6 +788,11 @@ public: */ const std::set *breakout_cells (unsigned int layout_index) const; + /** + * @brief Gets a hash value representing the breakout cells + */ + size_t breakout_cells_hash (unsigned int layout_index) const; + /** * @brief Clears the breakout cell list for a given layout */ diff --git a/src/db/unit_tests/dbDeepEdgesTests.cc b/src/db/unit_tests/dbDeepEdgesTests.cc index fae54490e..783ceb326 100644 --- a/src/db/unit_tests/dbDeepEdgesTests.cc +++ b/src/db/unit_tests/dbDeepEdgesTests.cc @@ -29,6 +29,7 @@ #include "dbEdgesUtils.h" #include "dbDeepShapeStore.h" #include "dbCellGraphUtils.h" +#include "dbDeepEdges.h" #include "tlUnitTest.h" #include "tlStream.h" @@ -1292,3 +1293,140 @@ TEST(20_in_and_out) db::compare_layouts (_this, target, tl::testdata () + "/algo/deep_edges_au20.gds"); } +TEST(deep_edges_and_cheats) +{ + db::Layout ly; + { + std::string fn (tl::testdata ()); + fn += "/algo/cheats.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l10 = ly.get_layer (db::LayerProperties (10, 0)); + unsigned int l11 = ly.get_layer (db::LayerProperties (11, 0)); + unsigned int l12 = ly.get_layer (db::LayerProperties (12, 0)); + unsigned int l13 = ly.get_layer (db::LayerProperties (13, 0)); + unsigned int l14 = ly.get_layer (db::LayerProperties (14, 0)); + unsigned int l19 = ly.get_layer (db::LayerProperties (19, 0)); + unsigned int l20 = ly.get_layer (db::LayerProperties (20, 0)); + unsigned int l21 = ly.get_layer (db::LayerProperties (21, 0)); + unsigned int l22 = ly.get_layer (db::LayerProperties (22, 0)); + unsigned int l23 = ly.get_layer (db::LayerProperties (23, 0)); + unsigned int l24 = ly.get_layer (db::LayerProperties (24, 0)); + unsigned int l29 = ly.get_layer (db::LayerProperties (29, 0)); + unsigned int l30 = ly.get_layer (db::LayerProperties (30, 0)); + unsigned int l31 = ly.get_layer (db::LayerProperties (31, 0)); + unsigned int l32 = ly.get_layer (db::LayerProperties (32, 0)); + unsigned int l33 = ly.get_layer (db::LayerProperties (33, 0)); + unsigned int l34 = ly.get_layer (db::LayerProperties (34, 0)); + unsigned int l39 = ly.get_layer (db::LayerProperties (39, 0)); + + db::DeepShapeStore dss; + + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss); + db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + + (r1.edges () - r2).insert_into (&ly, top_cell_index, l10); + + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second); + + (r1.edges () - r2).insert_into (&ly, top_cell_index, l11); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second); + + (r1.edges () - r2).insert_into (&ly, top_cell_index, l12); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second); + + (r1.edges () - r2).insert_into (&ly, top_cell_index, l13); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second); + + (r1.edges () - r2).insert_into (&ly, top_cell_index, l14); + + dss.clear_breakout_cells (0); + (r1.edges () - r2).insert_into (&ly, top_cell_index, l19); + + (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l20); + + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second); + + (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l21); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second); + + (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l22); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second); + + (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l23); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second); + + (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l24); + + dss.clear_breakout_cells (0); + (r1.edges () - r2.edges ()).insert_into (&ly, top_cell_index, l29); + + db::Region eo; + db::Edges e1; + + e1 = r2.edges (); + e1.extended (eo, 0, 0, 500, 0); + eo.insert_into (&ly, top_cell_index, l30); + EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true); + + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second); + + e1 = r2.edges (); + e1.extended (eo, 0, 0, 500, 0); + eo.insert_into (&ly, top_cell_index, l31); + EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second); + + e1 = r2.edges (); + e1.extended (eo, 0, 0, 500, 0); + eo.insert_into (&ly, top_cell_index, l32); + EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second); + + e1 = r2.edges (); + e1.extended (eo, 0, 0, 500, 0); + eo.insert_into (&ly, top_cell_index, l33); + EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second); + + e1 = r2.edges (); + e1.extended (eo, 0, 0, 500, 0); + eo.insert_into (&ly, top_cell_index, l34); + EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true); + + dss.clear_breakout_cells (0); + + e1 = r2.edges (); + e1.extended (eo, 0, 0, 500, 0); + eo.insert_into (&ly, top_cell_index, l39); + EXPECT_EQ (dynamic_cast (e1.delegate ())->merged_edges_available (), true); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testdata () + "/algo/cheats_edges_au.gds"); +} diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 5bdeaadd3..3583dc279 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -30,6 +30,7 @@ #include "dbRegionProcessors.h" #include "dbEdgesUtils.h" #include "dbDeepShapeStore.h" +#include "dbDeepRegion.h" #include "dbOriginalLayerRegion.h" #include "dbCellGraphUtils.h" #include "dbTestSupport.h" @@ -2846,3 +2847,97 @@ TEST(issue_663_separation_from_inside) CHECKPOINT(); db::compare_layouts (_this, ly, tl::testdata () + "/algo/deep_region_au663.gds"); } + +TEST(deep_region_and_cheats) +{ + db::Layout ly; + { + std::string fn (tl::testdata ()); + fn += "/algo/cheats.gds"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (ly); + } + + db::cell_index_type top_cell_index = *ly.begin_top_down (); + db::Cell &top_cell = ly.cell (top_cell_index); + + unsigned int l1 = ly.get_layer (db::LayerProperties (1, 0)); + unsigned int l2 = ly.get_layer (db::LayerProperties (2, 0)); + unsigned int l10 = ly.get_layer (db::LayerProperties (10, 0)); + unsigned int l11 = ly.get_layer (db::LayerProperties (11, 0)); + unsigned int l12 = ly.get_layer (db::LayerProperties (12, 0)); + unsigned int l13 = ly.get_layer (db::LayerProperties (13, 0)); + unsigned int l14 = ly.get_layer (db::LayerProperties (14, 0)); + unsigned int l19 = ly.get_layer (db::LayerProperties (19, 0)); + unsigned int l20 = ly.get_layer (db::LayerProperties (20, 0)); + unsigned int l21 = ly.get_layer (db::LayerProperties (21, 0)); + unsigned int l22 = ly.get_layer (db::LayerProperties (22, 0)); + unsigned int l23 = ly.get_layer (db::LayerProperties (23, 0)); + unsigned int l24 = ly.get_layer (db::LayerProperties (24, 0)); + unsigned int l29 = ly.get_layer (db::LayerProperties (29, 0)); + + db::DeepShapeStore dss; + + db::Region r1 (db::RecursiveShapeIterator (ly, top_cell, l1), dss); + db::Region r2 (db::RecursiveShapeIterator (ly, top_cell, l2), dss); + + (r1 - r2).insert_into (&ly, top_cell_index, l10); + + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second); + + (r1 - r2).insert_into (&ly, top_cell_index, l11); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second); + + (r1 - r2).insert_into (&ly, top_cell_index, l12); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second); + + (r1 - r2).insert_into (&ly, top_cell_index, l13); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second); + + (r1 - r2).insert_into (&ly, top_cell_index, l14); + + dss.clear_breakout_cells (0); + (r1 - r2).insert_into (&ly, top_cell_index, l19); + + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), false); + + r1.sized (-1000).insert_into (&ly, top_cell_index, l20); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("A").second); + + r1.sized (-1000).insert_into (&ly, top_cell_index, l21); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("B").second); + + r1.sized (-1000).insert_into (&ly, top_cell_index, l22); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("C").second); + + r1.sized (-1000).insert_into (&ly, top_cell_index, l23); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + dss.clear_breakout_cells (0); + dss.add_breakout_cell (0, dss.layout (0).cell_by_name ("D").second); + + r1.sized (-1000).insert_into (&ly, top_cell_index, l24); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + dss.clear_breakout_cells (0); + r1.sized (-1000).insert_into (&ly, top_cell_index, l29); + EXPECT_EQ (dynamic_cast (r1.delegate ())->merged_polygons_available (), true); + + CHECKPOINT(); + db::compare_layouts (_this, ly, tl::testdata () + "/algo/cheats_au.gds"); +} From ea039bf4bb95665d0bcba4cc721f68acb25e6f8d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 5 Dec 2023 21:33:08 +0100 Subject: [PATCH 09/18] Added missing files --- testdata/algo/cheats.gds | Bin 0 -> 702 bytes testdata/algo/cheats_au.gds | Bin 0 -> 2622 bytes testdata/algo/cheats_edges_au.gds | Bin 0 -> 7638 bytes testdata/drc/cheats.gds | Bin 0 -> 702 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 testdata/algo/cheats.gds create mode 100644 testdata/algo/cheats_au.gds create mode 100644 testdata/algo/cheats_edges_au.gds create mode 100644 testdata/drc/cheats.gds diff --git a/testdata/algo/cheats.gds b/testdata/algo/cheats.gds new file mode 100644 index 0000000000000000000000000000000000000000..4563489f95e2572ae111cb4e4a8293042d377123 GIT binary patch literal 702 zcmZQzV_;&6V31*CVt>xS!@$fS!l1z*fy`#$U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLR zXF}J{`~spjD*WEZ%}Ks#`lj4T5*9mzL988#_Kplv)dtWHs2d$E{;E9UebKy(MTFmWJFO!#oHv4!{t!2JRA5fT0X+6Ob6g@pkCFPk;j literal 0 HcmV?d00001 diff --git a/testdata/algo/cheats_au.gds b/testdata/algo/cheats_au.gds new file mode 100644 index 0000000000000000000000000000000000000000..a55ec86c51971d3d68edfd7a111dfaae3d56192a GIT binary patch literal 2622 zcmb_dOG*Pl5UtFoGsH=ZCVtR(06`R7D1r!yK@bI9xR9K}rAN>+xXI3~OHUvk!<{Z% zc!OA#o)@cU7{^R(XkV!AH?OPfRZE6E@0vOluli0g`P8OO3iWS_Jac~9BWnBMQTKlT z?B((6p#Quxd>C9&C(P#=W4c5^L}cn7Rme0vBHC*D{8x>Y8>0Ck5l}4!3qO1>&G$d- z&ek2#+%pjnaYoHw(tO#22_6vf6u+hUqAdGm;M_pO8MS_fZ`t-7lE3H*s-gLf8TB)K z=s*{UIHT6D�f_LkGG*#8dk5jQSZqbf61FJf%OE=%1(kD?ITZP}P6@Dfj}I^ZnY4 z`DOUfL0&+_8OQalQc)Lk?*}#R;zjA_Smi(FyDM@N_;O@Be_3ZHr@)k(l3M{H&ZwQ| zR8IEGKJeDBEng6E@QX7$o@B;3=46HyQA}mF@>^!xZ}wz@a{C2 bqP%8bg}o<>-~kb5)aPmc*LnEvf`GmOM3o~i literal 0 HcmV?d00001 diff --git a/testdata/algo/cheats_edges_au.gds b/testdata/algo/cheats_edges_au.gds new file mode 100644 index 0000000000000000000000000000000000000000..cf9f6e068b79c0af92733f47be997aaf048172ad GIT binary patch literal 7638 zcmbuDyKdD$5QgXYoH&Q%Bmt6;0O1lE8Uzsqmj)>zLgFGpks?aX15i@r0idI&Nk>CL znI}Lz01rS%3JMBJgxT?We8y|fzqYedJki>p|C#aZ>?V{_lI+vQAesG16B^PgZPBd$ zoyJM};^_|2%5dh<_WS$Kzkd4taQFDm(Z_>5+L*DqG)=dOMq{FMA)x`KiwP0kIy-b% zHP+q`EgcbwRkudxrhF3e!xR7H@;jpWV6wq3=wNy+LeB}sb#04nul>x;b z8ebVu;Co%Lv(b+NnP2Or1*j&iqL*ANw8~y0SzA5yy+EwYJDb;W6VJVadxrFoh0p#g zu$6hKmnNS59Q@&H<@x-5GViRRpJo3h%z3N)E#4>hJwHpaj_dmLXwG%K^W1wUs=MX- z)jJ%q8y!}-_!smb&`olM;v!irIx?Ux@B41T)(!0;sA+!G@GwF#$s_O(P)!~d)p31V zo$~eCecd|mv%pozJ&0qw_1uT|FS=oM$E)*k zS)Hy#x|fLJBeh$>1nM9m8-am%HQ-(v2!s*wun^`%kYGu6Ux`Km3Yf%X!@TKDE5kiu-znR(Q^$ ztVH#E&dGeR|I~Q-e%u*YPpr&4tMxZe8NcGo_;THr@mKgB@z;2XQ{omY^FjPKP8q-A zd&OVjd&FPkB~FQ3tjq`T-#lgfitiPFh3^r6jh8qjZm}{i@yB<#-ExO>d!4bv={vIP z_>-BtlU^FQh$b5|I|m$@8@0C-U1%`<3jRS}xjeW_>K~bRR_}0NH}&tyvcK#3Z>^{- z`}LNe&a#sa?WvllEw#Lc*K)D8qP$k_o4;rZ{C^XmHp;TH{sX%dv*xVT3X~j8NS@l=Z}(2AK!@6^JWB8F57@BQCIq01qRS;bDX_JOteZ mco?A!4xS!@$fS!l1z*fy`#$U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLR zXF}J{`~spjD*WEZ%}Ks#`lj4T5*9mzL988#_Kplv)dtWHs2d$E{;E9UebKy(MTFmWJFO!#oHv4!{t!2JRA5fT0X+6Ob6g@pkCFPk;j literal 0 HcmV?d00001 From ce77909c3f0d9b6b3c5f8099883fa8d86131472c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 5 Dec 2023 21:13:03 +0100 Subject: [PATCH 10/18] Include proxy in Git configuration Follows the suggestion from there: https://www.klayout.de/forum/discussion/2404. Using $KLAYOUT_GIT_HTTP_PROXY so it does not interfere with curl. --- src/tl/tl/tlGit.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/tl/tl/tlGit.cc b/src/tl/tl/tlGit.cc index 851e8fcd1..118b1d188 100644 --- a/src/tl/tl/tlGit.cc +++ b/src/tl/tl/tlGit.cc @@ -27,6 +27,7 @@ #include "tlProgress.h" #include "tlStaticObjects.h" #include "tlLog.h" +#include "tlEnv.h" #include #include @@ -314,6 +315,16 @@ GitObject::read (const std::string &org_url, const std::string &org_filter, cons fetch_opts.callbacks.credentials = &credentials_cb; fetch_opts.callbacks.payload = (void *) &progress; + // get proxy configuration from environment variable if available + // (see https://www.klayout.de/forum/discussion/2404) + + std::string http_proxy = tl::get_env ("KLAYOUT_GIT_HTTP_PROXY"); + + if (! http_proxy.empty ()) { + fetch_opts.proxy_opts.type = GIT_PROXY_SPECIFIED; + fetch_opts.proxy_opts.url = http_proxy.c_str (); + } + // build refspecs in case they are needed char *refs[] = { (char *) branch.c_str () }; From d5f484bf9249bd0e2339a1a608416ff6460a493a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Tue, 5 Dec 2023 22:09:57 +0100 Subject: [PATCH 11/18] Added EdgePair#distance --- src/db/db/gsiDeclDbEdgePair.cc | 8 ++++++++ testdata/ruby/dbEdgePairTest.rb | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/db/db/gsiDeclDbEdgePair.cc b/src/db/db/gsiDeclDbEdgePair.cc index 3d90abefe..4fb90d763 100644 --- a/src/db/db/gsiDeclDbEdgePair.cc +++ b/src/db/db/gsiDeclDbEdgePair.cc @@ -169,6 +169,14 @@ struct edge_pair_defs method ("bbox", &C::bbox, "@brief Gets the bounding box of the edge pair\n" ) + + method ("distance", &C::distance, + "@brief Gets the distance of the edges in the edge pair\n" + "\n" + "The distance between the two edges is defined as the minimum distance between any " + "two points on the two edges.\n" + "\n" + "This attribute has been introduced in version 0.28.14." + ) + method ("perimeter", &C::perimeter, "@brief Gets the perimeter of the edge pair\n" "\n" diff --git a/testdata/ruby/dbEdgePairTest.rb b/testdata/ruby/dbEdgePairTest.rb index 7e6502495..3fa8c757f 100644 --- a/testdata/ruby/dbEdgePairTest.rb +++ b/testdata/ruby/dbEdgePairTest.rb @@ -61,6 +61,7 @@ class DBEdgePair_TestClass < TestBase ep = RBA::EdgePair::new(RBA::Edge::new(0, 0, 10, 0), RBA::Edge::new(0, 20, 0, 0)) + assert_equal(ep.distance, 0) assert_equal(ep.perimeter, 30) assert_equal(ep.area, 100) assert_equal(ep.simple_polygon(0).area, 100) @@ -71,6 +72,10 @@ class DBEdgePair_TestClass < TestBase assert_equal(ep.area, 0) assert_equal(ep.simple_polygon(0).area, 0) + ep = RBA::EdgePair::new(RBA::Edge::new(0, 0, 10, 0), RBA::Edge::new(-10, 10, 20, 10)) + + assert_equal(ep.distance, 10) + end # Basics @@ -108,6 +113,7 @@ class DBEdgePair_TestClass < TestBase ep = RBA::DEdgePair::new(RBA::DEdge::new(0, 0, 10, 0), RBA::DEdge::new(0, 20, 0, 0)) + assert_equal(ep.distance, 0) assert_equal(ep.perimeter, 30) assert_equal(ep.area, 100) assert_equal(ep.simple_polygon(0).area, 100) @@ -118,6 +124,10 @@ class DBEdgePair_TestClass < TestBase assert_equal(ep.area, 0) assert_equal(ep.simple_polygon(0).area, 0) + ep = RBA::DEdgePair::new(RBA::DEdge::new(0, 0, 10, 0), RBA::DEdge::new(-10, 10, 20, 10)) + + assert_equal(ep.distance, 10) + end # Fuzzy compare From 04ba7d304082c8bd045b520946b3a5e5bc0b7196 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 6 Dec 2023 22:29:08 +0100 Subject: [PATCH 12/18] Some enhancements to package manager dialog: mute an assertion that sometimes happened due to update events, avoid too many requests for running macros after download and specifically avoid them after remove of packages. --- src/lay/lay/layMacroController.cc | 7 +++---- src/lay/lay/laySaltDownloadManager.cc | 3 +++ src/lay/lay/laySaltManagerDialog.cc | 6 +++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/lay/lay/layMacroController.cc b/src/lay/lay/layMacroController.cc index 2eb517e76..7c78016fe 100644 --- a/src/lay/lay/layMacroController.cc +++ b/src/lay/lay/layMacroController.cc @@ -379,9 +379,11 @@ MacroController::sync_package_paths () void MacroController::sync_implicit_macros (bool ask_before_autorun) { + // gets the external paths (tech, packages) into m_external_paths + sync_macro_sources (); + if (m_no_implicit_macros) { - sync_macro_sources (); sync_package_paths (); } else { @@ -392,9 +394,6 @@ MacroController::sync_implicit_macros (bool ask_before_autorun) prev_folders_by_path.insert (std::make_pair (p->path, *p)); } - // gets the external paths (tech, packages) into m_external_paths - sync_macro_sources (); - // delete macro collections which are no longer required or update description std::vector folders_to_delete; diff --git a/src/lay/lay/laySaltDownloadManager.cc b/src/lay/lay/laySaltDownloadManager.cc index 559b59333..3dd9f3727 100644 --- a/src/lay/lay/laySaltDownloadManager.cc +++ b/src/lay/lay/laySaltDownloadManager.cc @@ -523,6 +523,9 @@ SaltDownloadManager::execute (lay::SaltManagerDialog *parent, lay::Salt &salt) dialog->start (); + // Stop other events to interfere with the download, specifically not macro controller updates + tl::NoDeferredMethods silent_section; + std::sort (m_registry.begin (), m_registry.end ()); for (std::vector::const_iterator p = m_registry.begin (); p != m_registry.end (); ++p) { diff --git a/src/lay/lay/laySaltManagerDialog.cc b/src/lay/lay/laySaltManagerDialog.cc index 4e86323bd..dd58ed13e 100644 --- a/src/lay/lay/laySaltManagerDialog.cc +++ b/src/lay/lay/laySaltManagerDialog.cc @@ -1213,13 +1213,13 @@ private: void SaltManagerDialog::get_remote_grain_info (lay::SaltGrain *g, SaltGrainDetailsTextWidget *details) { - if (! g) { + // NOTE: we don't want to interfere with download here, so refuse to do update + // the info while a package is downloaded. + if (! g || m_downloaded_grain.get ()) { details->setHtml (QString ()); return; } - tl_assert (m_downloaded_grain.get () == 0); - m_downloaded_grain.reset (0); if (m_downloaded_grain_reader.get ()) { From 293074c2af82efc8164c01b83c992dff56455535 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Dec 2023 19:32:19 +0100 Subject: [PATCH 13/18] Enhanced API for environment variable handling --- src/pymod/unit_tests/pymod_tests.cc | 13 ++------- src/tl/tl/tlEnv.cc | 38 ++++++++++++++++++++++++ src/tl/tl/tlEnv.h | 10 +++++++ src/tl/unit_tests/tlEnvTests.cc | 45 +++++++++++++++++++++++++++++ src/tl/unit_tests/unit_tests.pro | 1 + 5 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 src/tl/unit_tests/tlEnvTests.cc diff --git a/src/pymod/unit_tests/pymod_tests.cc b/src/pymod/unit_tests/pymod_tests.cc index d523dd344..7ec39f7af 100644 --- a/src/pymod/unit_tests/pymod_tests.cc +++ b/src/pymod/unit_tests/pymod_tests.cc @@ -32,19 +32,12 @@ #include "tlUnitTest.h" #include "tlStream.h" +#include "tlEnv.h" int run_pymodtest (tl::TestBase *_this, const std::string &fn) { - static std::string pypath; - if (pypath.empty ()) { - pypath = "PYTHONPATH="; - pypath += STRINGIFY (PYTHONPATH); - } -#if defined(_WIN32) - _putenv (const_cast (pypath.c_str ())); -#else - putenv (const_cast (pypath.c_str ())); -#endif + std::string pypath = STRINGIFY (PYTHONPATH); + tl::set_env ("PYTHONPATH", pypath); tl::info << pypath; std::string fp (tl::testdata ()); diff --git a/src/tl/tl/tlEnv.cc b/src/tl/tl/tlEnv.cc index ffd779ddd..47107818c 100644 --- a/src/tl/tl/tlEnv.cc +++ b/src/tl/tl/tlEnv.cc @@ -23,6 +23,7 @@ #include "tlEnv.h" #include "tlString.h" +#include "tlThreads.h" #include @@ -38,8 +39,13 @@ namespace tl { +static tl::Mutex s_env_lock; +static std::map s_env_map; + std::string get_env (const std::string &name, const std::string &def_value) { + tl::MutexLocker env_locker (&s_env_lock); + #ifdef _WIN32 std::wstring wname = tl::to_wstring (name); wchar_t *env = _wgetenv (wname.c_str ()); @@ -58,6 +64,38 @@ std::string get_env (const std::string &name, const std::string &def_value) #endif } +void set_env (const std::string &name, const std::string &value) +{ + tl::MutexLocker env_locker (&s_env_lock); + + s_env_map [name] = name + "=" + value; + const std::string &s = s_env_map [name]; + +#if defined(_WIN32) + _putenv (const_cast (s.c_str ())); +#else + putenv (const_cast (s.c_str ())); +#endif +} + +void unset_env (const std::string &name) +{ + tl::MutexLocker env_locker (&s_env_lock); + +#if defined(_WIN32) + s_env_map [name] = name + "="; +#else + s_env_map [name] = name; +#endif + const std::string &s = s_env_map [name]; + +#if defined(_WIN32) + _putenv (const_cast (s.c_str ())); +#else + putenv (const_cast (s.c_str ())); +#endif +} + bool has_env (const std::string &name) { #ifdef _WIN32 diff --git a/src/tl/tl/tlEnv.h b/src/tl/tl/tlEnv.h index 454b68bd8..ca17fdd30 100644 --- a/src/tl/tl/tlEnv.h +++ b/src/tl/tl/tlEnv.h @@ -38,6 +38,16 @@ namespace tl */ std::string TL_PUBLIC get_env (const std::string &name, const std::string &def_value = std::string ()); +/** + * @brief Sets the value for the given environment variable + */ +void TL_PUBLIC set_env (const std::string &name, const std::string &value); + +/** + * @brief Removes the given environment variable + */ +void TL_PUBLIC unset_env (const std::string &name); + /** * @brief Gets the value if the given environment variable is set */ diff --git a/src/tl/unit_tests/tlEnvTests.cc b/src/tl/unit_tests/tlEnvTests.cc new file mode 100644 index 000000000..46a0f0364 --- /dev/null +++ b/src/tl/unit_tests/tlEnvTests.cc @@ -0,0 +1,45 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2023 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 "tlEnv.h" +#include "tlUnitTest.h" + +const char *dne_name = "__DOES_NOT_EXIST__"; + +TEST(1) +{ + EXPECT_EQ (tl::has_env (dne_name), false); + + tl::set_env (dne_name, "123"); + EXPECT_EQ (tl::has_env (dne_name), true); + + EXPECT_EQ (tl::get_env (dne_name), "123"); + + tl::set_env (dne_name, "42"); + EXPECT_EQ (tl::has_env (dne_name), true); + + EXPECT_EQ (tl::get_env (dne_name), "42"); + + tl::unset_env (dne_name); + EXPECT_EQ (tl::get_env (dne_name, "bla"), "bla"); + EXPECT_EQ (tl::has_env (dne_name), false); +} diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index 2e0bab909..0e4bcc449 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -16,6 +16,7 @@ SOURCES = \ tlDataMappingTests.cc \ tlDeferredExecutionTests.cc \ tlDeflateTests.cc \ + tlEnvTests.cc \ tlEventsTests.cc \ tlExpressionTests.cc \ tlFileSystemWatcherTests.cc \ From 821b0395b69148ef6a2109259dfa9892ce22d6f7 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Dec 2023 19:57:14 +0100 Subject: [PATCH 14/18] Maybe fixing issue #1560 - needs testing --- scripts/deploy-win-mingw.sh | 7 +++++++ scripts/klayout-inst.nsis | 5 +++-- src/lay/lay/layApplication.cc | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/scripts/deploy-win-mingw.sh b/scripts/deploy-win-mingw.sh index 26bdb6d55..12dfe8b8f 100644 --- a/scripts/deploy-win-mingw.sh +++ b/scripts/deploy-win-mingw.sh @@ -134,6 +134,13 @@ if ! [ -e $target/klayout.exe ]; then exit 1 fi +# ---------------------------------------------------------- +# cert.pem + +echo "Installing cert.pem .." + +cp $mingw_inst/etc/ssl/cert.pem $target + # ---------------------------------------------------------- # Plugins diff --git a/scripts/klayout-inst.nsis b/scripts/klayout-inst.nsis index a4d4a655e..cbf3cefd7 100644 --- a/scripts/klayout-inst.nsis +++ b/scripts/klayout-inst.nsis @@ -40,7 +40,7 @@ InstallDirRegKey HKLM \ "UninstallString" # The text to prompt the user to enter a directory -DirText "Please select your ${NAME} installation path below:" +DirText "Please select your ${NAME} installation path below (CAUTION: THE GIVEN FOLDER WILL BE DELETED ENTIRELY ON UNINSTALLATION - DO NOT USE A GENERAL PURPOSE FOLDER OR A DRIVE ONLY):" # automatically close the installer when done. AutoCloseWindow true @@ -68,6 +68,7 @@ section file *.dll file strm*.exe file .*-paths.txt + file cert.pem file /r db_plugins file /r lay_plugins file /r audio @@ -154,7 +155,7 @@ section "Uninstall" # now delete installed files rmDir /r "$INSTDIR" - # create a shortcut + # remove shortcut rmDir /r "$SMPROGRAMS\${NAME}" DeleteRegKey SHCTX "Software\Microsoft\Windows\CurrentVersion\Uninstall\${NAME}" diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index 89433d867..930801c5f 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -64,6 +64,7 @@ #include "tlHttpStream.h" #include "tlArch.h" #include "tlFileUtils.h" +#include "tlEnv.h" #include #include @@ -568,6 +569,19 @@ ApplicationBase::init_app () } std::string short_arch_string = tl::join (as, "-"); +#if defined(_WIN32) + // Set SSL_CERT_FILE for Windows installation and libcrypto. + + std::string cert_file = "cert.pem"; + std::string cert_env_var = "SSL_CERT_FILE"; + if (! tl::has_env (cert_env_var)) { + std::string cert_path = tl::combine_path (m_inst_path, cert_file); + if (tl::file_exists (cert_path)) { + tl::set_env (cert_env_var, cert_path); + } + } +#endif + std::vector klp_paths; for (std::vector ::const_iterator p = m_klayout_path.begin (); p != m_klayout_path.end (); ++p) { From 86866e52d33379fe77cff4291cb74e3988edeae5 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Dec 2023 20:48:39 +0100 Subject: [PATCH 15/18] Fixed part of issue #1559 (not snapping to some diagonals) --- src/edt/edt/edtService.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/edt/edt/edtService.cc b/src/edt/edt/edtService.cc index 5d415b9b5..3d022b244 100644 --- a/src/edt/edt/edtService.cc +++ b/src/edt/edt/edtService.cc @@ -261,7 +261,7 @@ Service::snap_marker_to_grid (const db::DVector &v, bool &snapped) const if (snapped) { vr += vv; - return db::DVector (vr.x () * snapped_to.x (), vr.y () * snapped_to.y ()); + return db::DVector (vr.x () * fabs (snapped_to.x ()), vr.y () * fabs (snapped_to.y ())); } else { return db::DVector (); } From 787114fee2fe31ada0fb3d057a3992391dc0e8a9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Dec 2023 21:28:07 +0100 Subject: [PATCH 16/18] Trying to fix CentOS 7 builds (segfault because of late initialization of Mutex) --- src/tl/tl/tlEnv.cc | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/tl/tl/tlEnv.cc b/src/tl/tl/tlEnv.cc index 47107818c..b5aa647bb 100644 --- a/src/tl/tl/tlEnv.cc +++ b/src/tl/tl/tlEnv.cc @@ -39,12 +39,16 @@ namespace tl { -static tl::Mutex s_env_lock; +static tl::Mutex *s_env_lock = 0; static std::map s_env_map; std::string get_env (const std::string &name, const std::string &def_value) { - tl::MutexLocker env_locker (&s_env_lock); + if (! s_env_lock) { + s_env_lock = new tl::Mutex (); + } + + tl::MutexLocker env_locker (s_env_lock); #ifdef _WIN32 std::wstring wname = tl::to_wstring (name); @@ -66,7 +70,11 @@ std::string get_env (const std::string &name, const std::string &def_value) void set_env (const std::string &name, const std::string &value) { - tl::MutexLocker env_locker (&s_env_lock); + if (! s_env_lock) { + s_env_lock = new tl::Mutex (); + } + + tl::MutexLocker env_locker (s_env_lock); s_env_map [name] = name + "=" + value; const std::string &s = s_env_map [name]; @@ -80,7 +88,11 @@ void set_env (const std::string &name, const std::string &value) void unset_env (const std::string &name) { - tl::MutexLocker env_locker (&s_env_lock); + if (! s_env_lock) { + s_env_lock = new tl::Mutex (); + } + + tl::MutexLocker env_locker (s_env_lock); #if defined(_WIN32) s_env_map [name] = name + "="; @@ -98,6 +110,12 @@ void unset_env (const std::string &name) bool has_env (const std::string &name) { + if (! s_env_lock) { + s_env_lock = new tl::Mutex (); + } + + tl::MutexLocker env_locker (s_env_lock); + #ifdef _WIN32 std::wstring wname = tl::to_wstring (name); wchar_t *env = _wgetenv (wname.c_str ()); From b6d3f8be93112d8072007b1d879e0818edae7167 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 7 Dec 2023 23:09:04 +0100 Subject: [PATCH 17/18] Added Edge#euclidian_distance --- src/db/db/gsiDeclDbEdge.cc | 20 +++++++++++++++++++- testdata/ruby/dbEdgeTest.rb | 14 ++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/db/db/gsiDeclDbEdge.cc b/src/db/db/gsiDeclDbEdge.cc index 8d1f0d94b..52ff1cdf5 100644 --- a/src/db/db/gsiDeclDbEdge.cc +++ b/src/db/db/gsiDeclDbEdge.cc @@ -555,7 +555,7 @@ struct edge_defs "This method has been introduced in version 0.26.2.\n" ) + method ("distance", &C::distance, gsi::arg ("p"), - "@brief Distance between the edge and a point.\n" + "@brief Gets the distance of the point from the line through the edge.\n" "\n" "Returns the distance between the edge and the point. The \n" "distance is signed which is negative if the point is to the\n" @@ -564,6 +564,11 @@ struct edge_defs "line through the edge. If the edge is degenerated, the distance\n" "is not defined.\n" "\n" + "This method considers the edge to define an infinite line running through it.\n" + "the distance is the minimum distance of the point to any of the points on this\n" + "infinite line. A similar method is \\euclidian_distance, but the latter regards\n" + "the edge as a finite set of points between the endpoints.\n" + "\n" "@param p The point to test.\n" "\n" "@return The distance\n" @@ -578,6 +583,19 @@ struct edge_defs "\n" "@return The side value\n" ) + + method ("euclidian_distance", &C::euclidian_distance, gsi::arg ("p"), + "@brief Gets the distance of the point from the the edge.\n" + "\n" + "Returns the minimum distance of the point to any point on the edge.\n" + "Unlike \\distance, the edge is considered a finite set of points between\n" + "the endpoints. The result is also not signed like it is the case for \\distance.\n" + "\n" + "This method has been introduced in version 0.28.14.\n" + "\n" + "@param p The point to test.\n" + "\n" + "@return The distance\n" + ) + method ("distance_abs", &C::distance_abs, gsi::arg ("p"), "@brief Absolute distance between the edge and a point.\n" "\n" diff --git a/testdata/ruby/dbEdgeTest.rb b/testdata/ruby/dbEdgeTest.rb index c6edc7fe8..ee0c81a5e 100644 --- a/testdata/ruby/dbEdgeTest.rb +++ b/testdata/ruby/dbEdgeTest.rb @@ -111,6 +111,9 @@ class DBEdge_TestClass < TestBase assert_equal( a.intersect?( RBA::DEdge::new( -1, 11, 1, 15 ) ), false ) assert_equal( a.distance( RBA::DPoint::new( 3, 3 ) ), 1.0 ) assert_equal( a.distance( RBA::DPoint::new( 3, 1 ) ), -1.0 ) + assert_equal( a.euclidian_distance( RBA::DPoint::new( 3, 3 ) ), 1.0 ) + assert_equal( a.euclidian_distance( RBA::DPoint::new( 3, 1 ) ), 1.0 ) + assert_equal( a.euclidian_distance( RBA::DPoint::new( -3, 2 ) ), 1.0 ) assert_equal( a.distance_abs( RBA::DPoint::new( 3, 3 ) ), 1.0 ) assert_equal( a.distance_abs( RBA::DPoint::new( 3, 1 ) ), 1.0 ) assert_equal( a.side_of( RBA::DPoint::new( 3, 3 ) ), 1 ) @@ -224,10 +227,13 @@ class DBEdge_TestClass < TestBase assert_equal( a.intersection_point( RBA::Edge::new( RBA::Point::new( -1, -1 ), RBA::Point::new( 1, 5 ) ) ).to_s, "0,2" ) assert_equal( a.intersection_point( RBA::Edge::new( RBA::Point::new( -1, 3 ), RBA::Point::new( 1, 5 ) ) ) == nil, true ) assert_equal( a.intersect?( RBA::Edge::new( RBA::Point::new( -1, 11 ), RBA::Point::new( 1, 15 ) ) ), false ) - assert_equal( a.distance( RBA::Point::new( 3, 3 ) ), 1.0 ) - assert_equal( a.distance( RBA::Point::new( 3, 1 ) ), -1.0 ) - assert_equal( a.distance_abs( RBA::Point::new( 3, 3 ) ), 1.0 ) - assert_equal( a.distance_abs( RBA::Point::new( 3, 1 ) ), 1.0 ) + assert_equal( a.distance( RBA::Point::new( 3, 3 ) ), 1 ) + assert_equal( a.distance( RBA::Point::new( 3, 1 ) ), -1 ) + assert_equal( a.euclidian_distance( RBA::Point::new( 3, 4 ) ), 2 ) + assert_equal( a.euclidian_distance( RBA::Point::new( 3, 0 ) ), 2 ) + assert_equal( a.euclidian_distance( RBA::Point::new( -4, 2 ) ), 2 ) + assert_equal( a.distance_abs( RBA::Point::new( 3, 3 ) ), 1 ) + assert_equal( a.distance_abs( RBA::Point::new( 3, 1 ) ), 1 ) assert_equal( a.side_of( RBA::Point::new( 3, 3 ) ), 1 ) assert_equal( a.side_of( RBA::Point::new( 3, 1 ) ), -1 ) From 3e114bd69cb98bc5e67bd0e8bd33836a74d1dfd3 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 8 Dec 2023 07:24:46 +0100 Subject: [PATCH 18/18] Fixed doc. --- src/db/db/gsiDeclDbEdge.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/db/db/gsiDeclDbEdge.cc b/src/db/db/gsiDeclDbEdge.cc index 52ff1cdf5..405b38f2c 100644 --- a/src/db/db/gsiDeclDbEdge.cc +++ b/src/db/db/gsiDeclDbEdge.cc @@ -565,9 +565,9 @@ struct edge_defs "is not defined.\n" "\n" "This method considers the edge to define an infinite line running through it.\n" - "the distance is the minimum distance of the point to any of the points on this\n" - "infinite line. A similar method is \\euclidian_distance, but the latter regards\n" - "the edge as a finite set of points between the endpoints.\n" + "\\distance returns the distance of 'p' to this line.\n" + "A similar method is \\euclidian_distance, but the latter regards\n" + "the edge a finite set of points between the endpoints.\n" "\n" "@param p The point to test.\n" "\n"