From 09329442f0781a180b0145d6bb7a889c50f5a70a Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 9 Apr 2025 23:30:13 +0200 Subject: [PATCH 1/7] Fixing issue #2019 (build issue against Qt 6.9) --- scripts/mkqtdecl6/mkqtdecl.conf | 3 +- src/gsiqt/qt6/QtXml/gsiDeclQDomNodeList.cc | 49 ++++------------------ 2 files changed, 11 insertions(+), 41 deletions(-) diff --git a/scripts/mkqtdecl6/mkqtdecl.conf b/scripts/mkqtdecl6/mkqtdecl.conf index 427141e2b..4b7c15fa5 100644 --- a/scripts/mkqtdecl6/mkqtdecl.conf +++ b/scripts/mkqtdecl6/mkqtdecl.conf @@ -547,7 +547,7 @@ drop_method "QDebug", /QDebug::operator\s*<<\((?!const\s+QString\s*&)/ # don't m drop_method "", /::operator\s*<<\(QDebug\s*\w*\s*,\s*(?!const\s+QString\s*&)/ # don't map the others right now - too many (TODO: how to map?) drop_method "QNoDebug", /QNoDebug::operator<add_arg (argspec_0); - decl->set_return (); -} - -static void _call_f_operator_excl__eq__c2484 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - const QDomNodeList &arg1 = gsi::arg_reader() (args, heap); - ret.write ((bool)((QDomNodeList *)cls)->operator!= (arg1)); -} - - // QDomNodeList &QDomNodeList::operator=(const QDomNodeList &) @@ -191,25 +178,6 @@ static void _call_f_operator_eq__2484 (const qt_gsi::GenericMethod * /*decl*/, v } -// bool QDomNodeList::operator==(const QDomNodeList &) - - -static void _init_f_operator_eq__eq__c2484 (qt_gsi::GenericMethod *decl) -{ - static gsi::ArgSpecBase argspec_0 ("arg1"); - decl->add_arg (argspec_0); - decl->set_return (); -} - -static void _call_f_operator_eq__eq__c2484 (const qt_gsi::GenericMethod * /*decl*/, void *cls, gsi::SerialArgs &args, gsi::SerialArgs &ret) -{ - __SUPPRESS_UNUSED_WARNING(args); - tl::Heap heap; - const QDomNodeList &arg1 = gsi::arg_reader() (args, heap); - ret.write ((bool)((QDomNodeList *)cls)->operator== (arg1)); -} - - // int QDomNodeList::size() @@ -238,14 +206,15 @@ static gsi::Methods methods_QDomNodeList () { methods += new qt_gsi::GenericMethod ("isEmpty?", "@brief Method bool QDomNodeList::isEmpty()\n", true, &_init_f_isEmpty_c0, &_call_f_isEmpty_c0); methods += new qt_gsi::GenericMethod ("item", "@brief Method QDomNode QDomNodeList::item(int index)\n", true, &_init_f_item_c767, &_call_f_item_c767); methods += new qt_gsi::GenericMethod ("length", "@brief Method int QDomNodeList::length()\n", true, &_init_f_length_c0, &_call_f_length_c0); - methods += new qt_gsi::GenericMethod ("!=", "@brief Method bool QDomNodeList::operator!=(const QDomNodeList &)\n", true, &_init_f_operator_excl__eq__c2484, &_call_f_operator_excl__eq__c2484); methods += new qt_gsi::GenericMethod ("assign", "@brief Method QDomNodeList &QDomNodeList::operator=(const QDomNodeList &)\n", false, &_init_f_operator_eq__2484, &_call_f_operator_eq__2484); - methods += new qt_gsi::GenericMethod ("==", "@brief Method bool QDomNodeList::operator==(const QDomNodeList &)\n", true, &_init_f_operator_eq__eq__c2484, &_call_f_operator_eq__eq__c2484); methods += new qt_gsi::GenericMethod ("size", "@brief Method int QDomNodeList::size()\n", true, &_init_f_size_c0, &_call_f_size_c0); return methods; } gsi::Class decl_QDomNodeList ("QtXml", "QDomNodeList", + gsi::method_ext("==", &QDomNodeList_operator_eq, gsi::arg ("other"), "@brief Method bool QDomNodeList::operator==(const QDomNodeList &) const") + + gsi::method_ext("!=", &QDomNodeList_operator_ne, gsi::arg ("other"), "@brief Method bool QDomNodeList::operator!=(const QDomNodeList &) const") ++ methods_QDomNodeList (), "@qt\n@brief Binding of QDomNodeList"); From fa618a5b761cf3267128dac35240641b8968386b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Wed, 9 Apr 2025 23:35:09 +0200 Subject: [PATCH 2/7] Fixing the strict weak ordering issue inside the edge processor --- src/db/db/dbEdgeProcessor.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/db/dbEdgeProcessor.cc b/src/db/db/dbEdgeProcessor.cc index fd3ffb113..c26b5569f 100644 --- a/src/db/db/dbEdgeProcessor.cc +++ b/src/db/db/dbEdgeProcessor.cc @@ -1321,7 +1321,7 @@ struct edge_xmin_at_yinterval_double_compare { if (edge_xmax (a) < edge_xmin (b)) { return true; - } else if (edge_xmin (a) >= edge_xmax (b)) { + } else if (edge_xmin (a) > edge_xmax (b)) { return false; } else { C xa = edge_xmin_at_yinterval_double (a, m_y1, m_y2); From d317dc2fe3a97d00f2153528e3e169a9918d898f Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 24 Apr 2025 23:30:50 +0200 Subject: [PATCH 3/7] Fixed issue #2025 (brackets get added on PCell parameters) --- src/edt/edt/edtPCellParametersPage.cc | 50 +++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/edt/edt/edtPCellParametersPage.cc b/src/edt/edt/edtPCellParametersPage.cc index 27ca1a261..8f27d312b 100644 --- a/src/edt/edt/edtPCellParametersPage.cc +++ b/src/edt/edt/edtPCellParametersPage.cc @@ -47,6 +47,31 @@ namespace edt { +static std::string variant_list_to_string (const tl::Variant &value) +{ + if (! value.is_list ()) { + tl::Variant v = tl::Variant::empty_list (); + v.push (value); + return v.to_parsable_string (); + } + + for (auto i = value.begin (); i != value.end (); ++i) { + if (! i->is_a_string () || std::string (i->to_string ()).find (",") != std::string::npos) { + return value.to_parsable_string (); + } + } + + // otherwise we can plainly combine the strings with "," + std::string res; + for (auto i = value.begin (); i != value.end (); ++i) { + if (i != value.begin ()) { + res += ","; + } + res += i->to_string (); + } + return res; +} + static void set_value (const db::PCellParameterDeclaration &p, QWidget *widget, const tl::Variant &value) { if (p.get_choices ().empty ()) { @@ -91,7 +116,7 @@ static void set_value (const db::PCellParameterDeclaration &p, QWidget *widget, QLineEdit *le = dynamic_cast (widget); if (le) { le->blockSignals (true); - le->setText (value.to_qstring ()); + le->setText (tl::to_qstring (variant_list_to_string (value))); le->blockSignals (false); } } @@ -905,8 +930,29 @@ PCellParametersPage::get_parameters_internal (db::ParameterStates &states, bool { QLineEdit *le = dynamic_cast (m_widgets [r]); if (le) { - std::vector values = tl::split (tl::to_string (le->text ()), ","); + + std::string s = tl::to_string (le->text ()); + + // try parsing a bracketed expression + tl::Extractor ex (s.c_str ()); + if (*ex.skip () == '(') { + tl::Variant v; + try { + ex.read (v); + ps.set_value (v); + break; + } catch (...) { + // ignore errors + } + } else if (ex.at_end ()) { + ps.set_value (tl::Variant::empty_list ()); + break; + } + + // otherwise: plain splitting at comma + std::vector values = tl::split (s, ","); ps.set_value (tl::Variant (values.begin (), values.end ())); + } } break; From 148498f8405751eca5a23905ca248c8f33b4a6ca Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 26 Apr 2025 16:15:25 +0200 Subject: [PATCH 4/7] Fixing issue #2026 (after 2.5D display main 2D layout does not display anymore with visible shapes) --- .../view_25d/lay_plugin/layD25ViewWidget.cc | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index b3b0a0e31..7a29a7ff0 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -661,15 +661,15 @@ D25ViewWidget::enter (const db::RecursiveShapeIterator *iter, double zstart, dou void D25ViewWidget::entry (const db::Region &data, double dbu, double zstart, double zstop) { - // try to establish a default color from the region's origin if required - const db::RecursiveShapeIterator *iter = 0; const db::OriginalLayerRegion *original = dynamic_cast (data.delegate ()); if (original) { - iter = original->iter (); + // try to establish a default color from the region's origin if required + auto it = original->begin_iter (); + enter (&it.first, zstart, zstop); + } else { + enter (0, zstart, zstop); } - enter (iter, zstart, zstop); - tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ..."))); render_region (progress, *m_layers.back ().vertex_chunk, *m_layers.back ().normals_chunk, *m_layers.back ().line_chunk, data, dbu, db::CplxTrans (dbu).inverted () * m_bbox, zstart, zstop); } @@ -677,15 +677,15 @@ D25ViewWidget::entry (const db::Region &data, double dbu, double zstart, double void D25ViewWidget::entry (const db::Edges &data, double dbu, double zstart, double zstop) { - // try to establish a default color from the region's origin if required - const db::RecursiveShapeIterator *iter = 0; const db::OriginalLayerEdges *original = dynamic_cast (data.delegate ()); if (original) { - iter = original->iter (); + // try to establish a default color from the region's origin if required + auto it = original->begin_iter (); + enter (&it.first, zstart, zstop); + } else { + enter (0, zstart, zstop); } - enter (iter, zstart, zstop); - tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ..."))); render_edges (progress, *m_layers.back ().vertex_chunk, *m_layers.back ().normals_chunk, *m_layers.back ().line_chunk, data, dbu, db::CplxTrans (dbu).inverted () * m_bbox, zstart, zstop); } @@ -693,15 +693,15 @@ D25ViewWidget::entry (const db::Edges &data, double dbu, double zstart, double z void D25ViewWidget::entry (const db::EdgePairs &data, double dbu, double zstart, double zstop) { - // try to establish a default color from the region's origin if required - const db::RecursiveShapeIterator *iter = 0; const db::OriginalLayerEdgePairs *original = dynamic_cast (data.delegate ()); if (original) { - iter = original->iter (); + // try to establish a default color from the region's origin if required + auto it = original->begin_iter (); + enter (&it.first, zstart, zstop); + } else { + enter (0, zstart, zstop); } - enter (iter, zstart, zstop); - tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ..."))); render_edge_pairs (progress, *m_layers.back ().vertex_chunk, *m_layers.back ().normals_chunk, *m_layers.back ().line_chunk, data, dbu, db::CplxTrans (dbu).inverted () * m_bbox, zstart, zstop); } From 2bd82af6feb476ffbb83abe2022d76564dc17655 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 26 Apr 2025 16:52:39 +0200 Subject: [PATCH 5/7] Provide a solution of feature request #2024 - There is a new configuration page entry called "Min spacing" for the grid. The default value is 4. The value specifies the grid min spacing in units of UI font height. - A bugfix is included: the ruler now is drawn after the grid, hence is not hidden by it (specifically in checkerboard pattern mode) - To allow bigger grid spacing, the ruler now is allowed to grow bigger than before. --- src/laybasic/laybasic/laybasicConfig.h | 1 + src/layview/layview/GridNetConfigPage.ui | 336 +++++++++++--------- src/layview/layview/layGridNet.cc | 129 +++++--- src/layview/layview/layGridNet.h | 8 + src/layview/layview/layGridNetConfigPage.cc | 5 + 5 files changed, 271 insertions(+), 208 deletions(-) diff --git a/src/laybasic/laybasic/laybasicConfig.h b/src/laybasic/laybasic/laybasicConfig.h index 1b33e6455..eb99c9d4b 100644 --- a/src/laybasic/laybasic/laybasicConfig.h +++ b/src/laybasic/laybasic/laybasicConfig.h @@ -43,6 +43,7 @@ static const std::string cfg_grid_grid_color ("grid-grid-color"); static const std::string cfg_grid_style0 ("grid-style0"); static const std::string cfg_grid_style1 ("grid-style1"); static const std::string cfg_grid_style2 ("grid-style2"); +static const std::string cfg_grid_density ("grid-density"); static const std::string cfg_grid_visible ("grid-visible"); static const std::string cfg_grid_micron ("grid-micron"); static const std::string cfg_grid_show_ruler ("grid-show-ruler"); diff --git a/src/layview/layview/GridNetConfigPage.ui b/src/layview/layview/GridNetConfigPage.ui index 34db49143..427129ba0 100644 --- a/src/layview/layview/GridNetConfigPage.ui +++ b/src/layview/layview/GridNetConfigPage.ui @@ -7,7 +7,7 @@ 0 0 483 - 341 + 361 @@ -59,6 +59,23 @@ 6 + + + + Far style + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Show ruler + + + @@ -108,7 +125,122 @@ - + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + + + + + + + + + + + + Grid + + + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + + + + + + + + Ruler + + + + + + + + + + + + + + Axis + + + + + + + + + + + + + + Close style + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Color (all) + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + Color @@ -118,14 +250,17 @@ - - - - Qt::Horizontal + + + + Style + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + @@ -169,30 +304,23 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - + + - + Color + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - Qt::Horizontal + + + + Color + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -245,141 +373,37 @@ - - - - Far style - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Close style - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Color (all) - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - - - Grid - - - - - - - Show Ruler - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Style - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Color - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - - - - - - - Axis - - - - - - - Color - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Ruler - - - - + Qt::Horizontal + + + + 1 + + + + + + + Min. spacing + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + (Font height units) + + + diff --git a/src/layview/layview/layGridNet.cc b/src/layview/layview/layGridNet.cc index 2cc8c85a2..b960579b1 100644 --- a/src/layview/layview/layGridNet.cc +++ b/src/layview/layview/layGridNet.cc @@ -41,6 +41,8 @@ namespace lay // ------------------------------------------------------------ // Helper functions to get and set the configuration +int default_density = 4; + static struct { lay::GridNet::GridStyle style; const char *string; @@ -79,6 +81,20 @@ GridNetStyleConverter::to_string (lay::GridNet::GridStyle style) return ""; } +void +GridNetDensityConverter::from_string (const std::string &value, int &density) +{ + density = default_density; // original default + tl::Extractor ex (value.c_str ()); + ex.try_read (density); +} + +std::string +GridNetDensityConverter::to_string (int density) +{ + return tl::to_string (density); +} + // ------------------------------------------------------------ // Implementation of the GridNetPluginDeclaration @@ -92,6 +108,7 @@ GridNetPluginDeclaration::get_options (std::vector < std::pair (cfg_grid_style0, GridNetStyleConverter ().to_string (lay::GridNet::Invisible))); options.push_back (std::pair (cfg_grid_style1, GridNetStyleConverter ().to_string (lay::GridNet::Dots))); options.push_back (std::pair (cfg_grid_style2, GridNetStyleConverter ().to_string (lay::GridNet::TenthDottedLines))); + options.push_back (std::pair (cfg_grid_density, "")); options.push_back (std::pair (cfg_grid_visible, tl::to_string (true))); options.push_back (std::pair (cfg_grid_show_ruler, tl::to_string (true))); // grid-micron is not configured here since some other entity is supposed to do this. @@ -122,7 +139,8 @@ GridNet::GridNet (LayoutViewBase *view) lay::Plugin (view), mp_view (view), m_visible (false), m_show_ruler (true), m_grid (1.0), - m_style0 (Invisible), m_style1 (Invisible), m_style2 (Invisible) + m_style0 (Invisible), m_style1 (Invisible), m_style2 (Invisible), + m_density (default_density) { // .. nothing yet .. } @@ -175,6 +193,12 @@ GridNet::configure (const std::string &name, const std::string &value) GridNetStyleConverter ().from_string (value, style); need_update = test_and_set (m_style2, style); + } else if (name == cfg_grid_density) { + + int density = 0; + GridNetDensityConverter ().from_string (value, density); + need_update = test_and_set (m_density, density); + } else if (name == cfg_grid_show_ruler) { bool sr = false; @@ -246,13 +270,14 @@ GridNet::render_bg (const lay::Viewport &vp, ViewObjectCanvas &canvas) // fw is the basic unit of the ruler geometry int fwr = lay::FixedFont::get_font (bmp_canvas->font_resolution ()).width (); + int threshold = std::min (1000, m_density * fwr); double dgrid = trans.ctrans (m_grid); GridStyle style = m_style1; // compute major grid and switch to secondary style if necessary int s = 0; - while (dgrid < fwr * 4) { + while (dgrid < threshold) { if (s == 0) { dgrid *= 2.0; } else if (s == 1) { @@ -279,56 +304,6 @@ GridNet::render_bg (const lay::Viewport &vp, ViewObjectCanvas &canvas) int nx = int (dbworld.width () / grid + eps) + 2; int ny = int (dbworld.height () / grid + eps) + 2; - if (m_show_ruler && dgrid < vp.width () * 0.2) { - - int rh = int (floor (0.5 + fwr * 0.8)); - int xoffset = int (floor (0.5 + fwr * 2.5)); - int yoffset = int (floor (0.5 + fwr * 2.5)); - - painter.fill_rect (db::Point (xoffset, vp.height () - yoffset - rh / 2), - db::Point (xoffset + int (floor (0.5 + dgrid)), vp.height () - yoffset + rh / 2), - ruler_color); - - painter.draw_rect (db::Point (xoffset + int (floor (0.5 + dgrid)), vp.height () - yoffset - rh / 2), - db::Point (xoffset + int (floor (0.5 + 2 * dgrid)), vp.height () - yoffset + rh / 2), - ruler_color); - - painter.draw_text (tl::sprintf ("%g \265m", grid * 2).c_str (), - db::Point (xoffset + int (floor (0.5 + trans.ctrans (2 * grid))), vp.height () - yoffset - rh / 2 - 2), - ruler_color, -1, 1); - - if (mp_view->global_trans ().fp_trans () != db::DFTrans ()) { - - // draw a small "F" indicating any global transformation - db::Point pts[] = { - db::Point (-4, -5), - db::Point (-4, 5), - db::Point (4, 5), - db::Point (4, 3), - db::Point (-2, 3), - db::Point (-2, 1), - db::Point (3, 1), - db::Point (3, -1), - db::Point (-2, -1), - db::Point (-2, -5), - db::Point (-4, -5) - }; - - db::Polygon poly; - poly.assign_hull (&pts[0], &pts[0] + (sizeof (pts) / sizeof (pts[0]))); - poly.transform (db::FTrans (mp_view->global_trans ().fp_trans ())); - - for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); !e.at_end (); ++e) { - db::Point p0 (xoffset + 2 * rh, vp.height () - yoffset - rh * 5); - db::Point p1 = p0 + db::Vector (int (floor (0.5 + (*e).p1 ().x () * 0.1 * rh * 4)), -int (floor (0.5 + (*e).p1 ().y () * 0.1 * rh * 4))); - db::Point p2 = p0 + db::Vector (int (floor (0.5 + (*e).p2 ().x () * 0.1 * rh * 4)), -int (floor (0.5 + (*e).p2 ().y () * 0.1 * rh * 4))); - painter.draw_line (p1, p2, ruler_color); - } - - } - - } - // draw grid if (style == Dots || style == TenthDottedLines || style == DottedLines || style == LightDottedLines) { @@ -549,6 +524,56 @@ GridNet::render_bg (const lay::Viewport &vp, ViewObjectCanvas &canvas) } + if (m_show_ruler && dgrid < vp.width () * 0.4) { + + int rh = int (floor (0.5 + fwr * 0.8)); + int xoffset = int (floor (0.5 + fwr * 2.5)); + int yoffset = int (floor (0.5 + fwr * 2.5)); + + painter.fill_rect (db::Point (xoffset, vp.height () - yoffset - rh / 2), + db::Point (xoffset + int (floor (0.5 + dgrid)), vp.height () - yoffset + rh / 2), + ruler_color); + + painter.draw_rect (db::Point (xoffset + int (floor (0.5 + dgrid)), vp.height () - yoffset - rh / 2), + db::Point (xoffset + int (floor (0.5 + 2 * dgrid)), vp.height () - yoffset + rh / 2), + ruler_color); + + painter.draw_text (tl::sprintf ("%g \265m", grid * 2).c_str (), + db::Point (xoffset + int (floor (0.5 + trans.ctrans (2 * grid))), vp.height () - yoffset - rh / 2 - 2), + ruler_color, -1, 1); + + if (mp_view->global_trans ().fp_trans () != db::DFTrans ()) { + + // draw a small "F" indicating any global transformation + db::Point pts[] = { + db::Point (-4, -5), + db::Point (-4, 5), + db::Point (4, 5), + db::Point (4, 3), + db::Point (-2, 3), + db::Point (-2, 1), + db::Point (3, 1), + db::Point (3, -1), + db::Point (-2, -1), + db::Point (-2, -5), + db::Point (-4, -5) + }; + + db::Polygon poly; + poly.assign_hull (&pts[0], &pts[0] + (sizeof (pts) / sizeof (pts[0]))); + poly.transform (db::FTrans (mp_view->global_trans ().fp_trans ())); + + for (db::Polygon::polygon_edge_iterator e = poly.begin_edge (); !e.at_end (); ++e) { + db::Point p0 (xoffset + 2 * rh, vp.height () - yoffset - rh * 5); + db::Point p1 = p0 + db::Vector (int (floor (0.5 + (*e).p1 ().x () * 0.1 * rh * 4)), -int (floor (0.5 + (*e).p1 ().y () * 0.1 * rh * 4))); + db::Point p2 = p0 + db::Vector (int (floor (0.5 + (*e).p2 ().x () * 0.1 * rh * 4)), -int (floor (0.5 + (*e).p2 ().y () * 0.1 * rh * 4))); + painter.draw_line (p1, p2, ruler_color); + } + + } + + } + } } diff --git a/src/layview/layview/layGridNet.h b/src/layview/layview/layGridNet.h index 89b63c3f0..d75dcde37 100644 --- a/src/layview/layview/layGridNet.h +++ b/src/layview/layview/layGridNet.h @@ -87,6 +87,7 @@ private: GridStyle m_style0; GridStyle m_style1; GridStyle m_style2; + int m_density; }; class GridNetStyleConverter @@ -96,6 +97,13 @@ public: std::string to_string (lay::GridNet::GridStyle style); }; +class GridNetDensityConverter +{ +public: + void from_string (const std::string &value, int &density); + std::string to_string (int density); +}; + } #endif diff --git a/src/layview/layview/layGridNetConfigPage.cc b/src/layview/layview/layGridNetConfigPage.cc index 6736f72f1..900a31b53 100644 --- a/src/layview/layview/layGridNetConfigPage.cc +++ b/src/layview/layview/layGridNetConfigPage.cc @@ -94,6 +94,10 @@ GridNetConfigPage::setup (lay::Dispatcher *root) style = lay::GridNet::Invisible; root->config_get (cfg_grid_style2, style, GridNetStyleConverter ()); mp_ui->style2_cbx->setCurrentIndex (int (style)); + + int density = 0; + root->config_get (cfg_grid_density, density, GridNetDensityConverter ()); + mp_ui->grid_density_sb->setValue (density); } void @@ -108,6 +112,7 @@ GridNetConfigPage::commit (lay::Dispatcher *root) root->config_set (cfg_grid_style0, lay::GridNet::GridStyle (mp_ui->style0_cbx->currentIndex ()), GridNetStyleConverter ()); root->config_set (cfg_grid_style1, lay::GridNet::GridStyle (mp_ui->style1_cbx->currentIndex ()), GridNetStyleConverter ()); root->config_set (cfg_grid_style2, lay::GridNet::GridStyle (mp_ui->style2_cbx->currentIndex ()), GridNetStyleConverter ()); + root->config_set (cfg_grid_density, mp_ui->grid_density_sb->value (), GridNetDensityConverter ()); } } // namespace lay From 2435e774f45597e2e3f9a0affed8951ab7c8ba81 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 26 Apr 2025 19:05:40 +0200 Subject: [PATCH 6/7] Preventing an internal error when using report after 'input' --- src/drc/drc/built-in-macros/_drc_engine.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index fa5cf402c..15c6356a4 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -1585,7 +1585,8 @@ module DRC self._context("report") do # finish what we got so far - _finish(false) + view = RBA::LayoutView::current + @def_output && @def_output.finish(false, view) @def_output = nil @def_output = _make_report(description, filename, cellname) From ffa42653feb97acfa4e665bc09a35db08771de9e Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 26 Apr 2025 22:04:50 +0200 Subject: [PATCH 7/7] Addressing issue #2011 - "report" can now be late in DRC without internal error Yet, the report will only capture the output layers after the report statement has been called. - Text objects don't create zero-area polygons in deep mode XOR now. --- src/db/db/dbLocalOperationUtils.cc | 8 +++++-- src/db/db/dbPolygon.h | 18 ++++++++++++++++ src/db/db/dbRegionLocalOperations.cc | 22 +++++++++++++++---- src/db/unit_tests/dbPolygonTests.cc | 29 ++++++++++++++++++++++++++ src/drc/unit_tests/drcSimpleTests.cc | 10 +++++++++ testdata/drc/drcSimpleTests_94.drc | 26 +++++++++++++++++++++++ testdata/drc/drcSimpleTests_94.gds | Bin 0 -> 606 bytes testdata/drc/drcSimpleTests_au94.gds | Bin 0 -> 734 bytes testdata/drc/drcSimpleTests_au94d.gds | Bin 0 -> 692 bytes 9 files changed, 107 insertions(+), 6 deletions(-) create mode 100644 testdata/drc/drcSimpleTests_94.drc create mode 100644 testdata/drc/drcSimpleTests_94.gds create mode 100644 testdata/drc/drcSimpleTests_au94.gds create mode 100644 testdata/drc/drcSimpleTests_au94d.gds diff --git a/src/db/db/dbLocalOperationUtils.cc b/src/db/db/dbLocalOperationUtils.cc index c338dbe6d..51d98807d 100644 --- a/src/db/db/dbLocalOperationUtils.cc +++ b/src/db/db/dbLocalOperationUtils.cc @@ -39,7 +39,9 @@ PolygonRefToShapesGenerator::PolygonRefToShapesGenerator (db::Layout *layout, db void PolygonRefToShapesGenerator::put (const db::Polygon &polygon) { tl::MutexLocker locker (&mp_layout->lock ()); - if (m_prop_id != 0) { + if (polygon.is_empty ()) { + // ignore empty polygons + } else if (m_prop_id != 0) { mp_shapes->insert (db::PolygonRefWithProperties (db::PolygonRef (polygon, mp_layout->shape_repository ()), m_prop_id)); } else { mp_shapes->insert (db::PolygonRef (polygon, mp_layout->shape_repository ())); @@ -58,7 +60,9 @@ PolygonSplitter::PolygonSplitter (PolygonSink &sink, double max_area_ratio, size void PolygonSplitter::put (const db::Polygon &poly) { - if (db::suggest_split_polygon (poly, m_max_vertex_count, m_max_area_ratio)) { + if (poly.is_empty ()) { + // ignore empty polygons + } else if (db::suggest_split_polygon (poly, m_max_vertex_count, m_max_area_ratio)) { std::vector split_polygons; db::split_polygon (poly, split_polygons); diff --git a/src/db/db/dbPolygon.h b/src/db/db/dbPolygon.h index 134412e8e..b56a36271 100644 --- a/src/db/db/dbPolygon.h +++ b/src/db/db/dbPolygon.h @@ -1771,6 +1771,14 @@ public: return true; } + /** + * @brief Returns a value indicating that the polygon is an empty one + */ + bool is_empty () const + { + return m_ctrs.size () == size_t (1) && m_ctrs[0].size () == 0; + } + /** * @brief Returns the number of points in the polygon */ @@ -1879,6 +1887,7 @@ public: for (typename contour_list_type::iterator h = m_ctrs.begin (); h != m_ctrs.end (); ++h) { h->transform (db::unit_trans (), true /*compress*/, remove_reflected); } + m_bbox = m_ctrs [0].bbox (); return *this; } @@ -2804,6 +2813,7 @@ public: { // compress the polygon by employing the transform method m_hull.transform (db::unit_trans (), true, remove_reflected); + m_bbox = m_hull.bbox (); return *this; } @@ -3022,6 +3032,14 @@ public: return m_hull.is_halfmanhattan (); } + /** + * @brief Returns a value indicating that the polygon is an empty one + */ + bool is_empty () const + { + return m_hull.size () == 0; + } + /** * @brief The number of holes * diff --git a/src/db/db/dbRegionLocalOperations.cc b/src/db/db/dbRegionLocalOperations.cc index 48d974563..64849b712 100644 --- a/src/db/db/dbRegionLocalOperations.cc +++ b/src/db/db/dbRegionLocalOperations.cc @@ -1618,18 +1618,34 @@ bool_and_or_not_local_operation::do_compute_local (db::Layout *layou } } + db::polygon_ref_generator pr (layout, result); + db::PolygonSplitter splitter (pr, proc->area_ratio (), proc->max_vertex_count ()); + for (auto i = interactions.begin (); i != interactions.end (); ++i) { const TR &subject = interactions.subject_shape (i->first); if (others.find (subject) != others.end ()) { + + // shortcut (and: keep, not: drop) + // Note that we still normalize and split the polygon, so we get a uniform + // behavior. if (m_is_and) { - result.insert (subject); + db::Polygon poly; + subject.instantiate (poly); + splitter.put (poly); } + } else if (i->second.empty ()) { + // shortcut (not: keep, and: drop) + // Note that we still normalize and split the polygon, so we get a uniform + // behavior. if (! m_is_and) { - result.insert (subject); + db::Polygon poly; + subject.instantiate (poly); + splitter.put (poly); } + } else { for (auto e = subject.begin_edge (); ! e.at_end(); ++e) { ep.insert (*e, p1); @@ -1649,8 +1665,6 @@ bool_and_or_not_local_operation::do_compute_local (db::Layout *layou } db::BooleanOp op (m_is_and ? db::BooleanOp::And : db::BooleanOp::ANotB); - db::polygon_ref_generator pr (layout, result); - db::PolygonSplitter splitter (pr, proc->area_ratio (), proc->max_vertex_count ()); db::PolygonGenerator pg (splitter, true, true); ep.set_base_verbosity (50); ep.process (pg, op); diff --git a/src/db/unit_tests/dbPolygonTests.cc b/src/db/unit_tests/dbPolygonTests.cc index c9e277d77..dc518c7bd 100644 --- a/src/db/unit_tests/dbPolygonTests.cc +++ b/src/db/unit_tests/dbPolygonTests.cc @@ -69,6 +69,7 @@ TEST(1) EXPECT_EQ (empty == p, true); EXPECT_EQ (p.is_box (), false); + EXPECT_EQ (p.is_empty (), true); std::vector c1, c2, c3; c1.push_back (db::Point (0, 0)); @@ -76,6 +77,7 @@ TEST(1) c1.push_back (db::Point (100, 1000)); c1.push_back (db::Point (100, 0)); p.assign_hull (c1.begin (), c1.end ()); + EXPECT_EQ (p.is_empty (), false); b = p.box (); EXPECT_EQ (p.holes (), size_t (0)); EXPECT_EQ (p.area (), 1000*100); @@ -1404,3 +1406,30 @@ TEST(28) db::Polygon b (db::Box (-1000000000, -1000000000, 1000000000, 1000000000)); EXPECT_EQ (b.perimeter (), 8000000000.0); } + +TEST(29) +{ + // Degenerated boxes and compress + + db::Polygon b (db::Box (10, 20, 10, 20)); + EXPECT_EQ (b.is_empty (), false); + EXPECT_EQ (b == db::Polygon (), false); + EXPECT_EQ (b.to_string (), "(10,20;10,20;10,20;10,20)"); + EXPECT_EQ (double (b.area ()), 0.0); + + b.compress (true); + + EXPECT_EQ (b.is_empty (), true); + EXPECT_EQ (b == db::Polygon (), true); + + db::SimplePolygon sb (db::Box (10, 20, 10, 20)); + EXPECT_EQ (sb.is_empty (), false); + EXPECT_EQ (sb == db::SimplePolygon (), false); + EXPECT_EQ (sb.to_string (), "(10,20;10,20;10,20;10,20)"); + EXPECT_EQ (double (sb.area ()), 0.0); + + sb.compress (true); + + EXPECT_EQ (sb.is_empty (), true); + EXPECT_EQ (sb == db::SimplePolygon (), true); +} diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index f88392542..c618af869 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1694,6 +1694,16 @@ TEST(93d_withAngle) run_test (_this, "93", true); } +TEST(94_texts_in_region_xor) +{ + run_test (_this, "94", false); +} + +TEST(94d_texts_in_region_xor) +{ + run_test (_this, "94", true); +} + TEST(100_edge_interaction_with_count) { run_test (_this, "100", false); diff --git a/testdata/drc/drcSimpleTests_94.drc b/testdata/drc/drcSimpleTests_94.drc new file mode 100644 index 000000000..5809b64af --- /dev/null +++ b/testdata/drc/drcSimpleTests_94.drc @@ -0,0 +1,26 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0) +l2 = input(2, 0) + +l1.output(1, 0) +l2.output(2, 0) + +x = l1 ^ l2 + +# we detect point-like polygons here by explicitly +# iterating. The enlargement makes sure, we have something +# to write to the output layout. +boxes = x.data.each.collect do |p| + RBA::Box::new(p.bbox.enlarged(10, 10)) +end +x.data = RBA::Region::new(boxes) + +x.output(10, 0) + diff --git a/testdata/drc/drcSimpleTests_94.gds b/testdata/drc/drcSimpleTests_94.gds new file mode 100644 index 0000000000000000000000000000000000000000..7e3a7cd5206cda09c06762097b7c95bc20b1b6ba GIT binary patch literal 606 zcmZQzV_;&6V31*CVt>iN!XU*U#=yY9gUn{&U}E#}bYfr-VP>^+>@@d2w)}&o%MSeo zv!g;7WLWX&V`B^P4`5(m;b353<7HxCWMJcC0-CNP!2JLJe-#D>rUnSjybUPY#J~Wf zVd6{;3@m~`{XB5}Vj%r&;*1O&3_KuH{!UZ{lq9~Xmg;@F#DJ57bSlHWG2>yXwkwQ}V z0sezUy8J*~=eS#M*POv>j=7n=nc0JZ$ORH5^$8-h(S$)Ju*ZtwK{ zWxC%@cb*>?;sjd;Bi3Sv6|BRZL+v{`SP*=`+PbW9a z_s!`=a{M|Q^buFK_>Ae_-2+h#FuTI z{q@xU{Q{^jm?P7pqFhAR0J}KV{xap!#=XPvy7AclF!zRAueud+h|hG?{C}y@>jg hIiCx3yo`cgLO=UdN!F_j>E|!w(D5qC{8grn@Cy^pZF2ws literal 0 HcmV?d00001