diff --git a/Changelog b/Changelog index 23d35b08d..62ecba455 100644 --- a/Changelog +++ b/Changelog @@ -1,19 +1,276 @@ -0.27 (2020-xx-xx): -* Enhancement: %GITHUB%/issues/521 - Enhanced API for ObjectInstPath +0.27 (2021-04-xx): + +* Enhancements: Numerous new functions for the RBA and pya API + Some highlights: + * "Texts" for text collections (similar for Edges/EdgePairs/Region) + * New modes for blending layout files - see GitHub issue #666 + * New function Cell#transform - see GitHub issue #598 + * New functions for Image (read, write, clear) + * New functions for Region and Edges correlating with the new DRC features + * Multi-cell hierarchical copy/move of trees - will maintain shared instances + * RBA: iterators are now automatically made available as Enumerable + * All functions having a void return specification now return self (allows chaining) + * More functions for manipulating selections (LayoutView#select_all etc.) + * Spline interpolation code available in new "Utils" namespace + * QByteArray support, mapping to Python byte arrays + * MainWindow#set_key_bindings, MainWindow#get_key_bindings, MainWindow#set_menu_items_hidden etc. + * New class RecursiveInstanceIterator (similar to RecursiveShapeIterator, but acts on instances) + * Deep vs. flat operations do not always flatten out now (flat vs. deep does however) + * Global transformations for inputs +* Enhancements: New DRC features + Some highlights: + * Better support for texts - "text layers" + * Combined AND+NOT feature for separating regions into inside and outside part + * "max_vertex_count" and "max_area_ratio" configuration options + * "forget" for memory optimization + * Shielding is optional now for some DRC functions + * "interact" now has a count filter + * In verbose more, figure counts and more information is printed + * Generic DRC function and complex DRC operations: for details search "Universal DRC" in documentation + * "not_opposite" and "rect_filter" options for some DRC functions + * "enclosing" (selects polygons entirely enclosing others) + * New filters for polygons: squares, non_squares, area ratio, bbox aspect ratio + * More intuitive specification of projection limits ("projecting < 2.um") + * "with_holes" and "without_holes", also with count + * Density check is included now ("with_densitiy", "without_density") + * "split_..." functions give interacting/non-interacting sets in one step + * Better support for generic transformations as Matrix2d and Matrix3d + * "fill" and "fill_with_left" functions for dummy fill + * NO "connected" feature yet. Sorry. Had to drop it to finish this release. +* Enhancements: new LVS features + Some highlights: + * Improved netlist and LVS result browser (infinite-depth browsing) + * Improved circuit match algorithm + * Case insensitive handling of object names for SPICE netlists + * Probe feature fixed in flat mode + * "connect_explicit": for details search "connect_explicit" in documentation +* Enhancements: New features for images + Some highlights: + * New menu item: show and hide all images - see GitHub issue #535 + * False color nodes now can have a left and right color allowing color steps + * Persistance of images through a special file format: "lyimg" (XML based) +* Enhancements: LEF/DEF reader + Some highlights: + * Support for layer map files + * More complete spec support (e.g. FILL, MASK, FOREIGN, DO/BY/STEP ...) + * Several bug fixes, e.g. routing layer switch for VIAs + * Some functions also act on the transient selection (less mouse clicks) +* Enhancements: Layout editing and rulers + Some highlights: + * Object properties now are changed without having to commit the dialogs + * Dockable editor options windows + * "Recently used" list + * A "distribute objects" feature (Edit/Selection/Distribute) + * Snap highlighting + * Mouse tracking cursor indicates grid- and object-snapped location +* Enhancements: Help browser + * Bookmarks + * Search in page (Ctrl+F) +* Enhancement: Improved fill tool + The fill tool now also supports skewed fill pattern repetitions +* Enhancement: Ability to utilize a LayoutView as a Widget + Standalone instantiation of a LayoutView object is + supported now. So it becomes possible to create + custom MainWindow UIs and embed a layout view there. +* Enhancement: Improved layer and cell list filtering and searching +* Enhancement: Experimental 3d (called 2.5d) view of layout + For details search "2.5d View" in documentation. +* Enhancement: Improved performance on sea of instances for OASIS files + Iterated OASIS instances are stored and handled in a leaner way in viewer mode +* Enhancement: Buddy scripts can concatenate files with "+" for input + Concatenation happens by "blending files". Beware of the risk this implies. +* Enhancement: Layer maps now support n:m layer mapping + This allows mapping n input layers to one logical layer (merging) and also + one input layer to m logical ones (clone layer). This applies to the + buddy scripts and layer maps inside KLayout's reader. +* Enhancement: include mechanism for easy include of files into DRC/LVS scripts + This is a plain text substitution feature. Don't use it for Ruby or Python + scripts (the preferred way is still require/import). But it's a quick way + to include partial DRC and LVS scripts without having to worry about variable + scope. For details see "Including other files" in the documentation under: + KLayout User Manual/Design Rule Check (DRC)/DRC Runsets. +* Bugfix: %GITHUB%/issues/750 + PCB gerber import: Incorrect handling of D02 operations. +* Bugfix: %GITHUB%/issues/740 + Bug in the "smooth" function. +* Enhancement: %GITHUB%/issues/691 + Technology specific libraries: library name resolution based on technology. +* Enhancement: %GITHUB%/issues/666 + Controlling the way a layout reader integrates cells into an existing layout. +* Bugfix: %GITHUB%/issues/663 + Deep mode DRC: separation from "inside" gives wrong errors. +* Enhancement: %GITHUB%/issues/648 + LVS could not do "connect_implicit" with global nets. +* Bugfix: %GITHUB%/issues/609 + Internal error on net extraction. +* Enhancement: %GITHUB%/issues/598 + Plain transformation of cell missing. +* Enhancement: %GITHUB%/issues/588 + RBA/PYA: Provide event when a net is selected in the netlist browser. +* Enhancement: %GITHUB%/issues/563 + True support for text objects in DRC/LVS (text layers). * Enhancement: %GITHUB%/issues/558 Edges#extents, Texts#extents and EdgePairs#extents now work hierarchically in deep mode. In DRC, this means, "extents" is a deep-enabled method now. -* Enhancement: %GITHUB%/issues/563 - True support for text objects in DRC/LVS (text layers) -* Enhancement: ability to utilize a LayoutView as a Widget - Standalone instantiation of a LayoutView object is - supported now. So it becomes possible to create - custom MainWindow UIs and embed a layout view there. +* Enhancement: %GITHUB%/issues/535 + Image handling enhancements. +* Enhancement: %GITHUB%/issues/521 + Enhanced API for ObjectInstPath. +* Enhancement: %GITHUB%/issues/487 + Difficult to select specific labels for net name assignment in net extraction. + Solution involves a more elaborate handling of texts through "text layers. -0.26.5 (2020-xx-xx): +0.26.11 (2021-02-27): + +* Bugfix: %GITHUB%/issues/733 + Relative path resolution in session files fails when the session file's path contains "+" characters +* Enhancement: %GITHUB%/issues/730 + Support of class 'QUiLoader' in PYA and RBA +* Bugfix: %GITHUB%/issues/728 + Fails to build on Debian hppa: uses non-standard sa_restorer field of struct sigaction +* Bugfix: %GITHUB%/issues/726 + Crash on LayoutView#clear_selection on Linux. +* Bugfix: %GITHUB%/issues/723 + Backup scheme wasn't working correctly with a single file without path + given as command line argument. + +0.26.10 (2020-02-02): + +* Enhancement: %GITHUB%/issues/720 + "Safe save" and backups: when saving files, the file is only overwritten after + the save terminated successfully. This will avoid loss of data for full volumes + or network share dropouts. In addition, a configurable number of back files can + be kept (see File/Setup: Application/General). +* Bugfix: %GITHUB%/issues/718 + GDS export issue fixed (breaking of polygons was filling holes) +* Bugfix: %GITHUB%/issues/709 + LVS compare enters infinite loop when it encounters two entirely identical subcircuits +* Bugfix: %GITHUB%/issues/708 + Qt binding: missing support for binary strings as QByteArray representative +* Bugfix: %GITHUB%/issues/707 + QJsonValue's string constructor is ambiguous +* Bugfix: %GITHUB%/issues/704 + Rational Splines not supported DXF +* Bugfix: %GITHUB%/issues/693 + MAGIC files won't find subcells when reading from command line +* Bugfix: HTTP stream reading issue with redirect + At least on MacOS a segfault happened when reading HTTP stream data + (e.g. for package manager) from addresses which are redirected. +* Enhancement: Removed %APPDATA% from DLL search path on Windows + This will avoid installation poisoning by the one from %APPDATA% + (which ironically is the default installation path). Eventually + multiple versions can be used in parallel. + +0.26.9 (2020-11-27): + +* Bugfix: %GITHUB%/issues/658 + Menu items were not put into the right place on MacOS. +* Bugfix: %GITHUB%/issues/652 + "M" factor scaling was not working for Spice reader. +* Bugfix: %GITHUB%/issues/651 + Fixed an issue with DRC "select". +* Bugfix: %GITHUB%/issues/647 + Text orientation was not considered properly in search & replace +* Bugfix: %GITHUB%/issues/646 + A potential crash was fixed happening when a PCell + library is deleted +* Bugfix: Display bug + Cell placements with small magnification factors (such that the + viewport dimensions exceeded the DBU space when seem from inside + the cell) lead to display errors. + +0.26.8 (2020-09-15): + +* Enhancement: %GITHUB%/issues/639 + A new method is available which enables copying of multiple cells + into a target layout while maintaining common subcells are single + cells. +* Bugfix: %GITHUB%/issues/637 + Points have not been selected properly when inside mirrored subcells + in partial edit mode. +* Bugfix: %GITHUB%/issues/629 + Qt5 QTimer timeout signal was not available to Python or Ruby. + This also applied to all "private" signals of Qt5. QTimer is just + one important example for this case. +* Bugfix: %GITHUB%/issues/617 + A problem with pseudo-const Python/Ruby objects in the netlist API + was fixed. +* Bugfix: %GITHUB%/issues/615 + Basic authentication for package manager now uses UTF-8 encoding. + Most servers expect this kind of encoding today. UTF password + characters are supported this way. + +0.26.7 (2020-07-07): + +* Bugfix: %GITHUB%/issues/381 and more + Some bugs fixed that happened specifically on MacOS. + 1.) A segfault that happened in LVS + 2.) Some classes were not properly registered for usage in scripts. +* Bugfix: %GITHUB%/issues/493 + LVS asserted on MacOS +* Enhancement: %GITHUB%/issues/586 + As a safety feature, the stream writers now refuse to write layouts + with cells carrying the same names. Writing such layers would result + in corrupted or invalid layout files. +* Bugfix: %GITHUB%/issues/589 (tentative) + On Anaconda-based builds for MacOS 10.15 (Catalina) a loss of instances + was observed. This could be traced down to compiler/library incompatibilities + but not further. +* Enhancements: %GITHUB%/issues/591 + Two enhancements in the macro editor: + 1.) A crash happening when adding a new location was fixed + 2.) The template selection popup can now be disabled by dismissing the + tip dialog. +* Bugfix: %GITHUB%/issues/592 + Reading a file into a layout with unnamed layers caused problems with + layer mapping specs. +* Bugfix: %GITHUB%/issues/596 + Library#_destroy was crashing the application. As this function must not + be called, it's rerouted to "nothing" for backward compatibility. +* Enhancement: %GITHUB%/issues/603 + The "adjust origin" feature now allows specifying the target + coordinates for the adjustment. +* Bugfix: %GITHUB%/issues/610 + An internal error happened for certain hierarchical configurations on + netlist extraction. +* Enhancement: LVS netlist compare + The algorithm was improved to provide better reproducibility. The + detection of matching paths in the presence of ambiguities was + improved. + In addition, the netlist compare now favours net names for resolving + ambiguities. So if nets are named the same in the layout and the + schematic, ambiguities are resolved based on these names. This is + usually more efficient. A new function is available to turn this + feature off: "consider_net_names(false)". + +0.26.6 (2020-06-05): + +* Enhancement: %GITHUB%/issues/522 + Skip comment lines with // in RVE DB reader +* Bugfix: %GITHUB%/issues/547 + Doc fixes, better error messages on some Shape methods +* Bugfix: %GITHUB%/issues/554 + Using 64bit coordinates on RVE reader to avoid overflow +* Bugfix: %GITHUB%/issues/565 + Spice reader: .global should not add pin if the signal + isn't used in a subcircuit +* Bugfix: %GITHUB%/issues/568 and %GITHUB%/issues/578 + A CIF reader and writer bug was fixed +* Bugfix: %GITHUB%/issues/570 and %GITHUB%/issues/579 + Perimenter can be included in antenna area for the + antenna check. This also includes a mode in which only + the perimeter is considered. +* Enhancement: %GITHUB%/issues/560 + A library can be associated with multiple technologies now. +* Bugfix: width of cell and library side panels could not be + reduced below the width of the selection boxes in the + header +* Bugfix: cell view selection header text did not get updated + when saving the layout to a different file + +0.26.5 (2020-05-02): * Bugfix: %GITHUB%/issues/539 An internal error happened on netlist flatten sometimes @@ -28,6 +285,8 @@ * Bugfix: %GITHUB%/issues/544 Duplicate .global statements in SPICE netlists created duplicate pins +* Bugfix: %GITHUB%/issues/548 + A shielding issue was fixed for DRC space measurements * Bugfix: diff tool bug with paths Differences in path points where no reported * Enhancement: documentation clarifications and typos fixed diff --git a/src/ant/ant/antPropertiesPage.cc b/src/ant/ant/antPropertiesPage.cc index 721cd8c24..98bb0fcd5 100644 --- a/src/ant/ant/antPropertiesPage.cc +++ b/src/ant/ant/antPropertiesPage.cc @@ -122,7 +122,6 @@ PropertiesPage::swap_points_clicked () y1->setText (ty1); y2->setText (ty2); - db::Transaction t (manager (), tl::to_string (QObject::tr ("Swap ruler points"))); emit edited (); } @@ -224,7 +223,6 @@ PropertiesPage::snap_to_layout_clicked () y2->setText (ys); } - db::Transaction t (manager (), tl::to_string (snap_p1 ? QObject::tr ("Snap first ruler point") : QObject::tr ("Snap second ruler point"))); emit edited (); break; @@ -249,7 +247,6 @@ PropertiesPage::snap_to_layout_clicked () x2->setText (tl::to_qstring (tl::micron_to_string (ee.second.x ()))); y2->setText (tl::to_qstring (tl::micron_to_string (ee.second.y ()))); - db::Transaction t (manager (), tl::to_string (QObject::tr ("Snap both ruler points"))); emit edited (); } diff --git a/src/ant/ant/antService.cc b/src/ant/ant/antService.cc index e5d74cef7..f9666fd2c 100644 --- a/src/ant/ant/antService.cc +++ b/src/ant/ant/antService.cc @@ -1274,8 +1274,9 @@ Service::end_move (const db::DPoint &, lay::angle_constraint_type) // compute moved object and replace ant::Object *rnew = new ant::Object (*robj); rnew->transform (m_trans); + int new_id = rnew->id (); mp_view->annotation_shapes ().replace (s->first, db::DUserObject (rnew)); - annotation_changed_event (rnew->id ()); + annotation_changed_event (new_id); } diff --git a/src/db/db/dbBoxTree.h b/src/db/db/dbBoxTree.h index acd9c37a2..cc687ca54 100644 --- a/src/db/db/dbBoxTree.h +++ b/src/db/db/dbBoxTree.h @@ -760,6 +760,15 @@ public: // .. nothing else .. } + /** + * @brief Move constructor + */ + box_tree (box_tree &&b) + : m_objects (b.m_objects), m_elements (b.m_elements), mp_root (b.mp_root) + { + b.mp_root = 0; + } + /** * @brief Assignment */ @@ -774,6 +783,21 @@ public: return *this; } + /** + * @brief Assignment (move) + */ + box_tree &operator= (box_tree &&b) + { + clear (); + m_objects = b.m_objects; + m_elements = b.m_elements; + if (b.mp_root) { + mp_root = b.mp_root; + b.mp_root = 0; + } + return *this; + } + /** * @brief The destructor */ @@ -1729,6 +1753,15 @@ public: // .. nothing else .. } + /** + * @brief Move constructor + */ + unstable_box_tree (unstable_box_tree &&b) + : m_objects (b.m_objects), mp_root (b.mp_root) + { + b.mp_root = 0; + } + /** * @brief Assignment */ @@ -1742,6 +1775,20 @@ public: return *this; } + /** + * @brief Assignment (move) + */ + unstable_box_tree &operator= (unstable_box_tree &&b) + { + clear (); + m_objects = b.m_objects; + if (b.mp_root) { + mp_root = b.mp_root; + b.mp_root = 0; + } + return *this; + } + /** * @brief The destructor */ diff --git a/src/db/db/dbCompoundOperation.cc b/src/db/db/dbCompoundOperation.cc index db4aedd84..e3e9b8d7c 100644 --- a/src/db/db/dbCompoundOperation.cc +++ b/src/db/db/dbCompoundOperation.cc @@ -357,10 +357,7 @@ CompoundRegionMultiInputOperationNode::init () CompoundRegionMultiInputOperationNode::~CompoundRegionMultiInputOperationNode () { - for (tl::shared_collection::iterator i = m_children.begin (); i != m_children.end (); ++i) { - delete i.operator-> (); - } - m_children.clear (); + // .. nothing yet .. } void diff --git a/src/db/db/dbD25TechnologyComponent.cc b/src/db/db/dbD25TechnologyComponent.cc index 2719bfbb7..62f9b24e4 100644 --- a/src/db/db/dbD25TechnologyComponent.cc +++ b/src/db/db/dbD25TechnologyComponent.cc @@ -119,6 +119,7 @@ D25TechnologyComponent::D25TechnologyComponent () // provide some explanation for the initialization m_src = "# Provide z stack information here\n" + "#\n" "# Each line is one layer. The specification consists of a layer specification, a colon and arguments.\n" "# The arguments are named (like \"x=...\") or in serial. Parameters are separated by comma or blanks.\n" "# Named arguments are:\n" @@ -127,7 +128,7 @@ D25TechnologyComponent::D25TechnologyComponent () "# zstop The upper z position of the extruded layer in µm\n" "# height The height of the extruded layer in µm\n" "#\n" - "# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart', " + "# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart',\n" "# the upper level of the previous layer will be used.\n" "#\n" "# If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to\n" @@ -139,25 +140,52 @@ D25TechnologyComponent::D25TechnologyComponent () "# 1: zstop=1.5, zstart=0.5 # same with named parameters\n" "# 1: height=1.0, zstop=1.5 # same with z stop minus height\n" "# 1: 1.0 zstop=1.5 # same with height as unnamed parameter\n" + "#\n" + "# VARIABLES\n" + "#\n" + "# You can declare variables with:\n" + "# var name = value\n" + "#\n" + "# You can use variables inside numeric expressions.\n" + "# Example:\n" + "# var hmetal = 0.48\n" + "# 7/0: 0.5 0.5+hmetal*2 # 2x thick metal\n" + "#\n" + "# You cannot use variables inside layer specifications currently.\n" + "#\n" + "# CONDITIONALS\n" + "#\n" + "# You can enable or disable branches of the table using 'if', 'else', 'elseif' and 'end':\n" + "# Example:\n" + "# var thick_m1 = true\n" + "# if thickm1\n" + "# 1: 0.5 1.5\n" + "# else\n" + "# 1: 0.5 1.2\n" + "# end\n" + "\n" ; } D25TechnologyComponent::D25TechnologyComponent (const D25TechnologyComponent &d) : db::TechnologyComponent (d25_component_name (), d25_description ()) { - m_layers = d.m_layers; m_src = d.m_src; } -void -D25TechnologyComponent::compile_from_source (const std::string &src) +D25TechnologyComponent::layers_type +D25TechnologyComponent::compile_from_source () const { + layers_type layers; + int current_line = 0; - m_layers.clear (); try { - std::vector lines = tl::split (src, "\n"); + tl::Eval eval; + std::vector conditional_stack; + + std::vector lines = tl::split (m_src, "\n"); for (std::vector::const_iterator l = lines.begin (); l != lines.end (); ++l) { ++current_line; @@ -168,12 +196,86 @@ D25TechnologyComponent::compile_from_source (const std::string &src) // ignore comments } else if (ex.at_end ()) { // ignore empty lines + + } else if (ex.test ("if")) { + + tl::Expression x; + eval.parse (x, ex); + conditional_stack.push_back (x.execute ().to_bool ()); + + ex.expect_end (); + + } else if (ex.test ("else")) { + + if (conditional_stack.empty ()) { + throw tl::Exception (tl::to_string (tr ("'else' without 'if'"))); + } + + conditional_stack.back () = ! conditional_stack.back (); + + ex.expect_end (); + + } else if (ex.test ("end")) { + + if (conditional_stack.empty ()) { + throw tl::Exception (tl::to_string (tr ("'end' without 'if'"))); + } + + conditional_stack.pop_back (); + + ex.expect_end (); + + } else if (ex.test ("elsif")) { + + if (conditional_stack.empty ()) { + throw tl::Exception (tl::to_string (tr ("'elsif' without 'if'"))); + } + + tl::Expression x; + eval.parse (x, ex); + conditional_stack.back () = x.execute ().to_bool (); + + ex.expect_end (); + + } else if (! conditional_stack.empty () && ! conditional_stack.back ()) { + + continue; + + } else if (ex.test ("var")) { + + std::string n; + ex.read_name (n); + + ex.expect ("="); + + tl::Expression x; + eval.parse (x, ex); + eval.set_var (n, x.execute ()); + + ex.expect_end (); + + } else if (ex.test ("print")) { + + tl::Expression x; + eval.parse (x, ex); + ex.expect_end (); + + tl::info << x.execute ().to_string (); + + } else if (ex.test ("error")) { + + tl::Expression x; + eval.parse (x, ex); + ex.expect_end (); + + throw tl::Exception (x.execute ().to_string ()); + } else { db::D25LayerInfo info; - if (! m_layers.empty ()) { - info.set_zstart (m_layers.back ().zstop ()); - info.set_zstop (m_layers.back ().zstop ()); + if (! layers.empty ()) { + info.set_zstart (layers.back ().zstop ()); + info.set_zstop (layers.back ().zstop ()); } tl::Variant z0, z1, h; @@ -191,16 +293,18 @@ D25TechnologyComponent::compile_from_source (const std::string &src) break; } - double pv = 0.0; + tl::Expression pvx; std::string pn; if (ex.try_read_name (pn)) { ex.expect ("="); - ex.read (pv); + eval.parse (pvx, ex); } else { - ex.read (pv); + eval.parse (pvx, ex); } + double pv = pvx.execute ().to_double (); + ex.test (","); if (pn.empty ()) { @@ -220,7 +324,7 @@ D25TechnologyComponent::compile_from_source (const std::string &src) if (args.size () == 0) { if (z0.is_nil () && z1.is_nil ()) { if (! h.is_nil ()) { - info.set_zstop (info.zstart () + h.to_double ()); + info.set_zstop (info.zstop () + h.to_double ()); } } else if (z0.is_nil ()) { info.set_zstop (z1.to_double ()); @@ -239,28 +343,28 @@ D25TechnologyComponent::compile_from_source (const std::string &src) } else if (args.size () == 1) { if (! h.is_nil ()) { if (! z0.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstart already given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstart already given"))); } if (! z1.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop implicitly given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop implicitly given"))); } info.set_zstart (args[0]); info.set_zstop (args[0] + h.to_double ()); } else { if (! z1.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop implicitly given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop implicitly given"))); } info.set_zstop ((! z0.is_nil () ? z0.to_double () : info.zstart ()) + args[0]); } } else if (args.size () == 2) { if (! z0.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstart already given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstart already given"))); } if (! z1.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop already given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop already given"))); } if (! h.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Rundundant parameters: height implicitly given"))); + throw tl::Exception (tl::to_string (tr ("Redundant parameters: height implicitly given"))); } info.set_zstart (args[0]); info.set_zstop (args[1]); @@ -268,25 +372,30 @@ D25TechnologyComponent::compile_from_source (const std::string &src) throw tl::Exception (tl::to_string (tr ("Too many parameters (max 2)"))); } - m_layers.push_back (info); + layers.push_back (info); } } + if (! conditional_stack.empty ()) { + throw tl::Exception (tl::to_string (tr ("'if', 'else' or 'elsif' without matching 'end'"))); + } + } catch (tl::Exception &ex) { throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (" in line %d")), current_line)); } - m_src = src; + return layers; } std::string D25TechnologyComponent::to_string () const { + layers_type layers = compile_from_source (); std::string res; - for (const_iterator i = begin (); i != end (); ++i) { + for (layers_type::const_iterator i = layers.begin (); i != layers.end (); ++i) { if (! res.empty ()) { res += "\n"; } @@ -317,11 +426,6 @@ public: virtual tl::XMLElementBase *xml_element () const { return new db::TechnologyComponentXMLElement (d25_component_name (), - tl::make_element ((D25TechnologyComponent::const_iterator (D25TechnologyComponent::*) () const) &D25TechnologyComponent::begin, (D25TechnologyComponent::const_iterator (D25TechnologyComponent::*) () const) &D25TechnologyComponent::end, &D25TechnologyComponent::add, "layer", - tl::make_member (&D25LayerInfo::layer_as_string, &D25LayerInfo::set_layer_from_string, "layer") + - tl::make_member (&D25LayerInfo::zstart, &D25LayerInfo::set_zstart, "zstart") + - tl::make_member (&D25LayerInfo::zstop, &D25LayerInfo::set_zstop, "zstop") - ) + tl::make_member (&D25TechnologyComponent::src, &D25TechnologyComponent::set_src, "src") ); } diff --git a/src/db/db/dbD25TechnologyComponent.h b/src/db/db/dbD25TechnologyComponent.h index 5e4a1d51f..3beade105 100644 --- a/src/db/db/dbD25TechnologyComponent.h +++ b/src/db/db/dbD25TechnologyComponent.h @@ -76,55 +76,8 @@ public: D25TechnologyComponent (const D25TechnologyComponent &d); typedef std::list layers_type; - typedef layers_type::const_iterator const_iterator; - typedef layers_type::iterator iterator; - void compile_from_source (const std::string &src); - - const_iterator begin () const - { - return m_layers.begin (); - } - - iterator begin () - { - return m_layers.begin (); - } - - const_iterator end () const - { - return m_layers.end (); - } - - iterator end () - { - return m_layers.end (); - } - - void clear () - { - m_layers.clear (); - } - - void erase (iterator p) - { - m_layers.erase (p); - } - - void insert (iterator p, const D25LayerInfo &info) - { - m_layers.insert (p, info); - } - - void add (const D25LayerInfo &info) - { - m_layers.push_back (info); - } - - size_t size () const - { - return m_layers.size (); - } + layers_type compile_from_source () const; const std::string &src () const { @@ -145,7 +98,6 @@ public: } private: - layers_type m_layers; std::string m_src; }; diff --git a/src/db/db/dbFillTool.cc b/src/db/db/dbFillTool.cc index 855be54b5..a684bc149 100644 --- a/src/db/db/dbFillTool.cc +++ b/src/db/db/dbFillTool.cc @@ -212,11 +212,6 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f throw tl::Exception (tl::to_string (tr ("Invalid row or column step vectors in fill_region: row_step x column_step vector vector product must be > 0"))); } - // disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box - if (enhanced_fill && ! glue_box.empty () && ! fp0.box ().enlarged (db::Vector (1, 1)).inside (glue_box)) { - enhanced_fill = false; - } - db::Vector kernel_origin (fc_bbox.left (), fc_bbox.bottom ()); std::vector filled_regions; @@ -256,13 +251,21 @@ fill_polygon_impl (db::Cell *cell, const db::Polygon &fp0, db::cell_index_type f continue; } - size_t ninsts = 0; + // disable enhanced mode an obey the origin if the polygon is not entirely inside and not at the boundary of the glue box + bool ef = enhanced_fill; + if (ef && ! glue_box.empty () && ! fp->box ().enlarged (db::Vector (1, 1)).inside (glue_box)) { + ef = false; + } + // pick a heuristic "good" starting point in enhanced mode + // TODO: this is a pretty weak optimization. db::Point o = origin; - if (enhanced_fill) { + if (ef) { o = fp->hull () [0]; } + size_t ninsts = 0; + GenericRasterizer am (*fp, row_step, column_step, o, fc_bbox.p2 () - fc_bbox.p1 ()); for (unsigned int i = 0; i < am.area_maps (); ++i) { @@ -454,7 +457,7 @@ fill_region (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell DB_PUBLIC void fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, - const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Point &origin, const db::Box &glue_box) + const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box) { const db::Region *fill_region = &fr; @@ -468,7 +471,7 @@ fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fi ++iteration; remaining.clear (); - fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, origin, true, &remaining, fill_margin, remaining_polygons, iteration, glue_box); + fill_region_impl (cell, *fill_region, fill_cell_index, fc_box, row_step, column_step, db::Point (), true, &remaining, fill_margin, remaining_polygons, iteration, glue_box); new_fill_region.swap (remaining); fill_region = &new_fill_region; diff --git a/src/db/db/dbFillTool.h b/src/db/db/dbFillTool.h index a6b5c905c..e3e060514 100644 --- a/src/db/db/dbFillTool.h +++ b/src/db/db/dbFillTool.h @@ -118,6 +118,6 @@ fill_region (db::Cell *cell, const db::Region &fp, db::cell_index_type fill_cell DB_PUBLIC void fill_region_repeat (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, - const db::Vector &fill_margin, db::Region *remaining_polygons = 0, const db::Point &origin = db::Point (), const db::Box &glue_box = db::Box ()); + const db::Vector &fill_margin, db::Region *remaining_polygons = 0, const db::Box &glue_box = db::Box ()); } diff --git a/src/db/db/dbLayer.h b/src/db/db/dbLayer.h index 2f54619f6..453c8648f 100644 --- a/src/db/db/dbLayer.h +++ b/src/db/db/dbLayer.h @@ -107,6 +107,14 @@ struct layer operator= (d); } + /** + * @brief The move constructor + */ + layer (const layer &&d) + { + operator= (d); + } + /** * @brief The assignment operator * @@ -123,6 +131,20 @@ struct layer return *this; } + /** + * @brief The assignment operator (move semantics) + */ + layer &operator= (const layer &&d) + { + if (&d != this) { + m_box_tree = d.m_box_tree; + m_bbox = d.m_bbox; + m_bbox_dirty = d.m_bbox_dirty; + m_tree_dirty = d.m_tree_dirty; + } + return *this; + } + /** * @brief Get the iterator for an object given by a pointer */ @@ -207,6 +229,18 @@ struct layer return m_box_tree.insert (sh); } + /** + * @brief Insert a new shape object (move semantics) + */ + iterator insert (const Sh &&sh) + { + // inserting will make the bbox and the tree "dirty" - i.e. + // it will need to be updated. + m_bbox_dirty = true; + m_tree_dirty = true; + return m_box_tree.insert (sh); + } + /** * @brief Replace the given element with a new one * @@ -228,6 +262,19 @@ struct layer return *ncpos; } + /** + * @brief Replace the given element with a new one (move semantics) + */ + Sh &replace (iterator pos, const Sh &&sh) + { + m_bbox_dirty = true; + m_tree_dirty = true; + non_const_iterator ncpos; + to_non_const_box_tree_iter (pos, ncpos, StableTag ()); + *ncpos = sh; + return *ncpos; + } + /** * @brief Erasing of an element * diff --git a/src/db/db/dbPolygonTools.cc b/src/db/db/dbPolygonTools.cc index 808133e68..6d37ab289 100644 --- a/src/db/db/dbPolygonTools.cc +++ b/src/db/db/dbPolygonTools.cc @@ -1626,7 +1626,7 @@ AreaMap::reinitialize (const db::Point &p0, const db::Vector &d, const db::Vecto m_ny = ny; if (mp_av) { - delete mp_av; + delete[] mp_av; } mp_av = new area_type [nx * ny]; diff --git a/src/db/db/dbRegionUtils.h b/src/db/db/dbRegionUtils.h index f1da9196d..a7e67ce61 100644 --- a/src/db/db/dbRegionUtils.h +++ b/src/db/db/dbRegionUtils.h @@ -558,7 +558,7 @@ public: virtual void process (const db::Polygon &poly, std::vector &res) const; virtual const TransformationReducer *vars () const { return 0; } - virtual bool result_is_merged () const { return true; } // we believe so ... + virtual bool result_is_merged () const { return false; } // isn't merged for nested holes :( virtual bool requires_raw_input () const { return false; } virtual bool wants_variants () const { return true; } virtual bool result_must_not_be_merged () const { return false; } @@ -577,7 +577,7 @@ public: virtual void process (const db::Polygon &poly, std::vector &res) const; virtual const TransformationReducer *vars () const { return 0; } - virtual bool result_is_merged () const { return true; } // we believe so ... + virtual bool result_is_merged () const { return false; } // isn't merged for nested hulls :( virtual bool requires_raw_input () const { return false; } virtual bool wants_variants () const { return true; } virtual bool result_must_not_be_merged () const { return false; } diff --git a/src/db/db/dbUserObject.h b/src/db/db/dbUserObject.h index 8961480ba..f9a3c0b92 100644 --- a/src/db/db/dbUserObject.h +++ b/src/db/db/dbUserObject.h @@ -206,6 +206,18 @@ public: } } + /** + * @brief The move constructor + */ + user_object (user_object &&d) + : mp_obj (0) + { + if (d.mp_obj) { + set_ptr (d.mp_obj); + d.mp_obj = 0; + } + } + /** * @brief Assignment operator */ @@ -219,6 +231,20 @@ public: return *this; } + /** + * @brief Assignment operator (move) + */ + user_object &operator= (user_object &&d) + { + if (d.mp_obj) { + set_ptr (d.mp_obj); + d.mp_obj = 0; + } else { + set_ptr (0); + } + return *this; + } + /** * @brief The destructor */ diff --git a/src/db/db/gsiDeclDbCell.cc b/src/db/db/gsiDeclDbCell.cc index 6681da3f8..8fb411341 100644 --- a/src/db/db/gsiDeclDbCell.cc +++ b/src/db/db/gsiDeclDbCell.cc @@ -1312,9 +1312,9 @@ fill_region_skew (db::Cell *cell, const db::Region &fr, db::cell_index_type fill static void fill_region_multi (db::Cell *cell, const db::Region &fr, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, - const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Point &origin, const db::Box &glue_box) + const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box) { - db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, origin, glue_box); + db::fill_region_repeat (cell, fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box); } static db::Instance cell_inst_dtransform_simple (db::Cell *cell, const db::Instance &inst, const db::DTrans &t) @@ -1881,7 +1881,6 @@ Class decl_Cell ("db", "Cell", gsi::arg ("column_step"), gsi::arg ("fill_margin", db::Vector ()), gsi::arg ("remaining_polygons", (db::Region *)0, "nil"), - gsi::arg ("origin", db::Point ()), gsi::arg ("glue_box", db::Box ()), "@brief Fills the given region with cells of the given type in enhanced mode with iterations\n" "This version operates like \\fill_region, but repeats the fill generation until no further fill cells can be placed. " diff --git a/src/db/db/gsiDeclDbRegion.cc b/src/db/db/gsiDeclDbRegion.cc index 898e01120..c8ee01b40 100644 --- a/src/db/db/gsiDeclDbRegion.cc +++ b/src/db/db/gsiDeclDbRegion.cc @@ -730,9 +730,9 @@ fill_region_skew (const db::Region *fr, db::Cell *cell, db::cell_index_type fill static void fill_region_multi (const db::Region *fr, db::Cell *cell, db::cell_index_type fill_cell_index, const db::Box &fc_box, const db::Vector &row_step, const db::Vector &column_step, - const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Point &origin, const db::Box &glue_box) + const db::Vector &fill_margin, db::Region *remaining_polygons, const db::Box &glue_box) { - db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, origin, glue_box); + db::fill_region_repeat (cell, *fr, fill_cell_index, fc_box, row_step, column_step, fill_margin, remaining_polygons, glue_box); } static db::Point default_origin; @@ -2921,7 +2921,6 @@ Class decl_Region (decl_dbShapeCollection, "db", "Region", gsi::arg ("column_step"), gsi::arg ("fill_margin", db::Vector ()), gsi::arg ("remaining_polygons", (db::Region *)0, "nil"), - gsi::arg ("origin", db::Point ()), gsi::arg ("glue_box", db::Box ()), "@brief A mapping of \\Cell#fill_region to the Region class\n" "\n" diff --git a/src/db/unit_tests/dbCompoundOperationTests.cc b/src/db/unit_tests/dbCompoundOperationTests.cc index a465fc28f..a0d305afa 100644 --- a/src/db/unit_tests/dbCompoundOperationTests.cc +++ b/src/db/unit_tests/dbCompoundOperationTests.cc @@ -99,6 +99,7 @@ void run_test1 (tl::TestBase *_this, bool deep) unsigned int l1002 = ly.get_layer (db::LayerProperties (1002, 0)); res.insert_into (&ly, *ly.begin_top_down (), l1002); + primary = new db::CompoundRegionOperationPrimaryNode (); db::CompoundRegionCheckOperationNode space_check (primary, db::SpaceRelation, false /*==all polygons*/, 1050, check_options); res = r.cop_to_edge_pairs (space_check); diff --git a/src/db/unit_tests/dbD25TechnologyComponentTests.cc b/src/db/unit_tests/dbD25TechnologyComponentTests.cc index 76080ef09..b83365ea4 100644 --- a/src/db/unit_tests/dbD25TechnologyComponentTests.cc +++ b/src/db/unit_tests/dbD25TechnologyComponentTests.cc @@ -30,44 +30,73 @@ TEST(1) { db::D25TechnologyComponent comp; - comp.compile_from_source ("1/0: 1.0 1.5 # a comment"); + comp.set_src ("1/0: 1.0 1.5 # a comment"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5"); + comp.set_src ("1/0: zstart=1.0 zstop=1.5"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: zstart=1.0 height=0.5"); + comp.set_src ("1/0: zstart=1.0 height=0.5"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: 1.0 height=0.5"); + comp.set_src ("1/0: 1.0 height=0.5"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: zstop=1.5 height=0.5"); + comp.set_src ("1/0: zstop=1.5 height=0.5"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); - comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5\nname: height=3"); + comp.set_src ("1/0: zstart=1.0 zstop=1.5\nname: height=3"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=1.5, zstop=4.5"); - comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.set_src ("1/0: zstart=1.0 zstop=1.5\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.compile_from_source (); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7"); + comp.set_src ("var x=1.0\n1/0: zstart=x zstop=x+0.5\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.compile_from_source (); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7"); + + comp.set_src ("var x=1.0\nif x == 1.0\n1/0: zstart=x zstop=x+0.5\nelse\n1/0: zstart=0 zstop=0\nend\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.compile_from_source (); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7"); + + comp.set_src ("var x=2.0\nif x == 1.0\n1/0: zstart=x zstop=x+0.5\nelse\n1/0: zstart=0 zstop=0\nend\nname: zstart=4.0 height=3\n\n# a comment line"); + comp.compile_from_source (); + EXPECT_EQ (comp.to_string (), "1/0: zstart=0, zstop=0\nname: zstart=4, zstop=7"); + try { - comp.compile_from_source ("blabla"); + comp.set_src ("blabla"); + comp.compile_from_source (); EXPECT_EQ (false, true); } catch (...) { } try { - comp.compile_from_source ("1/0: 1 2 3"); + comp.set_src ("1/0: 1 2 3"); + comp.compile_from_source (); EXPECT_EQ (false, true); } catch (...) { } try { - comp.compile_from_source ("1/0: foo=1 bar=2"); + comp.set_src ("1/0: foo=1 bar=2"); + comp.compile_from_source (); EXPECT_EQ (false, true); } catch (...) { } try { - comp.compile_from_source ("1/0: 1;2"); + comp.set_src ("1/0: 1;*2"); + comp.compile_from_source (); + EXPECT_EQ (false, true); + } catch (...) { } + + try { + comp.set_src ("error 42"); + comp.compile_from_source (); EXPECT_EQ (false, true); } catch (...) { } } diff --git a/src/db/unit_tests/dbDeepRegionTests.cc b/src/db/unit_tests/dbDeepRegionTests.cc index 46b57bf22..f02a2f1db 100644 --- a/src/db/unit_tests/dbDeepRegionTests.cc +++ b/src/db/unit_tests/dbDeepRegionTests.cc @@ -694,8 +694,8 @@ TEST(10_HullsAndHoles) db::Region hulls = r1_sized.hulls (); db::Region holes = r1_sized.holes (); - EXPECT_EQ (hulls.is_merged (), true); - EXPECT_EQ (holes.is_merged (), true); + EXPECT_EQ (hulls.is_merged (), false); + EXPECT_EQ (holes.is_merged (), false); db::Layout target; unsigned int target_top_cell_index = target.add_cell (ly.cell_name (top_cell_index)); diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index d7cd228ed..9a3d2eefb 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -259,6 +259,10 @@ module DRC DRCFillOrigin::new end + def multi_origin + DRCFillOrigin::new(nil, nil, true) + end + def origin(x, y) DRCFillOrigin::new(x, y) end diff --git a/src/drc/drc/built-in-macros/_drc_layer.rb b/src/drc/drc/built-in-macros/_drc_layer.rb index 489f2da3a..4d22374b8 100644 --- a/src/drc/drc/built-in-macros/_drc_layer.rb +++ b/src/drc/drc/built-in-macros/_drc_layer.rb @@ -4251,7 +4251,9 @@ CODE # @li @b origin(x, y) @/b: specifies a fixed point to align the pattern with. This point specifies the location # of the reference point for one pattern cell. @/li # @li @b auto_origin @/b: lets the algorithm choose the origin. This may result is a slightly better fill coverage - # as the algorithm is able to determine a pattern origin per fill island. @/li + # as the algorithm is able to determine a pattern origin per island to fill. @/li + # @li @b multi_origin @/b: lets the algorithm choose the origin and repeats the fill with different origins + # until no further fill cell can be fitted. @/li # @li @b fill_pattern(..) @/b: specifies the fill pattern. @/li # @/ul # @@ -4355,6 +4357,7 @@ CODE column_step = nil pattern = nil origin = RBA::DPoint::new + repeat = false args.each_with_index do |a,ai| if a.is_a?(DRCSource) @@ -4381,6 +4384,7 @@ CODE end elsif a.is_a?(DRCFillOrigin) origin = a.origin + repeat = a.repeat else raise("Argument ##{ai+1} not understood for '#{m}'") end @@ -4435,31 +4439,22 @@ CODE tp.var("cs", cs) tp.var("origin", origin) tp.var("fc_index", fc_index) + tp.var("repeat", repeat) + tp.var("with_left", with_left) - if with_left - tp.queue(<<"END") - var tc_box = _frame.bbox; - var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box; - !tile_box.empty && ( - tile_box = tile_box.enlarged(Vector.new(max(rs.x, fc_box.width), max(cs.y, fc_box.height))); - tile_box = tile_box & tc_box; - var left = Region.new; + tp.queue(<<"END") + var tc_box = _frame.bbox; + var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box; + !tile_box.empty && ( + tile_box = tile_box.enlarged(Vector.new(max(rs.x, fc_box.width), max(cs.y, fc_box.height))); + tile_box = tile_box & tc_box; + var left = with_left ? Region.new : nil; + repeat ? + (region & tile_box).fill_multi(top_cell, fc_index, fc_box, rs, cs, Vector.new, left, _tile.bbox) : (region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, left, Vector.new, left, _tile.bbox); - _output(#{result_arg}, left) - ) + with_left && _output(#{result_arg}, left) + ) END - else - tp.queue(<<"END") - var tc_box = _frame.bbox; - var tile_box = _tile ? (tc_box & _tile.bbox) : tc_box; - !tile_box.empty && ( - tile_box.right = tile_box.right + rs.x - 1; - tile_box.top = tile_box.top + cs.y - 1; - tile_box = tile_box & tc_box; - (region & tile_box).fill(top_cell, fc_index, fc_box, rs, cs, origin, nil, Vector.new, nil, _tile.bbox) - ) -END - end begin @engine._output_layout.start_changes @@ -4477,10 +4472,19 @@ END end @engine.run_timed("\"#{m}\" in: #{@engine.src_line}", self.data) do - self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, RBA::Vector::new, result) + if repeat + self.data.fill_multi(top_cell, fc_index, fc_box, rs, cs, RBA::Vector::new, result) + else + self.data.fill(top_cell, fc_index, fc_box, rs, cs, origin, result, RBA::Vector::new, result) + end end end + + if fill_cell.parent_cells == 0 + # fill cell not required (not placed) -> remove + fill_cell.delete + end self.data.disable_progress diff --git a/src/drc/drc/built-in-macros/_drc_tags.rb b/src/drc/drc/built-in-macros/_drc_tags.rb index 283a7813d..0da810678 100644 --- a/src/drc/drc/built-in-macros/_drc_tags.rb +++ b/src/drc/drc/built-in-macros/_drc_tags.rb @@ -334,7 +334,8 @@ module DRC # A wrapper for the fill origin definition class DRCFillOrigin - def initialize(x = nil, y = nil) + def initialize(x = nil, y = nil, repeat = false) + @repeat = repeat if !x && !y @origin = nil else @@ -350,6 +351,9 @@ module DRC def origin @origin end + def repeat + @repeat + end end # A wrapper for the tile_size option diff --git a/src/drc/unit_tests/drcSimpleTests.cc b/src/drc/unit_tests/drcSimpleTests.cc index 36b46732a..5d3abc750 100644 --- a/src/drc/unit_tests/drcSimpleTests.cc +++ b/src/drc/unit_tests/drcSimpleTests.cc @@ -1222,3 +1222,13 @@ TEST(45_fillWithOverlappingBoxesTiled) { run_test (_this, "45", false); } + +TEST(46_fillWithOverlappingBoxes) +{ + run_test (_this, "46", false); +} + +TEST(47_fillWithOverlappingBoxesTiled) +{ + run_test (_this, "47", false); +} diff --git a/src/edt/edt/edtInstPropertiesPage.cc b/src/edt/edt/edtInstPropertiesPage.cc index 2360211db..4034061fe 100644 --- a/src/edt/edt/edtInstPropertiesPage.cc +++ b/src/edt/edt/edtInstPropertiesPage.cc @@ -542,6 +542,9 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (rows_le->text ()), rows); + if (rows < 1) { + throw tl::Exception (tl::to_string (tr ("Rows count can't be zero"))); + } lay::indicate_error (rows_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (rows_le, &ex); @@ -550,6 +553,9 @@ InstPropertiesPage::create_applicator (db::Cell & /*cell*/, const db::Instance & try { tl::from_string (tl::to_string (columns_le->text ()), cols); + if (cols < 1) { + throw tl::Exception (tl::to_string (tr ("Columns count can't be zero"))); + } lay::indicate_error (columns_le, (tl::Exception *) 0); } catch (tl::Exception &ex) { lay::indicate_error (columns_le, &ex); diff --git a/src/lay/lay/doc/about/25d_screenshot.png b/src/lay/lay/doc/about/25d_screenshot.png new file mode 100644 index 000000000..4515ae722 Binary files /dev/null and b/src/lay/lay/doc/about/25d_screenshot.png differ diff --git a/src/lay/lay/doc/about/25d_view.xml b/src/lay/lay/doc/about/25d_view.xml new file mode 100644 index 000000000..f112260b7 --- /dev/null +++ b/src/lay/lay/doc/about/25d_view.xml @@ -0,0 +1,147 @@ + + + + + + The 2.5d View + + + + + + + +

+ The "2.5d view" offers a semi-3d view of the layout. It's not a full 3d view as the layers are only extruded vertically + into layers with a certain thickness. The view cannot model process topology, but it can visualize + wiring congestions in a three-dimensional space or the vertical relative dimensions of features of the process stack. +

+ +

+ To open the view, use "Tools/2.5d View". Currently, the performance is limited, a rough number for a + practical limit is around 100k polygons. The 2.5d view is only available, if KLayout was compiled with + OpenGL support. +

+ +

+ +

+ +

Setup

+ +

+ The 2.5d view needs a technology setup explaining the way the layers are transformed into planes. + The setup is provided within a technology. Open the technology manager (File/Manage Technologies) and + navigate to the "Z Stack (2.5d)" component. The setup is basically a list of entries listing the + layer from which to take the shapes and the depth information. +

+ +

+ Each entry is a single line. Empty lines are ignored. Everything after a '#' character is + considered a comment. +

+ +

+ Each specification line consists of a layer specification, a colon and arguments. + The arguments are named (like "x=...") or in serial. Parameters are separated by comma or blanks. + Named arguments are: +

+ +
    +
  • zstart: The lower z position of the extruded layer in µm
  • +
  • zstop: The upper z position of the extruded layer in µm
  • +
  • height: The height of the extruded layer in µm
  • +
+ +

+ 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart', + the upper level of the previous layer will be used. +

+ +

+ If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to + 'zstart' and 'zstop'. +

+ +

+ Here are some examples: +

+ +
1: 0.5 1.5                    # extrude layer 1/0 from 0.5 to 1.5 vertically\n"
+1/0: 0.5 1.5                  # same with explicit datatype\n"
+1: zstop=1.5, zstart=0.5      # same with named parameters\n"
+1: height=1.0, zstop=1.5      # same with z stop minus height\n"
+1: 1.0 zstop=1.5              # same with height as unnamed parameter\n"
+  
+ +

Variables

+ +

+ You can declare variables inside the setup files and use them in formulas for + computed values. Variables are defined and set with the "var" keyword on a single line. + The notation follows the "expression" syntax used in many other places inside KLayout + (). +

+ +

+ Here is an example: +

+ +
var hmetal = 0.48\n"
+7/0: 0.5 0.5+hmetal*2        # 2x thick metal\n"
+
+ +

Conditionals

+ +

+ For more flexibility, but of little practical use for now, conditionals are provided. + "if", "else", "elsif" and "end" for as in other languages, e.g. Ruby: +

+ +
var thick_m1 = true
+if thickm1
+  1: 0.5 1.5
+else
+  1: 0.5 1.2
+end
+
+ +

Navigating the 2.5d View

+ navigation + 2.5d navigation + +

+ The navigation is based on the movement of the camera while the scene is + formed by the extruded layout. The scene can be scaled to provide zoom features. + Scaling and rotation is relative to the pivot point which is indicated by the + compass icon on the ground plane. +

+ +

+ This is a short list of the navigation controls which act on the camera: +

+ +
    +
  • Dragging with the right mouse button down: change azimuth and elevation angle
  • +
  • Dragging with the middle mouse button down: move the pivot up and down or left and right
  • +
  • Mouse wheel: moves the pivot forward and backward
  • +
  • Control key + mouse wheel: magnify or shrink the layout
  • +
  • Press and hold shift key: switch to top level view (see below)
  • +
  • Up/down keys: move the pivot forward or backward
  • +
  • Left/right keys: move the pivot to the left or the right
  • +
  • Control + up/down keys: change the elevation angle
  • +
  • Control + left/right keys: change the azimuth angle
  • +
+ +

+ In top level view, the navigation is slightly different: +

+ +
    +
  • Dragging with the right mouse button down: change azimuth angle
  • +
  • mouse wheel: magnify or shrink the layout
  • +
  • Up/down/left/right keys: move the pivot on the horizontal plane
  • +
+ +
+ diff --git a/src/lay/lay/doc/about/drc_ref_layer.xml b/src/lay/lay/doc/about/drc_ref_layer.xml index 0d2b34c84..4b9b0554c 100644 --- a/src/lay/lay/doc/about/drc_ref_layer.xml +++ b/src/lay/lay/doc/about/drc_ref_layer.xml @@ -1044,7 +1044,9 @@ a positive value. A horizontal displacement component can be specified too, whic
  • origin(x, y) : specifies a fixed point to align the pattern with. This point specifies the location of the reference point for one pattern cell.
  • auto_origin : lets the algorithm choose the origin. This may result is a slightly better fill coverage -as the algorithm is able to determine a pattern origin per fill island.
  • +as the algorithm is able to determine a pattern origin per island to fill. +
  • multi_origin : lets the algorithm choose the origin and repeats the fill with different origins +until no further fill cell can be fitted.
  • fill_pattern(..) : specifies the fill pattern.
  • diff --git a/src/lay/lay/doc/about/index.xml b/src/lay/lay/doc/about/index.xml index f5c93bbe2..4a7efb65a 100644 --- a/src/lay/lay/doc/about/index.xml +++ b/src/lay/lay/doc/about/index.xml @@ -18,6 +18,7 @@ + diff --git a/src/lay/lay/layHelpResources.qrc b/src/lay/lay/layHelpResources.qrc index 52e9fc2f7..0e0053df0 100644 --- a/src/lay/lay/layHelpResources.qrc +++ b/src/lay/lay/layHelpResources.qrc @@ -47,6 +47,8 @@ doc/about/lvs_ref_global.xml doc/about/lvs_ref_netter.xml doc/about/packages.xml + doc/about/25d_view.xml + doc/about/25d_screenshot.png doc/manual/adjust_origin.xml diff --git a/src/lay/lay/layMainWindow.cc b/src/lay/lay/layMainWindow.cc index d40814b05..41cf82007 100644 --- a/src/lay/lay/layMainWindow.cc +++ b/src/lay/lay/layMainWindow.cc @@ -3942,7 +3942,7 @@ MainWindow::menu_activated (const std::string &symbol) if (current_view ()) { current_view ()->menu_activated (symbol); } else { - throw tl::Exception (tl::to_string (QObject::tr ("No view is active"))); + throw tl::Exception (tl::to_string (QObject::tr ("This function needs a layout but none was available"))); } } diff --git a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui index b1901ba63..a550fe8ad 100644 --- a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui +++ b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui @@ -44,6 +44,12 @@ Monospace + + QTextEdit::NoWrap + + + false + diff --git a/src/laybasic/laybasic/layAnnotationShapes.cc b/src/laybasic/laybasic/layAnnotationShapes.cc index c7babddd1..10a43b865 100644 --- a/src/laybasic/laybasic/layAnnotationShapes.cc +++ b/src/laybasic/laybasic/layAnnotationShapes.cc @@ -89,6 +89,12 @@ AnnotationShapes::AnnotationShapes (const AnnotationShapes &d) operator= (d); } +AnnotationShapes::AnnotationShapes (const AnnotationShapes &&d) + : db::LayoutStateModel (true /*busy*/), db::Object (d) +{ + operator= (d); +} + AnnotationShapes::~AnnotationShapes () { clear (); @@ -106,7 +112,21 @@ AnnotationShapes::operator= (const AnnotationShapes &d) } return *this; } -void + +AnnotationShapes & +AnnotationShapes::operator= (const AnnotationShapes &&d) +{ + if (&d != this) { + clear (); + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new AnnotationLayerOp (true /*insert*/, d.m_layer.begin (), d.m_layer.end ())); + } + m_layer = d.m_layer; + } + return *this; +} + +void AnnotationShapes::clear () { if (manager () && manager ()->transacting ()) { @@ -126,7 +146,17 @@ AnnotationShapes::insert (const shape_type &sh) return *m_layer.insert (sh); } -void +const AnnotationShapes::shape_type & +AnnotationShapes::insert (const shape_type &&sh) +{ + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new AnnotationLayerOp (true /*insert*/, sh)); + } + invalidate_state (); // HINT: must come before the change is done! + return *m_layer.insert (sh); +} + +void AnnotationShapes::reserve (size_t n) { m_layer.reserve (n); @@ -156,7 +186,21 @@ AnnotationShapes::replace (iterator pos, const shape_type &sh) return *pos; } -void +const AnnotationShapes::shape_type & +AnnotationShapes::replace (iterator pos, const shape_type &&sh) +{ + if (&*pos != &sh && *pos != sh) { + if (manager () && manager ()->transacting ()) { + manager ()->queue (this, new AnnotationLayerOp (false /*not insert*/, *pos)); + manager ()->queue (this, new AnnotationLayerOp (true /*insert*/, sh)); + } + invalidate_state (); // HINT: must come before the change is done! + m_layer.replace (pos, sh); + } + return *pos; +} + +void AnnotationShapes::redo (db::Op *op) { AnnotationLayerOp *layop = dynamic_cast (op); diff --git a/src/laybasic/laybasic/layAnnotationShapes.h b/src/laybasic/laybasic/layAnnotationShapes.h index f715c8597..c60abb5e5 100644 --- a/src/laybasic/laybasic/layAnnotationShapes.h +++ b/src/laybasic/laybasic/layAnnotationShapes.h @@ -135,16 +135,37 @@ public: */ AnnotationShapes (const AnnotationShapes &d); + /** + * @brief Copy ctor + */ + AnnotationShapes (const AnnotationShapes &&d); + /** * @brief Assignment operator */ AnnotationShapes &operator= (const AnnotationShapes &d); + /** + * @brief Assignment operator (move) + */ + AnnotationShapes &operator= (const AnnotationShapes &&d); + /** * @brief Insert a shape_type */ const shape_type &insert (const shape_type &sh); + /** + * @brief Insert a sequence of DUserObject shapes + * + * Inserts a sequence of shapes [from,to) + */ + + /** + * @brief Insert a shape_type (move semantics) + */ + const shape_type &insert (const shape_type &&sh); + /** * @brief Insert a sequence of DUserObject shapes * @@ -212,6 +233,11 @@ public: */ const shape_type &replace (iterator pos, const shape_type &sh); + /** + * @brief Replace an element at the given position with another shape (move semantics) + */ + const shape_type &replace (iterator pos, const shape_type &&sh); + /** * @brief updates the bbox * diff --git a/src/laybasic/laybasic/layBrowserPanel.cc b/src/laybasic/laybasic/layBrowserPanel.cc index a6a16c9a3..b1421b426 100644 --- a/src/laybasic/laybasic/layBrowserPanel.cc +++ b/src/laybasic/laybasic/layBrowserPanel.cc @@ -95,6 +95,7 @@ BookmarkItem::to_string () const BrowserPanel::BrowserPanel (QWidget *parent) : QWidget (parent), m_back_dm (this, &BrowserPanel::back), + m_new_url_dm (this, &BrowserPanel::new_url), mp_dispatcher (0) { init (); @@ -125,6 +126,7 @@ BrowserPanel::init () mp_ui->browser->addAction (mp_ui->action_find); mp_ui->browser->addAction (mp_ui->action_bookmark); + mp_ui->browser->setOpenLinks (false); mp_ui->browser_bookmark_view->addAction (mp_ui->action_delete_bookmark); mp_ui->browser_bookmark_view->setContextMenuPolicy (Qt::ActionsContextMenu); @@ -138,7 +140,8 @@ BrowserPanel::init () connect (mp_ui->search_edit, SIGNAL (textEdited (const QString &)), this, SLOT (search_text_changed (const QString &))); connect (mp_ui->search_edit, SIGNAL (returnPressed ()), this, SLOT (search_edited ())); connect (mp_ui->search_button, SIGNAL (clicked ()), this, SLOT (search_edited ())); - connect (mp_ui->browser, SIGNAL (textChanged ()), this, SLOT (text_changed ())); + connect (mp_ui->browser, SIGNAL (sourceChanged (const QUrl &)), this, SLOT (source_changed ())); + connect (mp_ui->browser, SIGNAL (anchorClicked (const QUrl &)), this, SLOT (anchor_clicked (const QUrl &))); connect (mp_ui->browser, SIGNAL (backwardAvailable (bool)), mp_ui->back_pb, SLOT (setEnabled (bool))); connect (mp_ui->browser, SIGNAL (forwardAvailable (bool)), mp_ui->forward_pb, SLOT (setEnabled (bool))); connect (mp_ui->outline_tree, SIGNAL (itemActivated (QTreeWidgetItem *, int)), this, SLOT (outline_item_clicked (QTreeWidgetItem *))); @@ -218,7 +221,7 @@ BrowserPanel::title () const std::string BrowserPanel::url () const { - return m_cached_url; + return tl::to_string (mp_ui->browser->source ().toString ()); } void @@ -416,13 +419,24 @@ BrowserPanel::search_text_changed (const QString &text) } void -BrowserPanel::text_changed () +BrowserPanel::source_changed () +{ + m_new_url_dm (); +} + +void +BrowserPanel::anchor_clicked (const QUrl &url) +{ + mp_ui->browser->setSource (url); + source_changed (); +} + +void +BrowserPanel::new_url () { QString title = mp_ui->browser->document ()->metaInformation (QTextDocument::DocumentTitle); - if (title != m_current_title) { - m_current_title = title; - emit title_changed (title); - } + m_current_title = title; + emit title_changed (title); // refresh on-page search page_search_edited (); diff --git a/src/laybasic/laybasic/layBrowserPanel.h b/src/laybasic/laybasic/layBrowserPanel.h index 0b3ed3465..2fe7d8aba 100644 --- a/src/laybasic/laybasic/layBrowserPanel.h +++ b/src/laybasic/laybasic/layBrowserPanel.h @@ -441,7 +441,9 @@ protected slots: void page_search_next(); void search_text_changed(const QString &text); void search_edited (); - void text_changed (); + void source_changed (); + void anchor_clicked (const QUrl &url); + void new_url (); void outline_item_clicked (QTreeWidgetItem *item); void bookmark_item_selected (QTreeWidgetItem *item); void delete_bookmark (); @@ -462,6 +464,7 @@ private: Ui::BrowserPanel *mp_ui; bool m_schedule_back; tl::DeferredMethod m_back_dm; + tl::DeferredMethod m_new_url_dm; std::string m_search_url, m_search_query_item; QString m_current_title; QList m_search_selection; diff --git a/src/laybasic/laybasic/layD25TechnologyComponent.cc b/src/laybasic/laybasic/layD25TechnologyComponent.cc index 5c7cb2c15..753d67c05 100644 --- a/src/laybasic/laybasic/layD25TechnologyComponent.cc +++ b/src/laybasic/laybasic/layD25TechnologyComponent.cc @@ -72,7 +72,13 @@ D25TechnologyComponentEditor::commit () } std::string src = tl::to_string (src_te->toPlainText ()); - data->compile_from_source (src); + + // test-compile before setting it + db::D25TechnologyComponent tc; + tc.set_src (src); + tc.compile_from_source (); + + data->set_src (src); } void diff --git a/src/laybasic/laybasic/layNetlistBrowserPage.cc b/src/laybasic/laybasic/layNetlistBrowserPage.cc index c63bcade2..2a74de56c 100644 --- a/src/laybasic/laybasic/layNetlistBrowserPage.cc +++ b/src/laybasic/laybasic/layNetlistBrowserPage.cc @@ -1027,6 +1027,8 @@ NetlistBrowserPage::adjust_view () ebox += bbox_for_device_abstract (layout, a->device_abstract, a->trans); } + trans *= device->trans (); + } else if (net) { db::cell_index_type cell_index = net->circuit ()->cell_index (); diff --git a/src/laybasic/laybasic/layPropertiesDialog.cc b/src/laybasic/laybasic/layPropertiesDialog.cc index ddd8b0390..6aa420e11 100644 --- a/src/laybasic/laybasic/layPropertiesDialog.cc +++ b/src/laybasic/laybasic/layPropertiesDialog.cc @@ -265,7 +265,7 @@ PropertiesDialog::apply () { BEGIN_PROTECTED - db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Auto-apply changes")), m_transaction_id); + db::Transaction t (mp_manager, tl::to_string (QObject::tr ("Apply changes")), m_transaction_id); try { diff --git a/src/laybasic/laybasic/syntax/d25_text.xml b/src/laybasic/laybasic/syntax/d25_text.xml index 5e0877b74..13fa5afc3 100644 --- a/src/laybasic/laybasic/syntax/d25_text.xml +++ b/src/laybasic/laybasic/syntax/d25_text.xml @@ -5,13 +5,35 @@ + + zstart + zstop + height + + + + true + false + nil + + - + + + + + + + + + + + + - @@ -22,22 +44,52 @@ - - - + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -46,19 +98,21 @@ - + - + + + @@ -73,4 +127,12 @@ + + + + + + + + diff --git a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc index 8d974cb6d..ae3a6dfb7 100644 --- a/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc +++ b/src/plugins/streamers/gds2/db_plugin/dbGDS2Reader.cc @@ -206,7 +206,13 @@ GDS2Reader::get_string () void GDS2Reader::get_string (std::string &s) const { - s.assign ((const char *) mp_rec_buf, 0, m_reclen); + if (m_reclen == 0) { + s.clear (); + } else if (mp_rec_buf [m_reclen - 1] != 0) { + s.assign ((const char *) mp_rec_buf, m_reclen); + } else { + s.assign ((const char *) mp_rec_buf, m_reclen - 1); + } } void diff --git a/src/plugins/tools/view_25d/lay_plugin/D25View.ui b/src/plugins/tools/view_25d/lay_plugin/D25View.ui index 5e509de09..04a6aac27 100644 --- a/src/plugins/tools/view_25d/lay_plugin/D25View.ui +++ b/src/plugins/tools/view_25d/lay_plugin/D25View.ui @@ -350,9 +350,9 @@ 0 - + - Press and hold SHIFT for top view + Press and hold SHIFT for top view (<a href="int:/about/25d_view.xml">more</a>) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc index db7d059b7..a9a585e7e 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc @@ -43,7 +43,7 @@ D25Camera::~D25Camera () void D25Camera::init () { - m_fov = 90.0; + m_fov = 45.0; m_cam_azimuth = m_cam_elevation = 0.0; m_top_view = false; } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index 94b23b462..8a98ab2c4 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -89,7 +89,7 @@ public: virtual void get_menu_entries (std::vector &menu_entries) const { lay::PluginDeclaration::get_menu_entries (menu_entries); - menu_entries.push_back (lay::menu_item ("lay::d25_view", "d25_view:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("2.5d View")))); + menu_entries.push_back (lay::menu_item ("lay::d25_view", "d25_view:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("2.5d View - experimental")))); } virtual bool configure (const std::string & /*name*/, const std::string & /*value*/) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index b973cdc7f..6c57d177e 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -23,6 +23,7 @@ #include "layD25View.h" #include "layLayoutView.h" +#include "layQtTools.h" #include "ui_D25View.h" @@ -53,6 +54,8 @@ D25View::D25View (QWidget *parent) connect (mp_ui->d25_view, SIGNAL (init_failed ()), this, SLOT (init_failed ())); mp_ui->gl_stack->setCurrentIndex (0); + + lay::activate_help_links (mp_ui->doc_label); } D25View::~D25View () diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 4aaed12f1..67c6bc8c9 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -246,40 +246,23 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) } else { - // compute vector of line of sight - std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); - - // by definition the ray goes through the camera position - QVector3D hp = hit_point_with_scene (ray.second); + double d = event->angleDelta ().y () * (1.0 / (90 * 16)); if (! (event->modifiers () & Qt::ControlModifier)) { - // No Ctrl is closeup + // No Ctrl is "move horizontally along the azimuth axis" - double f = event->angleDelta ().y () * (1.0 / (90 * 8)); - m_displacement += -((f / m_scale_factor) * std::min (cam_dist (), double ((cam_position () - hp).length ()))) * ray.second; + QMatrix4x4 t; + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + QVector3D cd = t.inverted ().map (QVector3D (0, 0, cam_dist ())); + + m_displacement += d * cd; } else { // "Ctrl" is zoom - double f = exp (event->angleDelta ().y () * (1.0 / (90 * 8))); - - QVector3D initial_displacement = m_displacement; - QVector3D displacement = m_displacement; - - m_scale_factor *= f; - displacement += hp * (1.0 - f) / m_scale_factor; - - // normalize the scene translation so the scene does not "flee" - - QMatrix4x4 ct = cam_trans (); - initial_displacement = ct.map (initial_displacement); - displacement = ct.map (displacement); - - lay::normalize_scene_trans (cam_perspective (), displacement, m_scale_factor, initial_displacement.z ()); - - m_displacement = ct.inverted ().map (displacement); + m_scale_factor *= exp (d); emit scale_factor_changed (m_scale_factor); @@ -294,8 +277,65 @@ void D25ViewWidget::keyPressEvent (QKeyEvent *event) { if (event->key () == Qt::Key_Shift) { + mp_mode.reset (0); set_top_view (true); + + } else if (event->key () == Qt::Key_Up || event->key () == Qt::Key_Down) { + + if (! top_view () && (event->modifiers () & Qt::ControlModifier) != 0) { + + // Ctrl + up/down changes elevation + + double d = (event->key () == Qt::Key_Up ? 2 : -2); + + set_cam_elevation (std::max (-90.0, std::min (90.0, cam_elevation () + d))); + + } else { + + // Move "into" or "out" + + double d = (event->key () == Qt::Key_Up ? 0.1 : -0.1); + + QMatrix4x4 t; + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + QVector3D cd = t.inverted ().map (QVector3D (0, 0, cam_dist ())); + + set_displacement (displacement () + d * cd); + + } + + } else if (event->key () == Qt::Key_Left || event->key () == Qt::Key_Right) { + + if (! top_view () && (event->modifiers () & Qt::ControlModifier) != 0) { + + // Ctrl + left/right changes azumith + + double d = (event->key () == Qt::Key_Right ? 2 : -2); + + double a = cam_azimuth () + d; + if (a < -180.0) { + a += 360.0; + } else if (a > 180.0) { + a -= 360.0; + } + + set_cam_azimuth (a); + + } else { + + // Move "left" and "right" + + double d = (event->key () == Qt::Key_Left ? 0.1 : -0.1); + + QMatrix4x4 t; + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + QVector3D cd = t.inverted ().map (QVector3D (cam_dist (), 0, 0)); + + set_displacement (displacement () + d * cd); + + } + } } @@ -435,17 +475,17 @@ namespace { const db::D25LayerInfo *operator() (lay::LayoutView *view, int cv_index, int layer_index) { - std::map >::const_iterator c = m_cache.find (cv_index); + std::map >::const_iterator c = m_cache.find (cv_index); if (c != m_cache.end ()) { - std::map::const_iterator l = c->second.find (layer_index); + std::map::const_iterator l = c->second.find (layer_index); if (l != c->second.end ()) { - return l->second; + return &l->second; } else { return 0; } } - std::map &lcache = m_cache [cv_index]; + std::map &lcache = m_cache [cv_index]; const db::D25TechnologyComponent *comp = 0; @@ -457,16 +497,18 @@ namespace { if (comp) { - std::map zi_by_lp; - for (db::D25TechnologyComponent::const_iterator i = comp->begin (); i != comp->end (); ++i) { - zi_by_lp.insert (std::make_pair (i->layer (), i.operator-> ())); + std::map zi_by_lp; + + db::D25TechnologyComponent::layers_type layers = comp->compile_from_source (); + for (db::D25TechnologyComponent::layers_type::const_iterator i = layers.begin (); i != layers.end (); ++i) { + zi_by_lp.insert (std::make_pair (i->layer (), *i)); } const db::Layout &ly = cv->layout (); for (int l = 0; l < int (ly.layers ()); ++l) { if (ly.is_valid_layer (l)) { const db::LayerProperties &lp = ly.get_properties (l); - std::map::const_iterator z = zi_by_lp.find (lp); + std::map::const_iterator z = zi_by_lp.find (lp); if (z == zi_by_lp.end () && ! lp.name.empty ()) { // If possible, try by name only z = zi_by_lp.find (db::LayerProperties (lp.name)); @@ -485,7 +527,7 @@ namespace { private: - std::map > m_cache; + std::map > m_cache; }; } @@ -955,9 +997,12 @@ D25ViewWidget::paintGL () vertexes.add (-0.25 * compass_rad, 0.0, 0.6 * compass_rad); vertexes.add (0.0, 0.0, -0.8 * compass_rad); + vertexes.add (0.0, 0.0, -0.8 * compass_rad); vertexes.add (0.25 * compass_rad, 0.0, 0.6 * compass_rad); + vertexes.add (0.25 * compass_rad, 0.0, 0.6 * compass_rad); + vertexes.add (-0.25 * compass_rad, 0.0, 0.6 * compass_rad); - vertexes.draw_to (this, positions, GL_TRIANGLES); + vertexes.draw_to (this, positions, GL_LINES); // draw base plane @@ -1029,8 +1074,8 @@ D25ViewWidget::paintGL () glDisable (GL_DEPTH_TEST); - int cube_size = 64; - int cube_margin = 20; + int cube_size = 32; + int cube_margin = 40; QMatrix4x4 into_top_right_corner; into_top_right_corner.translate (1.0 - 2.0 / width () * (cube_margin + cube_size / 2), 1.0 - 2.0 / height () * (cube_margin + cube_size / 2)); diff --git a/src/tl/tl/tlReuseVector.h b/src/tl/tl/tlReuseVector.h index 5a2eb6435..d9ff78cda 100644 --- a/src/tl/tl/tlReuseVector.h +++ b/src/tl/tl/tlReuseVector.h @@ -535,6 +535,19 @@ public: } } + /** + * @brief Move constructor + * + * See operator= for a description of the copy operation. + */ + reuse_vector (reuse_vector &&d) + { + mp_start = d.mp_start; d.mp_start = 0; + mp_finish = d.mp_finish; d.mp_finish = 0; + mp_capacity = d.mp_capacity; d.mp_capacity = 0; + mp_rdata = d.mp_rdata; d.mp_rdata = 0; + } + /** * @brief Destructor */ @@ -562,6 +575,20 @@ public: return *this; } + /** + * @brief Assignment (move) + */ + reuse_vector &operator= (reuse_vector &&d) + { + if (&d != this) { + mp_start = d.mp_start; d.mp_start = 0; + mp_finish = d.mp_finish; d.mp_finish = 0; + mp_capacity = d.mp_capacity; d.mp_capacity = 0; + mp_rdata = d.mp_rdata; d.mp_rdata = 0; + } + return *this; + } + /** * @brief Assignment * diff --git a/src/tl/tl/tlVector.h b/src/tl/tl/tlVector.h index b4ce0e5a1..0bbd77803 100644 --- a/src/tl/tl/tlVector.h +++ b/src/tl/tl/tlVector.h @@ -60,6 +60,11 @@ public: */ explicit vector (const tl::vector &d) : base (d) { } + /** + * @brief Move constructor + */ + explicit vector (const tl::vector &&d) : base (d) { } + /** * @brief Assignment */ @@ -71,6 +76,17 @@ public: return *this; } + /** + * @brief Assignment (Move) + */ + vector &operator= (const tl::vector &&d) + { + if (&d != this) { + base::operator= (d); + } + return *this; + } + /** * @brief Initialization with value and length */ diff --git a/testdata/drc/drcSimpleTests_46.drc b/testdata/drc/drcSimpleTests_46.drc new file mode 100644 index 000000000..1278a4681 --- /dev/null +++ b/testdata/drc/drcSimpleTests_46.drc @@ -0,0 +1,25 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +l1 = input(1, 0) +l1.output(1, 0) + +to_fill = extent - l1 + +fp1 = fill_pattern("FP1").shape(10, 0, box(0, 0, 800.nm, 800.nm)).origin(-100.nm, -100.nm) +to_fill = to_fill.fill_with_left(fp1, hstep(1.um), vstep(200.nm, 1.um), multi_origin) + +fp2 = fill_pattern("FP2").shape(10, 0, box(0, 0, 400.nm, 400.nm)).origin(-50.nm, -50.nm) +to_fill = to_fill.fill_with_left(fp2, hstep(0.5.um), vstep(100.nm, 0.5.um), multi_origin) + +fp3 = fill_pattern("FP3").shape(10, 0, box(0, 0, 200.nm, 200.nm)).origin(-25.nm, -25.nm) +to_fill = to_fill.fill_with_left(fp3, hstep(0.25.um), vstep(50.nm, 0.25.um), multi_origin) + +to_fill.output(100, 0) + + diff --git a/testdata/drc/drcSimpleTests_46.gds b/testdata/drc/drcSimpleTests_46.gds new file mode 100644 index 000000000..e9e05712b Binary files /dev/null and b/testdata/drc/drcSimpleTests_46.gds differ diff --git a/testdata/drc/drcSimpleTests_47.drc b/testdata/drc/drcSimpleTests_47.drc new file mode 100644 index 000000000..0d4fb3a06 --- /dev/null +++ b/testdata/drc/drcSimpleTests_47.drc @@ -0,0 +1,27 @@ + +source $drc_test_source +target $drc_test_target + +if $drc_test_deep + deep +end + +tiles(20, 20) + +l1 = input(1, 0) +l1.output(1, 0) + +to_fill = extent - l1 + +fp1 = fill_pattern("FP1").shape(10, 0, box(0, 0, 800.nm, 800.nm)).origin(-100.nm, -100.nm) +to_fill = to_fill.fill_with_left(fp1, hstep(1.um), vstep(200.nm, 1.um), multi_origin) + +fp2 = fill_pattern("FP2").shape(10, 0, box(0, 0, 400.nm, 400.nm)).origin(-50.nm, -50.nm) +to_fill = to_fill.fill_with_left(fp2, hstep(0.5.um), vstep(100.nm, 0.5.um), multi_origin) + +fp3 = fill_pattern("FP3").shape(10, 0, box(0, 0, 200.nm, 200.nm)).origin(-25.nm, -25.nm) +to_fill = to_fill.fill_with_left(fp3, hstep(0.25.um), vstep(50.nm, 0.25.um), multi_origin) + +to_fill.output(100, 0) + + diff --git a/testdata/drc/drcSimpleTests_47.gds b/testdata/drc/drcSimpleTests_47.gds new file mode 100644 index 000000000..e9e05712b Binary files /dev/null and b/testdata/drc/drcSimpleTests_47.gds differ diff --git a/testdata/drc/drcSimpleTests_au41.gds b/testdata/drc/drcSimpleTests_au41.gds index f509aa097..edfe1a1fe 100644 Binary files a/testdata/drc/drcSimpleTests_au41.gds and b/testdata/drc/drcSimpleTests_au41.gds differ diff --git a/testdata/drc/drcSimpleTests_au46.gds b/testdata/drc/drcSimpleTests_au46.gds new file mode 100644 index 000000000..4f3ebe68b Binary files /dev/null and b/testdata/drc/drcSimpleTests_au46.gds differ diff --git a/testdata/drc/drcSimpleTests_au47.gds b/testdata/drc/drcSimpleTests_au47.gds new file mode 100644 index 000000000..18de4fcf8 Binary files /dev/null and b/testdata/drc/drcSimpleTests_au47.gds differ