diff --git a/src/db/db/db.pro b/src/db/db/db.pro index df5648b48..35293190d 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -204,7 +204,6 @@ SOURCES = \ gsiDeclDbNetlistCrossReference.cc \ gsiDeclDbLayoutVsSchematic.cc \ dbNetlistObject.cc \ - dbD25TechnologyComponent.cc \ gsiDeclDbTexts.cc \ dbTexts.cc \ dbDeepTexts.cc \ @@ -381,7 +380,6 @@ HEADERS = \ dbLayoutVsSchematicFormatDefs.h \ dbLayoutVsSchematic.h \ dbNetlistObject.h \ - dbD25TechnologyComponent.h \ dbTexts.h \ dbDeepTexts.h \ dbAsIfFlatTexts.h \ diff --git a/src/db/db/dbCellVariants.cc b/src/db/db/dbCellVariants.cc index 0126a75c3..5f36cc7b7 100644 --- a/src/db/db/dbCellVariants.cc +++ b/src/db/db/dbCellVariants.cc @@ -511,19 +511,52 @@ VariantsCollectorBase::create_var_instances_non_tl_invariant (db::Cell &in_cell, std::map >::const_iterator f = var_table.find (i->object ().cell_index ()); if (f == var_table.end ()) { - in_cell.insert (*i); + in_cell.insert (*i); } else { const std::map &vt = f->second; - for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { + bool need_explode = false; + bool first = true; + db::cell_index_type ci = 0; + + for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end () && ! need_explode; ++ia) { db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans (*ia))); std::map::const_iterator v = vt.find (rt); tl_assert (v != vt.end ()); - in_cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (v->second), i->complex_trans (*ia)), i->properties_id ())); + if (first) { + ci = v->second; + first = false; + } else { + need_explode = (ci != v->second); + } + + } + + if (need_explode) { + + for (db::CellInstArray::iterator ia = i->begin (); ! ia.at_end (); ++ia) { + + db::ICplxTrans rt = mp_red->reduce (for_var * mp_red->reduce_trans (i->complex_trans (*ia))); + std::map::const_iterator v = vt.find (rt); + tl_assert (v != vt.end ()); + + in_cell.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (v->second), i->complex_trans (*ia)), i->properties_id ())); + + } + + } else if (ci != i->object ().cell_index ()) { + + db::CellInstArray new_array = *i; + new_array.object () = db::CellInst (ci); + in_cell.insert (db::CellInstArrayWithProperties (new_array, i->properties_id ())); + + } else { + + in_cell.insert (*i); } diff --git a/src/db/db/dbD25TechnologyComponent.cc b/src/db/db/dbD25TechnologyComponent.cc deleted file mode 100644 index 9b421ed7e..000000000 --- a/src/db/db/dbD25TechnologyComponent.cc +++ /dev/null @@ -1,436 +0,0 @@ - -/* - - KLayout Layout Viewer - Copyright (C) 2006-2022 Matthias Koefferlein - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#include "dbD25TechnologyComponent.h" -#include "tlClassRegistry.h" -#include "tlString.h" - -namespace db -{ - -std::string d25_component_name () -{ - return std::string ("d25"); -} - -std::string d25_description () -{ - return tl::to_string (tr ("Z stack (2.5d)")); -} - -// ----------------------------------------------------------------------------------------- -// D25LayerInfo implementation - -D25LayerInfo::D25LayerInfo () - : m_layer (), m_zstart (0.0), m_zstop (0.0) -{ - // .. nothing yet .. -} - -D25LayerInfo::~D25LayerInfo () -{ - // .. nothing yet .. -} - -D25LayerInfo::D25LayerInfo (const D25LayerInfo &other) -{ - operator= (other); -} - -D25LayerInfo & -D25LayerInfo::operator= (const D25LayerInfo &other) -{ - if (this != &other) { - m_layer = other.m_layer; - m_zstart = other.m_zstart; - m_zstop = other.m_zstop; - } - return *this; -} - -bool -D25LayerInfo::operator== (const D25LayerInfo &other) const -{ - return fabs (m_zstart - other.m_zstart) < db::epsilon && fabs (m_zstop - other.m_zstop) < db::epsilon; -} - -void -D25LayerInfo::set_layer (const db::LayerProperties &l) -{ - m_layer = l; -} - -void -D25LayerInfo::set_layer_from_string (const std::string &l) -{ - db::LayerProperties lp; - tl::Extractor ex (l.c_str ()); - try { - lp.read (ex); - } catch (tl::Exception &) { - // ignore errors for now. - } - m_layer = lp; -} - -std::string -D25LayerInfo::layer_as_string () const -{ - return m_layer.to_string (); -} - -void -D25LayerInfo::set_zstart (double z0) -{ - m_zstart = z0; -} - -void -D25LayerInfo::set_zstop (double z1) -{ - m_zstop = z1; -} - -// ----------------------------------------------------------------------------------- -// D25TechnologyComponent implementation - -D25TechnologyComponent::D25TechnologyComponent () - : db::TechnologyComponent (d25_component_name (), d25_description ()) -{ - // 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" - "#\n" - "# zstart The lower z position of the extruded layer in µm\n" - "# 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',\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" - "# 'zstart' and 'zstop'.\n" - "#\n" - "# Examples:\n" - "# 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" - "#\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_src = d.m_src; -} - -D25TechnologyComponent::layers_type -D25TechnologyComponent::compile_from_source () const -{ - layers_type layers; - - int current_line = 0; - - try { - - 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; - - tl::Extractor ex (l->c_str ()); - - if (ex.test ("#")) { - // 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 (! layers.empty ()) { - info.set_zstart (layers.back ().zstop ()); - info.set_zstop (layers.back ().zstop ()); - } - - tl::Variant z0, z1, h; - std::vector args; - - db::LayerProperties lp; - lp.read (ex); - info.set_layer (lp); - - ex.expect (":"); - - while (! ex.at_end ()) { - - if (ex.test ("#")) { - break; - } - - tl::Expression pvx; - - std::string pn; - if (ex.try_read_name (pn)) { - ex.expect ("="); - eval.parse (pvx, ex); - } else { - eval.parse (pvx, ex); - } - - double pv = pvx.execute ().to_double (); - - ex.test (","); - - if (pn.empty ()) { - args.push_back (pv); - } else if (pn == "zstart") { - z0 = pv; - } else if (pn == "zstop") { - z1 = pv; - } else if (pn == "height") { - h = pv; - } else { - throw tl::Exception (tl::to_string (tr ("Invalid parameter name: ")) + pn); - } - - } - - if (args.size () == 0) { - if (z0.is_nil () && z1.is_nil ()) { - if (! h.is_nil ()) { - info.set_zstop (info.zstop () + h.to_double ()); - } - } else if (z0.is_nil ()) { - info.set_zstop (z1.to_double ()); - if (! h.is_nil ()) { - info.set_zstart (info.zstop () - h.to_double ()); - } - } else if (z1.is_nil ()) { - info.set_zstart (z0.to_double ()); - if (! h.is_nil ()) { - info.set_zstop (info.zstart () + h.to_double ()); - } - } else { - info.set_zstart (z0.to_double ()); - info.set_zstop (z1.to_double ()); - } - } else if (args.size () == 1) { - if (! h.is_nil ()) { - if (! z0.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstart already given"))); - } - if (! z1.is_nil ()) { - 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 ("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 ("Redundant parameters: zstart already given"))); - } - if (! z1.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop already given"))); - } - if (! h.is_nil ()) { - throw tl::Exception (tl::to_string (tr ("Redundant parameters: height implicitly given"))); - } - info.set_zstart (args[0]); - info.set_zstop (args[1]); - } else { - throw tl::Exception (tl::to_string (tr ("Too many parameters (max 2)"))); - } - - 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)); - } - - return layers; -} - -std::string -D25TechnologyComponent::to_string () const -{ - layers_type layers = compile_from_source (); - std::string res; - - for (layers_type::const_iterator i = layers.begin (); i != layers.end (); ++i) { - if (! res.empty ()) { - res += "\n"; - } - res += i->layer ().to_string () + ": zstart=" + tl::to_string (i->zstart ()) + ", zstop=" + tl::to_string (i->zstop ()); - } - - return res; -} - -// ----------------------------------------------------------------------------------- -// D25TechnologyComponent technology component registration - -class D25TechnologyComponentProvider - : public db::TechnologyComponentProvider -{ -public: - D25TechnologyComponentProvider () - : db::TechnologyComponentProvider () - { - // .. nothing yet .. - } - - virtual db::TechnologyComponent *create_component () const - { - return new D25TechnologyComponent (); - } - - virtual tl::XMLElementBase *xml_element () const - { - return new db::TechnologyComponentXMLElement (d25_component_name (), - tl::make_member (&D25TechnologyComponent::src, &D25TechnologyComponent::set_src, "src") - ); - } -}; - -static tl::RegisteredClass tc_decl (new D25TechnologyComponentProvider (), 3100, d25_component_name ().c_str ()); - -} diff --git a/src/db/db/dbD25TechnologyComponent.h b/src/db/db/dbD25TechnologyComponent.h deleted file mode 100644 index db38b3124..000000000 --- a/src/db/db/dbD25TechnologyComponent.h +++ /dev/null @@ -1,106 +0,0 @@ - -/* - - KLayout Layout Viewer - Copyright (C) 2006-2022 Matthias Koefferlein - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - -#ifndef HDR_dbD25TechnologyComponent -#define HDR_dbD25TechnologyComponent - -#include "dbTechnology.h" -#include "dbLayerProperties.h" - -namespace db -{ - -class DB_PUBLIC D25LayerInfo -{ -public: - D25LayerInfo (); - ~D25LayerInfo (); - D25LayerInfo (const D25LayerInfo &other); - D25LayerInfo &operator= (const D25LayerInfo &other); - - bool operator== (const D25LayerInfo &other) const; - - const db::LayerProperties &layer () const - { - return m_layer; - } - - void set_layer_from_string (const std::string &l); - std::string layer_as_string () const; - - void set_layer (const db::LayerProperties &l); - - double zstart () const - { - return m_zstart; - } - - void set_zstart (double z0); - - double zstop () const - { - return m_zstop; - } - - void set_zstop (double z1); - -private: - db::LayerProperties m_layer; - double m_zstart, m_zstop; -}; - -class DB_PUBLIC D25TechnologyComponent - : public db::TechnologyComponent -{ -public: - D25TechnologyComponent (); - D25TechnologyComponent (const D25TechnologyComponent &d); - - typedef std::list layers_type; - - layers_type compile_from_source () const; - - const std::string &src () const - { - return m_src; - } - - // for persistency only, use "compile_from_source" to read from a source string - void set_src (const std::string &s) - { - m_src = s; - } - - std::string to_string () const; - - db::TechnologyComponent *clone () const - { - return new D25TechnologyComponent (*this); - } - -private: - std::string m_src; -}; - -} - -#endif diff --git a/src/db/db/dbHierProcessor.cc b/src/db/db/dbHierProcessor.cc index 3c9d1215e..a54b9676f 100644 --- a/src/db/db/dbHierProcessor.cc +++ b/src/db/db/dbHierProcessor.cc @@ -1063,11 +1063,6 @@ private: void collect_instance_interactions (const db::CellInstArray *inst1, const db::CellInstArray *inst2) { -#if 0 -printf("@@@ check instance interactions %s (#%d, %s) <-> %s (#%d, %s)\n", - mp_subject_layout->cell_name (inst1->object ().cell_index ()), int (inst1->size ()), (inst1->bbox(db::box_convert (*mp_subject_layout)).to_string()).c_str(), - mp_intruder_layout->cell_name (inst2->object ().cell_index ()), int (inst2->size ()), (inst2->bbox(db::box_convert (*mp_intruder_layout)).to_string()).c_str()); // @@@ -#endif // TODO: this algorithm is not in particular effective for identical arrays const db::Cell &cell1 = mp_subject_layout->cell (inst1->object ().cell_index ()); @@ -1076,9 +1071,6 @@ printf("@@@ check instance interactions %s (#%d, %s) <-> %s (#%d, %s)\n", std::unordered_map > > interactions_cache; -#if 0 -printf("@@@ -> #%d\n", int(inst1->size())); -#endif for (db::CellInstArray::iterator n = inst1->begin (); ! n.at_end (); ++n) { db::ICplxTrans tn1 = inst1->complex_trans (*n); @@ -1482,9 +1474,6 @@ void local_processor::compute_contexts (local_processor_contexts::context_key_type &intruders, db::Coord dist) const { -#if 0 // @@@ -printf("@@@ --- compute_contexts (%s @ %s)\n", mp_subject_layout->cell_name (subject_cell->cell_index ()), subject_cell_inst.to_string().c_str()); fflush(stdout); -#endif CRONOLOGY_COLLECTION_BRACKET(event_compute_contexts) if (tl::verbosity () >= m_base_verbosity + 20) { diff --git a/src/db/db/dbLayoutDiff.cc b/src/db/db/dbLayoutDiff.cc index e57cd0240..e7940a24b 100644 --- a/src/db/db/dbLayoutDiff.cc +++ b/src/db/db/dbLayoutDiff.cc @@ -287,6 +287,32 @@ private: db::Coord m_tolerance; }; +/** + * @brief A fuzzy compare operator for edge pairs + * Compares two edge pair objects applying a tolerance between them. The tolerance is the allowed deviation + * of points in database units. + */ +struct EdgePairCompareOpWithTolerance +{ + EdgePairCompareOpWithTolerance (db::Coord tolerance) + : m_ec (tolerance) + { } + + bool operator() (const db::EdgePair &a, const db::EdgePair &b) const + { + if (m_ec (a.first (), b.first ())) { + return true; + } else if (m_ec (b.first (), a.first ())) { + return false; + } else { + return m_ec (a.second (), b.second ()); + } + } + +private: + EdgeCompareOpWithTolerance m_ec; +}; + /** * @brief A fuzzy compare operator for boxes * Compares two box objects applying a tolerance between them. The tolerance is the allowed deviation @@ -492,6 +518,12 @@ make_edge_compare_func (db::Coord tolerance) return pair_compare_func > (EdgeCompareOpWithTolerance (tolerance), std_compare_func ()); } +pair_compare_func > +make_edge_pair_compare_func (db::Coord tolerance) +{ + return pair_compare_func > (EdgePairCompareOpWithTolerance (tolerance), std_compare_func ()); +} + pair_compare_func > make_box_compare_func (db::Coord tolerance) { @@ -540,6 +572,21 @@ collect_edges (const db::Layout & /*l*/, const db::Cell *c, unsigned int layer, } } +static void +collect_edge_pairs (const db::Layout & /*l*/, const db::Cell *c, unsigned int layer, unsigned int flags, std::vector< std::pair > &shapes, PropertyMapper &pn) +{ + shapes.clear (); + + for (db::ShapeIterator s = c->shapes (layer).begin (db::ShapeIterator::EdgePairs); !s.at_end (); ++s) { + db::properties_id_type prop_id = 0; + if (! (flags & layout_diff::f_no_properties)) { + prop_id = pn (s->prop_id ()); + } + shapes.push_back (std::make_pair (db::EdgePair (), prop_id)); + s->edge_pair (shapes.back ().first); + } +} + static void collect_boxes (const db::Layout &, const db::Cell *c, unsigned int layer, unsigned int flags, std::vector< std::pair > &shapes, PropertyMapper &pn) { @@ -828,6 +875,8 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout std::vector > boxes_b; std::vector > edges_a; std::vector > edges_b; + std::vector > edge_pairs_a; + std::vector > edge_pairs_b; for (unsigned int cci = 0; cci < common_cells.size (); ++cci) { @@ -1053,6 +1102,31 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout r.end_edge_differences (); } + // compare edge pairs + + edge_pairs_a.clear(); + edge_pairs_b.clear(); + if (is_valid_a) { + collect_edge_pairs (a, cell_a, layer_a, flags, edge_pairs_a, prop_normalize_a); + } + if (is_valid_b) { + collect_edge_pairs (b, cell_b, layer_b, flags, edge_pairs_b, prop_normalize_b); + } + + reduce (edge_pairs_a, edge_pairs_b, make_edge_pair_compare_func (tolerance), tolerance > 0); + + if (!edge_pairs_a.empty () || !edge_pairs_b.empty ()) { + differs = true; + if (flags & layout_diff::f_silent) { + return false; + } + r.begin_edge_pair_differences (); + if (verbose) { + r.detailed_diff (n.properties_repository (), edge_pairs_a, edge_pairs_b); + } + r.end_edge_pair_differences (); + } + r.end_layer (); } @@ -1130,6 +1204,9 @@ public: void begin_edge_differences (); void detailed_diff (const db::PropertiesRepository &pr, const std::vector > &a, const std::vector > &b); void end_edge_differences (); + void begin_edge_pair_differences (); + void detailed_diff (const db::PropertiesRepository &pr, const std::vector > &a, const std::vector > &b); + void end_edge_pair_differences (); void begin_text_differences (); void detailed_diff (const db::PropertiesRepository &pr, const std::vector > &a, const std::vector > &b); void end_text_differences (); @@ -1525,6 +1602,34 @@ PrintingDifferenceReceiver::end_edge_differences () { } +void +PrintingDifferenceReceiver::begin_edge_pair_differences () +{ + try { + enough (tl::error) << "Edge pairs differ for layer " << m_layer.to_string () << " in cell " << m_cellname; + } catch (tl::CancelException &) { + // ignore cancel exceptions + } +} + +void +PrintingDifferenceReceiver::detailed_diff (const db::PropertiesRepository &pr, const std::vector > &a, const std::vector > &b) +{ + try { + enough (tl::info) << "Not in b but in a:"; + print_diffs (pr, a, b); + enough (tl::info) << "Not in a but in b:"; + print_diffs (pr, b, a); + } catch (tl::CancelException &) { + // ignore cancel exceptions + } +} + +void +PrintingDifferenceReceiver::end_edge_pair_differences () +{ +} + void PrintingDifferenceReceiver::begin_text_differences () { diff --git a/src/db/db/dbLayoutDiff.h b/src/db/db/dbLayoutDiff.h index ed0e01e0b..4482c5009 100644 --- a/src/db/db/dbLayoutDiff.h +++ b/src/db/db/dbLayoutDiff.h @@ -119,6 +119,9 @@ public: virtual void begin_edge_differences () { } virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector > & /*a*/, const std::vector > & /*b*/) { } virtual void end_edge_differences () { } + virtual void begin_edge_pair_differences () { } + virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector > & /*a*/, const std::vector > & /*b*/) { } + virtual void end_edge_pair_differences () { } virtual void begin_text_differences () { } virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector > & /*a*/, const std::vector > & /*b*/) { } virtual void end_text_differences () { } diff --git a/src/db/db/dbLayoutUtils.cc b/src/db/db/dbLayoutUtils.cc index 3f18ff33a..dea4ab705 100644 --- a/src/db/db/dbLayoutUtils.cc +++ b/src/db/db/dbLayoutUtils.cc @@ -25,6 +25,7 @@ #include "dbCellVariants.h" #include "dbPolygonTools.h" #include "tlProgress.h" +#include "tlTimer.h" namespace db { @@ -436,9 +437,38 @@ ContextCache::find_layout_context (db::cell_index_type from, db::cell_index_type // ------------------------------------------------------------ // Scale and snap a layout +static void +scale_and_snap_cell_instance (db::CellInstArray &ci, const db::ICplxTrans &tr, const db::ICplxTrans &trinv, const db::Vector &delta, db::Coord g, db::Coord m, db::Coord d) +{ + db::Trans ti (ci.front ()); + + db::Vector ti_disp = ti.disp (); + ti_disp.transform (tr); + ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, delta.x (), g, m, d, delta.y ()); + ti_disp.transform (trinv); + + ci.move (ti_disp - ti.disp ()); +} + +static db::Edge +scaled_and_snapped_edge (const db::Edge &e, db::Coord g, db::Coord m, db::Coord d, db::Coord ox, db::Coord oy) +{ + int64_t dg = int64_t (g) * int64_t (d); + + int64_t x1 = snap_to_grid (int64_t (e.p1 ().x ()) * m + int64_t (ox), dg) / int64_t (d); + int64_t y1 = snap_to_grid (int64_t (e.p1 ().y ()) * m + int64_t (oy), dg) / int64_t (d); + + int64_t x2 = snap_to_grid (int64_t (e.p2 ().x ()) * m + int64_t (ox), dg) / int64_t (d); + int64_t y2 = snap_to_grid (int64_t (e.p2 ().y ()) * m + int64_t (oy), dg) / int64_t (d); + + return db::Edge (db::Point (x1, y1), db::Point (x2, y2)); +} + void scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db::Coord d) { + tl::SelfTimer timer (tl::verbosity () >= 31, tl::to_string (tr ("scale_and_snap"))); + if (g < 0) { throw tl::Exception (tl::to_string (tr ("Snapping requires a positive grid value"))); } @@ -453,8 +483,11 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db db::cell_variants_collector vars (db::ScaleAndGridReducer (g, m, d)); - vars.collect (layout, cell); - vars.separate_variants (layout, cell); + { + tl::SelfTimer timer1 (tl::verbosity () >= 41, tl::to_string (tr ("scale_and_snap: variant formation"))); + vars.collect (layout, cell); + vars.separate_variants (layout, cell); + } std::set called_cells; cell.collect_called_cells (called_cells); @@ -463,9 +496,10 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db db::LayoutLocker layout_locker (&layout); layout.update (); - std::vector heap; + tl::SelfTimer timer2 (tl::verbosity () >= 41, tl::to_string (tr ("scale_and_snap: snapping and scaling"))); - unsigned int work_layer = layout.insert_layer (); + std::vector heap; + std::vector iterated_array_vectors; for (db::Layout::iterator c = layout.begin (); c != layout.end (); ++c) { @@ -486,7 +520,7 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db for (db::Layout::layer_iterator l = layout.begin_layers (); l != layout.end_layers (); ++l) { db::Shapes &s = c->shapes ((*l).first); - db::Shapes &out = c->shapes (work_layer); + db::Shapes new_shapes (layout.is_editable ()); for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); ! si.at_end (); ++si) { @@ -495,7 +529,20 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db poly.transform (tr); poly = scaled_and_snapped_polygon (poly, g, m, d, tr_disp.x (), g, m, d, tr_disp.y (), heap); poly.transform (trinv); - out.insert (poly); + + if (si->is_box () && poly.is_box ()) { + if (si->has_prop_id ()) { + new_shapes.insert (db::BoxWithProperties (poly.box (), si->prop_id ())); + } else { + new_shapes.insert (poly.box ()); + } + } else { + if (si->has_prop_id ()) { + new_shapes.insert (db::PolygonWithProperties (poly, si->prop_id ())); + } else { + new_shapes.insert (poly); + } + } } @@ -506,48 +553,94 @@ scale_and_snap (db::Layout &layout, db::Cell &cell, db::Coord g, db::Coord m, db text.transform (tr); text.trans (db::Trans (text.trans ().rot (), scaled_and_snapped_vector (text.trans ().disp (), g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()))); text.transform (trinv); - out.insert (text); + + if (si->has_prop_id ()) { + new_shapes.insert (db::TextWithProperties (text, si->prop_id ())); + } else { + new_shapes.insert (text); + } } - s.swap (out); - out.clear (); + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::Edges); ! si.at_end (); ++si) { + + db::Edge edge; + si->edge (edge); + edge.transform (tr); + edge = scaled_and_snapped_edge (edge, g, m , d, tr_disp.x (), tr_disp.y ()); + edge.transform (trinv); + + if (si->has_prop_id ()) { + new_shapes.insert (db::EdgeWithProperties (edge, si->prop_id ())); + } else { + new_shapes.insert (edge); + } + + } + + for (db::Shapes::shape_iterator si = s.begin (db::ShapeIterator::EdgePairs); ! si.at_end (); ++si) { + + db::EdgePair edge_pair; + si->edge_pair (edge_pair); + edge_pair.transform (tr); + edge_pair = db::EdgePair (scaled_and_snapped_edge (edge_pair.first (), g, m , d, tr_disp.x (), tr_disp.y ()), + scaled_and_snapped_edge (edge_pair.second (), g, m , d, tr_disp.x (), tr_disp.y ())); + edge_pair.transform (trinv); + + if (si->has_prop_id ()) { + new_shapes.insert (db::EdgePairWithProperties (edge_pair, si->prop_id ())); + } else { + new_shapes.insert (edge_pair); + } + + } + + s.swap (new_shapes); } // Snap instance placements to grid and magnify // NOTE: we can modify the instances because the ScaleAndGridReducer marked every cell with children // as a variant cell (an effect of ScaleAndGridReducer::want_variants(cell) == true where cells have children). - // Variant cells are not copied blindly back to the original layout. - - std::list new_insts; + // The variant formation also made sure the iterated and regular arrays are exploded where required. for (db::Cell::const_iterator inst = c->begin (); ! inst.at_end (); ++inst) { const db::CellInstArray &ia = inst->cell_inst (); - for (db::CellInstArray::iterator i = ia.begin (); ! i.at_end (); ++i) { - db::Trans ti (*i); - db::Vector ti_disp = ti.disp (); - ti_disp.transform (tr); - ti_disp = scaled_and_snapped_vector (ti_disp, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); - ti_disp.transform (trinv); - ti.disp (ti_disp); + iterated_array_vectors.clear (); + db::Vector a, b; + unsigned long na, nb; - if (ia.is_complex ()) { - new_insts.push_back (db::CellInstArray (ia.object (), ia.complex_trans (ti))); - } else { - new_insts.push_back (db::CellInstArray (ia.object (), ti)); + db::CellInstArray new_array (ia); + + if (ia.is_iterated_array (&iterated_array_vectors)) { + + bool needs_update = false; + for (std::vector::iterator i = iterated_array_vectors.begin (); i != iterated_array_vectors.end (); ++i) { + db::Vector v = scaled_and_snapped_vector (*i, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + if (v != *i) { + needs_update = true; + *i = v; + } } + if (needs_update) { + new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), iterated_array_vectors.begin (), iterated_array_vectors.end ()); + } + + } else if (ia.is_regular_array (a, b, na, nb)) { + + a = scaled_and_snapped_vector (a, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + b = scaled_and_snapped_vector (b, g, m, d, tr_disp.x (), g, m, d, tr_disp.y ()); + + new_array = db::CellInstArray (ia.object (), ia.complex_trans (ia.front ()), a, b, na, nb); + } - } + scale_and_snap_cell_instance (new_array, tr, trinv, tr_disp, g, m, d); + c->replace (*inst, new_array); - c->clear_insts (); - - for (std::list::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) { - c->insert (*i); } } diff --git a/src/db/db/dbTestSupport.cc b/src/db/db/dbTestSupport.cc index aa5522df0..090e849a2 100644 --- a/src/db/db/dbTestSupport.cc +++ b/src/db/db/dbTestSupport.cc @@ -138,7 +138,7 @@ void compare_layouts (tl::TestBase *_this, const db::Layout &layout, const std:: equal = db::compare_layouts (*subject, layout_au, (n > 0 ? db::layout_diff::f_silent : db::layout_diff::f_verbose) | ((norm & AsPolygons) != 0 ? db::layout_diff::f_boxes_as_polygons + db::layout_diff::f_paths_as_polygons : 0) - | db::layout_diff::f_flatten_array_insts + | ((norm & WithArrays) != 0 ? 0 : db::layout_diff::f_flatten_array_insts) /*| db::layout_diff::f_no_text_details | db::layout_diff::f_no_text_orientation*/ , tolerance, 100 /*max diff lines*/); if (equal && n > 0) { diff --git a/src/db/db/dbTestSupport.h b/src/db/db/dbTestSupport.h index 9b031fdce..8f89cf7e9 100644 --- a/src/db/db/dbTestSupport.h +++ b/src/db/db/dbTestSupport.h @@ -56,7 +56,8 @@ enum NormalizationMode WriteOAS = 2, // normalize subject by writing to OASIS and reading back NormFileMask = 7, // bits the extract for file mode NoContext = 8, // write tmp file without context - AsPolygons = 16 // paths and boxes are treated as polygons + AsPolygons = 16, // paths and boxes are treated as polygons + WithArrays = 32 // do not flatten arrays }; /** diff --git a/src/db/unit_tests/dbD25TechnologyComponentTests.cc b/src/db/unit_tests/dbD25TechnologyComponentTests.cc deleted file mode 100644 index 30ac2b807..000000000 --- a/src/db/unit_tests/dbD25TechnologyComponentTests.cc +++ /dev/null @@ -1,102 +0,0 @@ - -/* - - KLayout Layout Viewer - Copyright (C) 2006-2022 Matthias Koefferlein - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - - - -#include "dbD25TechnologyComponent.h" -#include "tlUnitTest.h" - - -TEST(1) -{ - db::D25TechnologyComponent comp; - - 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.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.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.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.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.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.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.set_src ("blabla"); - comp.compile_from_source (); - EXPECT_EQ (false, true); - } catch (...) { } - - try { - comp.set_src ("1/0: 1 2 3"); - comp.compile_from_source (); - EXPECT_EQ (false, true); - } catch (...) { } - - try { - comp.set_src ("1/0: foo=1 bar=2"); - comp.compile_from_source (); - EXPECT_EQ (false, true); - } catch (...) { } - - try { - 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/dbLayoutUtilsTests.cc b/src/db/unit_tests/dbLayoutUtilsTests.cc index 3dac06878..26130e050 100644 --- a/src/db/unit_tests/dbLayoutUtilsTests.cc +++ b/src/db/unit_tests/dbLayoutUtilsTests.cc @@ -25,6 +25,8 @@ #include "dbCellMapping.h" #include "dbTestSupport.h" #include "dbReader.h" +#include "dbLayoutDiff.h" +#include "dbPropertiesRepository.h" #include "tlString.h" #include "tlUnitTest.h" @@ -653,3 +655,127 @@ TEST(18_scale_and_snap) CHECKPOINT(); db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns3.gds"); } + +TEST(19_scale_and_snap_basic) +{ + db::Layout l1; + db::Layout l2; + + db::PropertiesRepository::properties_set ps1; + ps1.insert (std::make_pair (l1.properties_repository ().prop_name_id (tl::Variant ("p")), tl::Variant (17))); + db::properties_id_type pid1 = l1.properties_repository ().properties_id (ps1); + + db::PropertiesRepository::properties_set ps2; + ps2.insert (std::make_pair (l2.properties_repository ().prop_name_id (tl::Variant ("p")), tl::Variant (17))); + db::properties_id_type pid2 = l2.properties_repository ().properties_id (ps2); + + db::Cell &top1 = l1.cell (l1.add_cell ("TOP")); + db::Cell &top2 = l2.cell (l2.add_cell ("TOP")); + + db::Cell &a1 = l1.cell (l1.add_cell ("A")); + db::Cell &a2a = l2.cell (l2.add_cell ("A")); + + unsigned int layer1 = l1.insert_layer (db::LayerProperties (1, 0)); + unsigned int layer2 = l2.insert_layer (db::LayerProperties (1, 0)); + + a1.shapes (layer1).insert (db::Box (0, 0, 100, 100)); + a2a.shapes (layer2).insert (db::Box (0, 0, 100, 100)); + + top1.shapes (layer1).insert (db::Box (11, 21, 31, 41)); + top2.shapes (layer2).insert (db::Box (10, 20, 30, 40)); + + top1.shapes (layer1).insert (db::BoxWithProperties (db::Box (11, 21, 31, 41), pid1)); + top2.shapes (layer2).insert (db::BoxWithProperties (db::Box (10, 20, 30, 40), pid2)); + + top1.shapes (layer1).insert (db::Edge (11, 21, 31, 41)); + top2.shapes (layer2).insert (db::Edge (10, 20, 30, 40)); + + top1.shapes (layer1).insert (db::EdgeWithProperties (db::Edge (11, 21, 31, 41), pid1)); + top2.shapes (layer2).insert (db::EdgeWithProperties (db::Edge (10, 20, 30, 40), pid2)); + + top1.shapes (layer1).insert (db::EdgePair (db::Edge (11, 21, 31, 41), db::Edge (111, 121, 131, 141))); + top2.shapes (layer2).insert (db::EdgePair (db::Edge (10, 20, 30, 40), db::Edge (110, 120, 130, 140))); + + top1.shapes (layer1).insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (11, 21, 31, 41), db::Edge (111, 121, 131, 141)), pid1)); + top2.shapes (layer2).insert (db::EdgePairWithProperties (db::EdgePair (db::Edge (10, 20, 30, 40), db::Edge (110, 120, 130, 140)), pid2)); + + top1.shapes (layer1).insert (db::Polygon (db::Box (11, 21, 31, 41))); + top2.shapes (layer2).insert (db::Polygon (db::Box (10, 20, 30, 40))); + + top1.shapes (layer1).insert (db::PolygonWithProperties (db::Polygon (db::Box (11, 21, 31, 41)), pid1)); + top2.shapes (layer2).insert (db::PolygonWithProperties (db::Polygon (db::Box (10, 20, 30, 40)), pid2)); + + db::Point pts1[] = { + db::Point (1, 101), + db::Point (101, 101), + db::Point (101, 201) + }; + + db::Point pts2[] = { + db::Point (0, 100), + db::Point (100, 100), + db::Point (100, 200) + }; + + top1.shapes (layer1).insert (db::Path (&pts1 [0], &pts1 [sizeof (pts1) / sizeof(pts1 [0])], 20)); + top2.shapes (layer2).insert (db::Path (&pts2 [0], &pts2 [sizeof (pts2) / sizeof(pts2 [0])], 20)); + + top1.shapes (layer1).insert (db::PathWithProperties (db::Path (&pts1 [0], &pts1 [sizeof (pts1) / sizeof(pts1 [0])], 20), pid1)); + top2.shapes (layer2).insert (db::PathWithProperties (db::Path (&pts2 [0], &pts2 [sizeof (pts2) / sizeof(pts2 [0])], 20), pid2)); + + top1.shapes (layer1).insert (db::Text ("t1", db::Trans (db::Vector (11, 21)))); + top2.shapes (layer2).insert (db::Text ("t1", db::Trans (db::Vector (10, 20)))); + + top1.shapes (layer1).insert (db::TextWithProperties (db::Text ("t1", db::Trans (db::Vector (11, 21))), pid1)); + top2.shapes (layer2).insert (db::TextWithProperties (db::Text ("t1", db::Trans (db::Vector (10, 20))), pid2)); + + top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)))); + top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)))); + + top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21))), pid1)); + top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20))), pid2)); + + top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), db::Vector (0, 10), db::Vector (10, 0), 2, 3)); + top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), db::Vector (0, 10), db::Vector (10, 0), 2, 3)); + + top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), db::Vector (0, 10), db::Vector (10, 0), 2, 3), pid1)); + top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), db::Vector (0, 10), db::Vector (10, 0), 2, 3), pid2)); + + std::vector ia; + ia.push_back (db::Vector (0, 0)); + ia.push_back (db::Vector (10, 0)); + ia.push_back (db::Vector (0, 10)); + + top1.insert (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), ia.begin (), ia.end ())); + top2.insert (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), ia.begin (), ia.end ())); + + top1.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a1.cell_index ()), db::Trans (db::Vector (11, 21)), ia.begin (), ia.end ()), pid1)); + top2.insert (db::CellInstArrayWithProperties (db::CellInstArray (db::CellInst (a2a.cell_index ()), db::Trans (db::Vector (10, 20)), ia.begin (), ia.end ()), pid2)); + + db::scale_and_snap (l1, top1, 10, 1, 1); + + bool equal = db::compare_layouts (l1, l2, + db::layout_diff::f_verbose + | db::layout_diff::f_boxes_as_polygons + | db::layout_diff::f_paths_as_polygons + , 0, 100 /*max diff lines*/); + EXPECT_EQ (equal, true); +} + +TEST(20_scale_and_snap) +{ + db::Layout l1; + { + std::string fn (tl::testdata ()); + fn += "/algo/scale_and_snap4.oas"; + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (l1); + } + + db::scale_and_snap (l1, l1.cell (*l1.begin_top_down ()), 10, 95, 100); + + CHECKPOINT(); + db::compare_layouts (_this, l1, tl::testdata () + "/algo/layout_utils_au_sns4.oas", db::NormalizationMode (db::WriteOAS + db::WithArrays)); +} + diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 8601dfb65..ffe564cb9 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -39,7 +39,6 @@ SOURCES = \ dbPolygonToolsTests.cc \ dbTechnologyTests.cc \ dbStreamLayerTests.cc \ - dbD25TechnologyComponentTests.cc \ dbVectorTests.cc \ dbVariableWidthPathTests.cc \ dbTransTests.cc \ diff --git a/src/drc/drc/built-in-macros/_drc_engine.rb b/src/drc/drc/built-in-macros/_drc_engine.rb index 3600355ca..9bf0556a0 100644 --- a/src/drc/drc/built-in-macros/_drc_engine.rb +++ b/src/drc/drc/built-in-macros/_drc_engine.rb @@ -1626,6 +1626,54 @@ CODE nil end + # %DRC% + # @name region_touch + # @brief Specifies region selected input in "touch mode" + # @synopsis region_touch(args) + # See \Source#touching for a description of that function. + # + # The following code will select shapes touching a 500x600 micron rectangle (lower left corner at 0,0) + # from the input layout. The shapes will not be clipped: + # + # @code + # region_touch(0.mm, 0.mm, 0.5.mm, 0.6.mm) + # # shapes will now be the ones touching the rectangular region + # l1 = input(1, 0) + # @/code + # + # To remove this condition, call "region_touch" without any arguments. + + def region_touch(*args) + self._context("region_touch") do + @def_source = layout.touching(*args) + end + nil + end + + # %DRC% + # @name region_overlap + # @brief Specifies region selected input in "overlap mode" + # @synopsis region_overlap(args) + # See \Source#overlapping for a description of that function. + # + # The following code will select shapes overlapping a 500x600 micron rectangle (lower left corner at 0,0) + # from the input layout. The shapes will not be clipped: + # + # @code + # region_overlapping(0.mm, 0.mm, 0.5.mm, 0.6.mm) + # # shapes will now be the ones overlapping the rectangular region + # l1 = input(1, 0) + # @/code + # + # To remove this condition, call "region_overlapping" without any arguments. + + def region_overlap(*args) + self._context("region_overlap") do + @def_source = layout.overlapping(*args) + end + nil + end + # %DRC% # @name global_transform # @brief Gets or sets a global transformation diff --git a/src/drc/drc/built-in-macros/drc_interpreters.lym b/src/drc/drc/built-in-macros/drc_interpreters.lym index 4a0108d44..a5c4d13ed 100644 --- a/src/drc/drc/built-in-macros/drc_interpreters.lym +++ b/src/drc/drc/built-in-macros/drc_interpreters.lym @@ -158,6 +158,11 @@ module DRC # Register the new interpreters DRCInterpreter::new(drc_recipe) DRCPlainTextInterpreter::new(drc_recipe) + + # Creates a new macro category + if RBA::Application::instance + RBA::Application::instance.add_macro_category("drc", "DRC", [ "drc" ]) + end end diff --git a/src/gtfui/gtfUiDialog.cc b/src/gtfui/gtfUiDialog.cc index 395dc2eec..504760616 100644 --- a/src/gtfui/gtfUiDialog.cc +++ b/src/gtfui/gtfUiDialog.cc @@ -264,7 +264,7 @@ static std::string log_event_to_text (const gtf::LogEventBase *e) { std::string t = e->name (); - /* @@@ too much: + /* too much: std::vector< std::pair > attrs; e->attributes (attrs); for (std::vector< std::pair >::const_iterator a = attrs.begin (); a != attrs.end (); ++a) { diff --git a/src/lay/lay/MacroPropertiesDialog.ui b/src/lay/lay/MacroPropertiesDialog.ui index d7a2c29e8..1a281dac4 100644 --- a/src/lay/lay/MacroPropertiesDialog.ui +++ b/src/lay/lay/MacroPropertiesDialog.ui @@ -100,7 +100,6 @@ - 75 true @@ -224,25 +223,56 @@ 6 + + + Priority + + + + Prolog - - - - - - - + Epilog + + + + + 0 + 0 + + + + + + + + for autorun: 0 = first, 1 = second ... + + + + + + + + 1 + 0 + + + + + + + diff --git a/src/lay/lay/doc/about/25d_screenshot.png b/src/lay/lay/doc/about/25d_screenshot.png index 1796a0573..32c96174e 100644 Binary files a/src/lay/lay/doc/about/25d_screenshot.png and b/src/lay/lay/doc/about/25d_screenshot.png differ diff --git a/src/lay/lay/doc/about/25d_screenshot2.png b/src/lay/lay/doc/about/25d_screenshot2.png new file mode 100644 index 000000000..5c988166f Binary files /dev/null and b/src/lay/lay/doc/about/25d_screenshot2.png differ diff --git a/src/lay/lay/doc/about/25d_view.xml b/src/lay/lay/doc/about/25d_view.xml index a23667f30..22438889e 100644 --- a/src/lay/lay/doc/about/25d_view.xml +++ b/src/lay/lay/doc/about/25d_view.xml @@ -18,97 +18,187 @@

- To open the view, use "Tools/2.5d View". Currently, the performance is limited, a rough number for a + 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.

+

+ In order to use the tool, you will need a script generating the material stack. + Such a script is a variant of a DRC script (see ). + The DRC language is used to import or generate polygon layers which are then + extruded and placed on a certain z level. +

+ +

+ To create a new script, use "Tools/2.5d View/New 2.5d Script". This will create a new script in the + macro editor. +

+ +

+ A simple script is this one. It takes two layers - 1/0 and 2/0 - and extrudes then in a + stacked fashion, the first with 200nm thickness and the second one with 300nm: +

+ +
+z(input(1, 0), zstart: 0.1.um, height: 200.nm)  # extrudes layer 1/0 to a height of 200nm starting at z=100nm
+z(input(2, 0), height: 300.nm)                  # adds layer 2/0 for the next 300nm
+
+ +

+ To run the script, use the "Run" button from the macro IDE or pick the script + from the script list in the "Tools/2.5d View" menu. If your script is not shown in that + menu, check if it is configured to be bound to a menu item. +

+ +

+ After the script was executed, the 2.5d window is displayed. If you closed that window, you can + re-open it with "Tools/2.5d View/Open Window". The window will show the layout section visible + in the layout view. To refresh the scene - also after changing the script - either run the script + again from the macro IDE or use the green "re-run" button in the upper left corner of the 2.5d view + window. +

+

-

Setup

+

2.5d Script Anatomy

- 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: + As mentioned, a 2.5d script is a variant of a DRC script. You can basically use all features + of DRC, specifically boolean operations. Some practical restrictions exist:

    -
  • 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
  • +
  • You should not use external sources ("source" statement) as the 2.5d view is related to the loaded layout
  • +
  • Report generation or "output" statements are permitted, but do not make much sense in the context + of 2.5d view scripts.

- '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. + 2.5d scripts utilizes the DRC language with these two additional functions: +

+ +
    +
  • z(layer [, options])

    +

    Extrudes the given layer. "layer" is a DRC layer (polygon, edge or even edge pair). "options" declare the z extrusion and display parameters.

    +
  • +
  • zz( [options] ) { block }

    +

    Declares a material group which combines multiple "z" statements under a single display group. + This allows generating 3d material geometries which are more than a single extruded plane. + The display parameters then are specified within "zz" for all "z" calls inside the block.

    +
  • +
+ +

"z" Function (plane extrusion)

+ + +

+ The layer argument of the function is a DRC layer which is rendered as an extruded sheet. + Further arguments control the height, z location and colors. + When used inside the "zz" block, the color options of the "z" calls are ignored and + taken from "zz" instead.

- If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to - 'zstart' and 'zstop'. + Options for this function are:

+
    +
  • zstart: specifies the bottom coordinate of the extruded sheet. If this option is not given, the top coordinate of the previous "z" statement is used.
  • +
  • zstop: specifies the top coordinate of the extruded sheet. Alternatively you can use "height".
  • +
  • height: specifies the extrusion height. Alternatively you can use "zstop".
  • +
  • color: specifies the color to use as a 24 bit hex RGB triplet (use "0xrrggbb" to specify the color similar to the HTML notation "#rrggbb"). + A color specification gives a single color with not differentiation of frame and wall colors.
  • +
  • frame: specifies the frame color to use as a 24 bit hex RGB triplet. If only a frame color is specified, the geometry will be rendered as wire frame only.
  • +
  • fill: specifies the fill (wall) color to use as a 24 bit hex RGB triplet. This allows specifying a different color for wall and frame when used with "frame".
  • +
  • like: specifies to use the same colors than used for some layer in the layout view. + If the layer is an original layer (i.e. taken from "input"), "like" defaults to the + original layer's source. If given, "like" needs to be a string representation of the + layer source (e.g. "7/0" for layer 7, datatype 0).
  • +
  • name: gives the material a name for displaying in the material list.
  • +
+

- Here are some examples: + Examples for the extrusion options:

-
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"
+  
+z(layer, 0.1 .. 0.2)                extrude layer to z = 0.1 to 0.2 um
+z(layer, zstart: 0.1, zstop: 0.2)   same as above
+z(layer, zstart: 0.1, height: 0.1)  same as above, but with height instead of zstop
+z(layer, height: 200.nm)            extrude layer from last z position with a height of 200nm
 
-

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: + Examples for display options:

-
var thick_m1 = true
-if thickm1
-  1: 0.5 1.5
-else
-  1: 0.5 1.2
+  
+z(..., color: 0xff0000)             use bright red for the material color (RGB)
+z(..., frame: 0xff0000)             use bright red for the frame color (combine with "fill" for the fill color)
+z(..., fill: 0x00ff00)              use bright green for the fill color along (combine with "frame" for the frame color)
+z(..., like: "7/0")                 borrow style from layout view's style for layer "7/0"
+z(..., name: "M1")                  assigns a name to show for the material 
+
+ +

"zz" Function (material groups)

+ + +

+ The "zz" function forms a display group which clusters multiple "z" calls. The basic usage is with a block + containing the "z" calls. As DRC scripts are Ruby, the notation for the block is either "do .. end" or + curly brackets immediately after the "zz" call: +

+ +
+zz( display options ... ) do
+  z(layer1, extrusion options ... )
+  z(layer2, extrusion options ... )
+  ...
 end
 
+

+ The "z" calls do not need to have colors or other display options as they are + taken from "zz". +

+ +

+ Material groups allow forming more complex, stacked geometries. Here is an example + forming a simple FinFET geometry using boolean and a sizing operation: +

+ +
+poly = input(2, 0)
+active = input(1, 0)
+
+z(poly, zstart: 0, height: 20.nm, name: "POLY")
+
+zz(name: "ACTIVE", like: "1/0") do
+  
+  poly_sized = poly.sized(10.nm)
+  active_over_poly_sized = poly_sized & active
+  
+  z(active - poly, zstart: 0, height: 10.nm)       # bottom sheet
+  z(active_over_poly_sized - poly, height: 10.nm)  # center sheet
+  z(active_over_poly_sized, height: 10.nm)         # top sheet
+
+end
+
+ +

+ Which renders this result: +

+ +

+ +

+

Navigating the 2.5d View

- navigation - 2.5d navigation + +

The navigation is based on the movement of the camera while the scene is @@ -159,7 +249,7 @@ end made invisible in the 2.5d view.

-

Other controls

+

Other Controls

The left zoom slider changes the overall scale factor. The right slider only changes the z (height) axis zoom factor. @@ -176,5 +266,13 @@ end front view, top view etc.

+

Material Visibility

+ +

+ Using the check boxes from the material view right of the scene view you can disable + materials, so they are no longer rendered. From the material list's context menu, + you can hide or show all materials or just the selected ones. +

+ diff --git a/src/lay/lay/gsiDeclLayApplication.cc b/src/lay/lay/gsiDeclLayApplication.cc index 287b80f92..fbf23517b 100644 --- a/src/lay/lay/gsiDeclLayApplication.cc +++ b/src/lay/lay/gsiDeclLayApplication.cc @@ -87,6 +87,12 @@ static std::string version (C *) return C::version (); } +template +static void add_macro_category (C *c, const std::string &name, const std::string &description, const std::vector &folders) +{ + c->add_macro_category (name, description, folders); +} + template static gsi::Methods application_methods () { @@ -226,6 +232,12 @@ static gsi::Methods application_methods () "@brief Returns the architecture string\n" "This method has been introduced in version 0.25." ) + + method_ext &> ("add_macro_category", &add_macro_category, gsi::arg ("name"), gsi::arg ("description"), gsi::arg ("folders"), + "@brief Creates a new macro category\n" + "Creating a new macro category is only possible during the autorun_early stage. " + "The new macro category must correspond to an interpreter registered at the same stage.\n" + "This method has been introduced in version 0.28." + ) + method ("instance", &C::instance, "@brief Return the singleton instance of the application\n" "\n" diff --git a/src/lay/lay/layApplication.cc b/src/lay/lay/layApplication.cc index f5d4dd505..a66c633a2 100644 --- a/src/lay/lay/layApplication.cc +++ b/src/lay/lay/layApplication.cc @@ -686,6 +686,22 @@ ApplicationBase::init_app () if (mc) { + // create the basic macro categories + + if (ruby_interpreter ().available ()) { + std::vector folders; + folders.push_back ("macros"); + folders.push_back ("ruby"); + mc->add_macro_category ("macros", "Ruby", folders); + } + + if (python_interpreter ().available ()) { + std::vector folders; + folders.push_back ("pymacros"); + folders.push_back ("python"); + mc->add_macro_category ("pymacros", "Python", folders); + } + mc->enable_implicit_macros (! m_no_macros); // Add the global ruby modules as the first ones. @@ -741,13 +757,29 @@ ApplicationBase::init_app () } } + std::set already_executed; + // run all early autorun macros - lym::MacroCollection::root ().autorun_early (); + lym::MacroCollection::root ().autorun_early (&already_executed); + + // autorun_early may have added macro categories, so we need to call finish() again + if (mc) { + + mc->finish (); + + // as this regenerates the macro collection, autorun_early is required again + // note: this does no re-execute macros that have been executed already + lym::MacroCollection::root ().autorun_early (&already_executed); + + } // rescan the folders because early autorun macros might have added // suffixes through the MacroInterpreter interface. lym::MacroCollection::root ().rescan (); + // and yet another autorun_early pass .. + lym::MacroCollection::root ().autorun_early (&already_executed); + // creates the main window or plugin root as required setup (); @@ -785,6 +817,15 @@ ApplicationBase::init_app () } } +void +ApplicationBase::add_macro_category (const std::string &name, const std::string &description, const std::vector &folders) +{ + lay::MacroController *mc = lay::MacroController::instance (); + if (mc) { + mc->add_macro_category (name, description, folders); + } +} + ApplicationBase::~ApplicationBase () { tl::set_ui_exception_handlers (0, 0, 0); diff --git a/src/lay/lay/layApplication.h b/src/lay/lay/layApplication.h index 85eb65267..887fc42c5 100644 --- a/src/lay/lay/layApplication.h +++ b/src/lay/lay/layApplication.h @@ -214,6 +214,13 @@ public: return *mp_python_interpreter; } + /** + * @brief Adds a new macro category + * + * This method is only effective when called during the autorun_early stage + */ + void add_macro_category (const std::string &name, const std::string &description, const std::vector &folders); + /** * @brief Return true, if undo buffering is enabled */ diff --git a/src/lay/lay/layHelpResources.qrc b/src/lay/lay/layHelpResources.qrc index 06524e1f5..a853c8b3d 100644 --- a/src/lay/lay/layHelpResources.qrc +++ b/src/lay/lay/layHelpResources.qrc @@ -49,6 +49,7 @@ doc/about/packages.xml doc/about/25d_view.xml doc/about/25d_screenshot.png + doc/about/25d_screenshot2.png doc/manual/adjust_origin.xml diff --git a/src/lay/lay/layMacroController.cc b/src/lay/lay/layMacroController.cc index 77bd03e20..51b1111ef 100644 --- a/src/lay/lay/layMacroController.cc +++ b/src/lay/lay/layMacroController.cc @@ -49,62 +49,27 @@ MacroController::MacroController () // .. nothing yet .. } -static lay::MacroController::MacroCategory ruby_cat () +void +MacroController::add_macro_category (const std::string &name, const std::string &description, const std::vector &folders) { lay::MacroController::MacroCategory cat; - cat.name = "macros"; - cat.description = tl::to_string (QObject::tr ("Ruby")); - cat.folders.push_back ("macros"); - cat.folders.push_back ("ruby"); - return cat; -} - -static lay::MacroController::MacroCategory python_cat () -{ - lay::MacroController::MacroCategory cat; - cat.name = "pymacros"; - cat.description = tl::to_string (QObject::tr ("Python")); - cat.folders.push_back ("pymacros"); - cat.folders.push_back ("python"); - return cat; -} - -static lay::MacroController::MacroCategory drc_cat () -{ - lay::MacroController::MacroCategory cat; - cat.name = "drc"; - cat.description = tl::to_string (QObject::tr ("DRC")); - cat.folders.push_back ("drc"); - return cat; -} - -static lay::MacroController::MacroCategory lvs_cat () -{ - lay::MacroController::MacroCategory cat; - cat.name = "lvs"; - cat.description = tl::to_string (QObject::tr ("LVS")); - cat.folders.push_back ("lvs"); - return cat; + cat.name = name; + cat.description = description; + cat.folders = folders; + m_macro_categories.push_back (cat); } void MacroController::finish () { + lym::MacroCollection::root ().clear (); + // Scan built-in macros // These macros are always taken, even if there are no macros requested (they are required to // fully form the API). lym::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-macros", "macros", true); lym::MacroCollection::root ().add_folder (tl::to_string (QObject::tr ("Built-In")), ":/built-in-pymacros", "pymacros", true); - // TODO: consider adding "drc" and "lvs" dynamically and allow more dynamic categories - // We can do so if we first load the macros with the initial interpreters, then do autorun (which creates DSL interpreters) and then - // register the remaining categories. - - m_macro_categories.push_back (ruby_cat ()); - m_macro_categories.push_back (python_cat ()); - m_macro_categories.push_back (drc_cat ()); - m_macro_categories.push_back (lvs_cat ()); - // scans the macros from techs and packages (this will allow autorun-early on them) // and updates m_external_paths sync_macro_sources (); diff --git a/src/lay/lay/layMacroController.h b/src/lay/lay/layMacroController.h index 757d92653..cae8e979b 100644 --- a/src/lay/lay/layMacroController.h +++ b/src/lay/lay/layMacroController.h @@ -147,10 +147,16 @@ public: /** * @brief Loads the macros from the predefined paths and establishes the search paths - * This method will also establish the macro categories. + * This method can be called multiple times. */ void finish (); + /** + * @brief Adds a new macro category + * finish() needs to be called after adding a new category. + */ + void add_macro_category (const std::string &name, const std::string &description, const std::vector &folders); + /** * @brief Adds a temporary macro * diff --git a/src/lay/lay/layMacroPropertiesDialog.cc b/src/lay/lay/layMacroPropertiesDialog.cc index 58fcf16f5..2c04a77c8 100644 --- a/src/lay/lay/layMacroPropertiesDialog.cc +++ b/src/lay/lay/layMacroPropertiesDialog.cc @@ -75,6 +75,7 @@ MacroPropertiesDialog::update (const lym::Macro *macro) propertiesFrame->setEnabled (! macro->is_readonly ()); description->setText (tl::to_qstring (macro->description ())); version->setText (tl::to_qstring (macro->version ())); + priority->setText (tl::to_qstring (tl::to_string (macro->priority ()))); prolog->setText (tl::to_qstring (macro->prolog ())); epilog->setText (tl::to_qstring (macro->epilog ())); autorun->setChecked (macro->is_autorun ()); @@ -98,6 +99,10 @@ MacroPropertiesDialog::commit (lym::Macro *macro) macro->set_show_in_menu (showmenu->isChecked ()); macro->set_group_name (tl::to_string (groupName->text ())); macro->set_menu_path (tl::to_string (menuPath->text ())); + + int p = 0; + tl::from_string (tl::to_string (priority->text ()), p); + macro->set_priority (p); } } diff --git a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui deleted file mode 100644 index 19c8bfc39..000000000 --- a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui +++ /dev/null @@ -1,55 +0,0 @@ - - - D25TechnologyComponentEditor - - - - 0 - 0 - 549 - 434 - - - - Settings - - - - - - <html>2.5d Vertical stack information (see <a href="int:/about/25d_view.xml">here</a> for details)</html> - - - - - - - - 0 - 0 - - - - Line - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - QTextEdit::NoWrap - - - false - - - - - - - - - diff --git a/src/laybasic/laybasic/layD25TechnologyComponent.cc b/src/laybasic/laybasic/layD25TechnologyComponent.cc deleted file mode 100644 index af6bbee16..000000000 --- a/src/laybasic/laybasic/layD25TechnologyComponent.cc +++ /dev/null @@ -1,115 +0,0 @@ - -/* - - KLayout Layout Viewer - Copyright (C) 2006-2022 Matthias Koefferlein - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - - -#include "laybasicConfig.h" -#include "dbD25TechnologyComponent.h" -#include "layD25TechnologyComponent.h" -#include "layQtTools.h" - -#include -#include - -namespace lay -{ - -D25TechnologyComponentEditor::D25TechnologyComponentEditor (QWidget *parent) - : TechnologyComponentEditor (parent) -{ - setupUi (this); - - src_te->setFont (monospace_font ()); - - activate_help_links (label); - - QResource res (tl::to_qstring (":/syntax/d25_text.xml")); - QByteArray data ((const char *) res.data (), int (res.size ())); -#if QT_VERSION >= 0x60000 - if (res.compressionAlgorithm () == QResource::ZlibCompression) { -#else - if (res.isCompressed ()) { -#endif - data = qUncompress (data); - } - - QBuffer input (&data); - input.open (QIODevice::ReadOnly); - mp_hl_basic_attributes.reset (new GenericSyntaxHighlighterAttributes ()); - mp_hl_attributes.reset (new GenericSyntaxHighlighterAttributes (mp_hl_basic_attributes.get ())); - lay::GenericSyntaxHighlighter *hl = new GenericSyntaxHighlighter (src_te, input, mp_hl_attributes.get ()); - input.close (); - - hl->setDocument (src_te->document ()); - - connect (src_te, SIGNAL (cursorPositionChanged ()), this, SLOT (cursor_position_changed ())); -} - -void -D25TechnologyComponentEditor::cursor_position_changed () -{ - int line = src_te->textCursor ().block ().firstLineNumber () + 1; - lnum_label->setText (tl::to_qstring (tl::sprintf (tl::to_string (tr ("Line %d")), line))); -} - -void -D25TechnologyComponentEditor::commit () -{ - db::D25TechnologyComponent *data = dynamic_cast (tech_component ()); - if (! data) { - return; - } - - std::string src = tl::to_string (src_te->toPlainText ()); - - // test-compile before setting it - db::D25TechnologyComponent tc; - tc.set_src (src); - tc.compile_from_source (); - - data->set_src (src); -} - -void -D25TechnologyComponentEditor::setup () -{ - db::D25TechnologyComponent *data = dynamic_cast (tech_component ()); - if (! data) { - return; - } - - src_te->setPlainText (tl::to_qstring (data->src ())); -} - -class D25TechnologyComponentEditorProvider - : public lay::TechnologyEditorProvider -{ -public: - virtual lay::TechnologyComponentEditor *create_editor (QWidget *parent) const - { - return new D25TechnologyComponentEditor (parent); - } -}; - -static tl::RegisteredClass editor_decl (new D25TechnologyComponentEditorProvider (), 3100, "d25"); - -} // namespace lay - diff --git a/src/laybasic/laybasic/layD25TechnologyComponent.h b/src/laybasic/laybasic/layD25TechnologyComponent.h deleted file mode 100644 index 5cdf03df8..000000000 --- a/src/laybasic/laybasic/layD25TechnologyComponent.h +++ /dev/null @@ -1,57 +0,0 @@ - -/* - - KLayout Layout Viewer - Copyright (C) 2006-2022 Matthias Koefferlein - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -*/ - - -#ifndef HDR_layD25TechnologyComponent -#define HDR_layD25TechnologyComponent - -#include "ui_D25TechnologyComponentEditor.h" -#include "layTechnology.h" -#include "layGenericSyntaxHighlighter.h" - -#include - -namespace lay { - -class D25TechnologyComponentEditor - : public lay::TechnologyComponentEditor, - public Ui::D25TechnologyComponentEditor -{ -Q_OBJECT - -public: - D25TechnologyComponentEditor (QWidget *parent); - - void commit (); - void setup (); - -private slots: - void cursor_position_changed (); - -private: - std::unique_ptr mp_hl_attributes, mp_hl_basic_attributes; -}; - -} - -#endif - diff --git a/src/laybasic/laybasic/layParsedLayerSource.h b/src/laybasic/laybasic/layParsedLayerSource.h index 7bc862d42..e3bbfa511 100644 --- a/src/laybasic/laybasic/layParsedLayerSource.h +++ b/src/laybasic/laybasic/layParsedLayerSource.h @@ -35,8 +35,8 @@ namespace db { - struct LayerProperties; class Layout; + struct LayerProperties; } namespace lay diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index a9cd72e78..ed2625d9d 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -74,8 +74,7 @@ FORMS = \ NetInfoDialog.ui \ NetExportDialog.ui \ SelectCellViewForm.ui \ - LayoutStatistics.ui \ - D25TechnologyComponentEditor.ui + LayoutStatistics.ui RESOURCES = \ laybasicResources.qrc \ @@ -192,7 +191,6 @@ SOURCES = \ laySelectCellViewForm.cc \ layLayoutStatisticsForm.cc \ gsiDeclLayNetlistBrowserDialog.cc \ - layD25TechnologyComponent.cc \ layLayoutViewFunctions.cc HEADERS = \ @@ -300,7 +298,6 @@ HEADERS = \ layDispatcher.h \ laySelectCellViewForm.h \ layLayoutStatisticsForm.h \ - layD25TechnologyComponent.h \ layLayoutViewFunctions.h INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC diff --git a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym index f9f9863f8..24cd20021 100644 --- a/src/lvs/lvs/built-in-macros/lvs_interpreters.lym +++ b/src/lvs/lvs/built-in-macros/lvs_interpreters.lym @@ -159,6 +159,11 @@ module LVS LVSInterpreter::new(lvs_recipe) LVSPlainTextInterpreter::new(lvs_recipe) + # Creates a new macro category + if RBA::Application::instance + RBA::Application::instance.add_macro_category("lvs", "LVS", [ "lvs" ]) + end + end diff --git a/src/lym/lym/lymMacro.cc b/src/lym/lym/lymMacro.cc index 8067b67df..429a4fbf2 100644 --- a/src/lym/lym/lymMacro.cc +++ b/src/lym/lym/lymMacro.cc @@ -46,6 +46,8 @@ #include #include +#include +#include namespace lym { @@ -53,7 +55,7 @@ namespace lym // ---------------------------------------------------------------------- Macro::Macro () - : m_modified (true), m_readonly (false), m_autorun (false), m_autorun_default (false), m_autorun_early (false), m_show_in_menu (false), m_is_file (false), mp_parent (0), m_interpreter (None), m_format (Macro::NoFormat) + : m_modified (true), m_readonly (false), m_autorun (false), m_autorun_default (false), m_autorun_early (false), m_priority (0), m_show_in_menu (false), m_is_file (false), mp_parent (0), m_interpreter (None), m_format (Macro::NoFormat) { // .. nothing yet .. } @@ -87,6 +89,7 @@ void Macro::assign (const lym::Macro &other) m_autorun = other.m_autorun; m_autorun_default = other.m_autorun_default; m_autorun_early = other.m_autorun_early; + m_priority = other.m_priority; m_show_in_menu = other.m_show_in_menu; m_shortcut = other.m_shortcut; m_format = other.m_format; @@ -111,6 +114,7 @@ bool Macro::operator== (const Macro &other) const m_text == other.m_text && m_autorun == other.m_autorun && m_autorun_early == other.m_autorun_early && + m_priority == other.m_priority && m_show_in_menu == other.m_show_in_menu && m_shortcut == other.m_shortcut && m_interpreter == other.m_interpreter && @@ -182,6 +186,7 @@ static tl::XMLStruct xml_struct ("klayout-macro", tl::make_member (&Macro::doc, &Macro::set_doc, "doc") + tl::make_member (&Macro::is_autorun, &Macro::set_autorun, "autorun") + tl::make_member (&Macro::is_autorun_early, &Macro::set_autorun_early, "autorun-early") + + tl::make_member (&Macro::priority, &Macro::set_priority, "priority") + tl::make_member (&Macro::shortcut, &Macro::set_shortcut, "shortcut") + tl::make_member (&Macro::show_in_menu, &Macro::set_show_in_menu, "show-in-menu") + tl::make_member (&Macro::group_name, &Macro::set_group_name, "group-name") + @@ -550,19 +555,22 @@ struct PropertyField void (lym::Macro::*string_setter) (const std::string &); bool (lym::Macro::*bool_getter) () const; void (lym::Macro::*bool_setter) (bool); + int (lym::Macro::*int_getter) () const; + void (lym::Macro::*int_setter) (int); }; static PropertyField property_fields[] = { - { "description", &lym::Macro::description, &lym::Macro::set_description, 0, 0 }, - { "prolog", &lym::Macro::prolog, &lym::Macro::set_prolog, 0, 0 }, - { "epilog", &lym::Macro::epilog, &lym::Macro::set_epilog, 0, 0 }, - { "version", &lym::Macro::version, &lym::Macro::set_version, 0, 0 }, - { "autorun", 0, 0, &lym::Macro::is_autorun, &lym::Macro::set_autorun }, - { "autorun-early", 0, 0, &lym::Macro::is_autorun_early, &lym::Macro::set_autorun_early}, - { "show-in-menu", 0, 0, &lym::Macro::show_in_menu, &lym::Macro::set_show_in_menu }, - { "group-name", &lym::Macro::group_name, &lym::Macro::set_group_name, 0, 0 }, - { "menu-path", &lym::Macro::menu_path, &lym::Macro::set_menu_path, 0, 0 }, - { "shortcut", &lym::Macro::shortcut, &lym::Macro::set_shortcut, 0, 0 } + { "description", &lym::Macro::description, &lym::Macro::set_description, 0, 0, 0, 0 }, + { "prolog", &lym::Macro::prolog, &lym::Macro::set_prolog, 0, 0, 0, 0 }, + { "epilog", &lym::Macro::epilog, &lym::Macro::set_epilog, 0, 0, 0, 0 }, + { "version", &lym::Macro::version, &lym::Macro::set_version, 0, 0, 0, 0 }, + { "autorun", 0, 0, &lym::Macro::is_autorun, &lym::Macro::set_autorun, 0, 0 }, + { "autorun-early", 0, 0, &lym::Macro::is_autorun_early, &lym::Macro::set_autorun_early, 0, 0 }, + { "show-in-menu", 0, 0, &lym::Macro::show_in_menu, &lym::Macro::set_show_in_menu, 0, 0 }, + { "group-name", &lym::Macro::group_name, &lym::Macro::set_group_name, 0, 0, 0, 0 }, + { "menu-path", &lym::Macro::menu_path, &lym::Macro::set_menu_path, 0, 0, 0, 0 }, + { "shortcut", &lym::Macro::shortcut, &lym::Macro::set_shortcut, 0, 0, 0, 0 }, + { "priority", 0, 0, 0, 0, &lym::Macro::priority, &lym::Macro::set_priority } }; static std::string escape_pta_string (const char *cp) @@ -623,6 +631,11 @@ void Macro::sync_text_with_properties () if (v) { new_lines.push_back (std::string ("# $") + pf->name); } + } else if (pf->int_getter) { + int v = (this->*(pf->int_getter)) (); + if (v) { + new_lines.push_back (std::string ("# $") + pf->name + ": " + tl::to_string (v)); + } } } @@ -670,6 +683,8 @@ void Macro::sync_properties_with_text () (this->*(pf->string_setter)) (std::string ()); } else if (pf->bool_setter) { (this->*(pf->bool_setter)) (false); + } else if (pf->int_setter) { + (this->*(pf->int_setter)) (0); } } @@ -694,6 +709,10 @@ void Macro::sync_properties_with_text () (this->*(pf->string_setter)) (unescape_pta_string (pex.skip ())); } else if (pf->bool_setter) { (this->*(pf->bool_setter)) (true); + } else if (pf->int_setter) { + int v = 0; + tl::from_string (pex.skip (), v); + (this->*(pf->int_setter)) (v); } break; @@ -765,6 +784,15 @@ void Macro::set_autorun (bool f) } } +void Macro::set_priority (int p) +{ + if (p != m_priority) { + m_modified = true; + m_priority = p; + on_changed (); + } +} + void Macro::set_show_in_menu (bool f) { if (f != m_show_in_menu) { @@ -1065,6 +1093,11 @@ MacroCollection::MacroCollection () } MacroCollection::~MacroCollection () +{ + do_clear (); +} + +void MacroCollection::do_clear () { for (iterator m = begin (); m != end (); ++m) { delete m->second; @@ -1513,6 +1546,13 @@ void MacroCollection::scan (const std::string &path) } } +void MacroCollection::clear () +{ + begin_changes (); + do_clear (); + on_changed (); +} + void MacroCollection::erase (lym::Macro *mp) { for (iterator m = m_macros.begin (); m != m_macros.end (); ++m) { @@ -1861,30 +1901,78 @@ bool MacroCollection::has_autorun_early () const return has_autorun_for (*this, true); } -static void autorun_for (lym::MacroCollection &collection, bool early) +static int collect_priority (lym::MacroCollection &collection, bool early, int from_prio) { + int p = -1; + for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) { - autorun_for (*c->second, early); + int pp = collect_priority (*c->second, early, from_prio); + if (pp >= from_prio && (p < 0 || pp < p)) { + p = pp; + } } for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) { if (c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) { - BEGIN_PROTECTED_SILENT - c->second->run (); - c->second->install_doc (); - END_PROTECTED_SILENT + int pp = c->second->priority (); + if (pp >= from_prio && (p < 0 || pp < p)) { + p = pp; + } } } + + return p; +} + +static void autorun_for_prio (lym::MacroCollection &collection, bool early, std::set *executed_already, int prio) +{ + for (lym::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) { + autorun_for_prio (*c->second, early, executed_already, prio); + } + + for (lym::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) { + + if (c->second->priority () == prio && c->second->can_run () && ((early && c->second->is_autorun_early ()) || (!early && c->second->is_autorun () && !c->second->is_autorun_early ()))) { + + if (!executed_already || executed_already->find (c->second->path ()) == executed_already->end ()) { + + BEGIN_PROTECTED_SILENT + c->second->run (); + c->second->install_doc (); + END_PROTECTED_SILENT + + if (executed_already) { + executed_already->insert (c->second->path ()); + } + + } + + } + + } } -void MacroCollection::autorun () +static void autorun_for (lym::MacroCollection &collection, bool early, std::set *executed_already) { - autorun_for (*this, false); + int prio = 0; + while (true) { + int p = collect_priority (collection, early, prio); + if (p < prio) { + break; + } + autorun_for_prio (collection, early, executed_already, p); + prio = p + 1; + } } -void MacroCollection::autorun_early () +void MacroCollection::autorun (std::set *already_executed) { - autorun_for (*this, true); + autorun_for (*this, false, already_executed); +} + +void MacroCollection::autorun_early (std::set *already_executed) +{ + autorun_for (*this, true, already_executed); } void MacroCollection::dump (int l) diff --git a/src/lym/lym/lymMacro.h b/src/lym/lym/lymMacro.h index 396bdbee3..619be68a6 100644 --- a/src/lym/lym/lymMacro.h +++ b/src/lym/lym/lymMacro.h @@ -430,6 +430,20 @@ public: */ void set_autorun_early (bool f); + /** + * @brief Gets the priority of the macro in autorun and autorun-early mode + * 0 is the first priority, -1 means "never execute". + */ + int priority () const + { + return m_priority; + } + + /** + * @brief Sets the priority + */ + void set_priority (int p); + /** * @brief Gets a value indicating whether the macro shall be shown in the menu */ @@ -596,6 +610,7 @@ private: bool m_autorun; bool m_autorun_default; bool m_autorun_early; + int m_priority; bool m_show_in_menu; std::string m_group_name; std::string m_menu_path; @@ -845,6 +860,12 @@ public: */ void add_unspecific (lym::Macro *m); + /** + * @brief Empties the collection + * Note: only the unspecific on_changed event is generated. + */ + void clear (); + /** * @brief Erases the given macro from the list * @@ -995,7 +1016,7 @@ public: /** * @brief Runs all macros marked with auto-run */ - void autorun (); + void autorun (std::set *already_executed = 0); /** * @brief Returns true, if the collection has an early autorun macro @@ -1005,7 +1026,7 @@ public: /** * @brief Runs all macros marked with early auto-run */ - void autorun_early (); + void autorun_early (std::set *already_executed = 0); /** * @brief Redo the scan (will add new files or folders) @@ -1129,6 +1150,8 @@ private: m_readonly = f; } + void do_clear (); + // no copying MacroCollection (const MacroCollection &d); MacroCollection &operator= (const MacroCollection &d); diff --git a/src/plugins/tools/view_25d/lay_plugin/D25View.ui b/src/plugins/tools/view_25d/lay_plugin/D25View.ui index 75301397d..a38817f62 100644 --- a/src/plugins/tools/view_25d/lay_plugin/D25View.ui +++ b/src/plugins/tools/view_25d/lay_plugin/D25View.ui @@ -59,6 +59,42 @@ 0 + + + + false + + + Execute script again + + + ... + + + + :/run.png:/run.png + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 10 + 20 + + + + @@ -343,6 +379,9 @@ + + 2 + @@ -358,7 +397,60 @@ 0 - + + + QFrame::NoFrame + + + QFrame::Plain + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + + 1 + 0 + + + + + + + 0 + 0 + + + + QAbstractItemView::ExtendedSelection + + + 0 + + + true + + + + + + @@ -419,6 +511,21 @@ + + + + + + In order to use the 2.5d view you will need a script which generates the view.<br/> +See here for more information: <a href="int:/about/25d_view.xml">The 2.5d View</a>. + + + Qt::AlignCenter + + + + + @@ -482,6 +589,36 @@ + + + Select All + + + + + Unselect All + + + + + Show All + + + + + Hide All + + + + + Show Selected + + + + + Hide Selected + + @@ -510,5 +647,37 @@ + + select_all_action + triggered() + material_list + selectAll() + + + -1 + -1 + + + 716 + 336 + + + + + unselect_all_action + triggered() + material_list + clearSelection() + + + -1 + -1 + + + 716 + 336 + + + diff --git a/src/plugins/tools/view_25d/lay_plugin/built-in-macros/_d25_engine.rb b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/_d25_engine.rb new file mode 100644 index 000000000..f1114cc0b --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/_d25_engine.rb @@ -0,0 +1,288 @@ +# $autorun-early +# $priority: 1 + +require 'pathname' + +module D25 + + class D25ZInfo + + attr_accessor :layer, :zstart, :zstop, :display + + def initialize(_layer, _zstart, _zstop, _display) + self.layer = _layer + self.zstart = _zstart + self.zstop = _zstop + self.display = _display + end + + end + + class D25Display + + attr_accessor :fill, :frame, :like, :name + + def initialize + self.fill = nil + self.frame = nil + self.like = nil + self.name = nil + end + + def set_fill(arg) + if !arg.is_a?(0xffffff.class) + raise("'fill' must be a color value (an integer)") + end + self.fill = arg + end + + def set_frame(arg) + if !arg.is_a?(0xffffff.class) + raise("'frame' must be a color value (an integer)") + end + self.frame = arg + end + + def set_color(arg) + if !arg.is_a?(0xffffff.class) + raise("'color' must be a color value (an integer)") + end + self.fill = arg + self.frame = nil + end + + def set_like(arg) + li = nil + if arg.is_a?(String) + li = RBA::LayerInfo::from_string(arg) + elsif arg.is_a?(RBA::LayerInfo) + li = arg + else + raise("'like' must be a string or LayerInfo object") + end + self.like = li + end + + end + + # The D25 engine + + class D25Engine < DRC::DRCEngine + + def initialize + + super + + @current_z = 0.0 + @zstack = [] + + # clip to layout view + if ! RBA::LayoutView::current + raise "No layout loaded for running 2.5d view on" + end + + self.region_overlap(RBA::LayoutView::current.box) + + end + + def z(*args) + + self._context("z") do + + layer = nil + zstart = nil + zstop = nil + height = nil + display = D25Display::new + + args.each do |a| + + if a.is_a?(Range) + + zstart = a.min + zstop = a.max + + elsif a.is_a?(DRC::DRCLayer) + + if layer + raise("Duplicate layer argument") + end + layer = a + if ! layer.data.is_a?(RBA::Region) && ! layer.data.is_a?(RBA::Edges) && ! layer.data.is_a?(RBA::EdgePairs) + raise("Expected a polygon, edge or edge pair layer") + end + + elsif a.is_a?(1.class) || a.is_a?(1.0.class) + + if height + raise("Duplicate height specification") + end + height = a + + elsif a.is_a?(Hash) + + if a[:height] + if height + raise("Duplicate height specification") + end + height = a[:height] + end + + if a[:zstart] + if zstart + raise("Duplicate zstart specification") + end + zstart = a[:zstart] + end + + if a[:zstop] + if zstop + raise("Duplicate zstop specification") + end + zstop = a[:zstop] + end + + a[:color] && display.set_color(a[:color]) + a[:frame] && display.set_frame(a[:frame]) + a[:fill] && display.set_fill(a[:fill]) + a[:like] && display.set_like(a[:like]) + + if a[:name] + display.name = a[:name].to_s + end + + invalid_keys = a.keys.select { |k| ![ :height, :zstart, :zstop, :color, :frame, :fill, :like, :name ].member?(k) } + if invalid_keys.size > 0 + raise("Keyword argument(s) not understood: #{invalid_keys.collect(&:to_s).join(',')}") + end + + else + raise("Argument not understood: #{a.inspect}") + end + + end + + if ! zstart + zstart = @current_z + end + if ! zstop && ! height + raise("Either height or zstop must be specified") + elsif zstop && height + raise("Either height or zstop must be specified, not both") + end + if height + zstop = zstart + height + end + @current_z = zstop + + if ! layer + raise("No layer specified") + end + + info = D25ZInfo::new(layer, zstart, zstop, @display || display) + @zstack << info + + return info + + end + + end + + def zz(*args, &block) + + begin + + display = D25Display::new + @display = display + + args.each do |a| + + if a.is_a?(D25ZInfo) + + @zstack.each do |z| + if z == a + z.display = display + end + end + + elsif a.is_a?(Hash) + + a[:color] && display.set_color(a[:color]) + a[:frame] && display.set_frame(a[:frame]) + a[:fill] && display.set_fill(a[:fill]) + a[:like] && display.set_like(a[:like]) + + if a[:name] + display.name = a[:name].to_s + end + + invalid_keys = a.keys.select { |k| ![ :fill, :frame, :color, :hollow, :like, :name ].member?(k) } + if invalid_keys.size > 0 + raise("Keyword argument(s) not understood: #{invalid_keys.collect(&:to_s).join(',')}") + end + + else + raise("Argument not understood: #{a.inspect}") + end + + end + + block && yield + + ensure + @display = nil + end + + end + + def _check + + if @zstack.empty? + raise("No z calls made in 2.5d script") + end + + end + + def _finish(final = true) + + super(final) + + if final + + view = RBA::LayoutView::current.open_d25_view + + begin + + view.begin(self._generator) + + displays = {} + + @zstack.each do |z| + (displays[z.display.object_id] ||= []) << z + end + + displays.each do |k,zz| + display = zz[0].display + view.open_display(display.frame, display.fill, display.like, display.name) + zz.each do |z| + view.entry(z.layer.data, self.dbu, z.zstart, z.zstop) + end + view.close_display + end + + view.finish + + rescue => ex + view.clear + view.close + raise ex + end + + end + + end + + end + +end + diff --git a/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_install.lym b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_install.lym new file mode 100644 index 000000000..ead33cc20 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_install.lym @@ -0,0 +1,63 @@ + + + + + + + + + true + false + + false + + + ruby + + +module D25 + + # Installs the home menu entries (needs to be done on autorun, not autorun-early) + + if RBA::Application::instance && RBA::Application::instance.main_window + + cat = "d25" + name = "2.5d" + + mw = RBA::Application::instance.main_window + mw.menu.insert_menu("tools_menu.verification_group+", "d25", "2.5d View") + + @new_action = RBA::Action::new + @new_action.title = "New #{name} Script" + @new_action.on_triggered do + mw.show_macro_editor(cat, true) + end + + mw.menu.insert_item("tools_menu.#{cat}.end", "new_script", @new_action) + + @edit_action = RBA::Action::new + @edit_action.title = "Edit #{name} Script" + @edit_action.on_triggered do + mw.show_macro_editor(cat, false) + end + + mw.menu.insert_item("tools_menu.#{cat}.end", "edit_script", @edit_action) + + @open_action = RBA::Action::new + @open_action.title = "Open Window" + @open_action.on_triggered do + if ! RBA::LayoutView::current + RBA::MessageBox::critical("Error", "No layout loaded for running 2.5d view on", RBA::MessageBox::Ok) + else + RBA::LayoutView::current.open_d25_view + end + end + + mw.menu.insert_item("tools_menu.#{cat}.end", "open_window", @open_action) + + end + +end + + + diff --git a/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym new file mode 100644 index 000000000..86d7d954d --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/built-in-macros/d25_interpreters.lym @@ -0,0 +1,171 @@ + + + + + + + + + false + true + + false + + + ruby + + +module D25 + + class D25Executable < RBA::Executable + + def initialize(macro, generator) + + @d25 = D25Engine::new + @d25._generator = generator + + @macro = macro + + end + + def execute + + @d25._start("D25: " + @macro.path) + + # Set a debugger scope so that our errors end up with the debugger set to the D25's line + RBA::MacroExecutionContext::set_debugger_scope(@macro.path) + + begin + + # No verbosity set in d25 engine - we cannot use the engine's logger + RBA::Logger::verbosity >= 10 && RBA::Logger::info("Running #{@macro.path}") + @d25.instance_eval(@macro.text, @macro.path) + + rescue => ex + + @d25.error("In #{@macro.path}: #{ex.to_s}") + RBA::MacroExecutionContext::ignore_next_exception + raise ex + + end + + @d25._check + + nil + + end + + def cleanup + + # Remove the debugger scope + RBA::MacroExecutionContext::remove_debugger_scope + + # cleans up and creates layout and report views + @d25._finish + + end + + end + + # A DSL implementation for a D25 language (XML format) + class D25Interpreter < RBA::MacroInterpreter + + # Constructor + def initialize(recipe) + + @recipe = recipe + + # Make the DSL use ruby syntax highlighting + self.syntax_scheme = "ruby" + self.suffix = "lyd25" + self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger + self.storage_scheme = RBA::MacroInterpreter::MacroFormat + self.description = "D25" + + # Registers the new interpreter + register("d25-dsl-xml") + + # create a template for the macro editor: + create_template(":/d25-templates/d25.lym") + + # if available, create a menu branch + if RBA::Application::instance && RBA::Application::instance.main_window + mw = RBA::Application::instance.main_window + mw.menu.insert_menu("tools_menu.verification_group+", "d25", "2.5d View") + end + + end + + # Implements the execute method + def executable(macro) + D25Executable::new(macro, @recipe.generator("script" => macro.path)) + end + + end + + # A DSL implementation for a D25 language (Plain text format) + class D25PlainTextInterpreter < RBA::MacroInterpreter + + # Constructor + def initialize(recipe) + + @recipe = recipe + + # Make the DSL use ruby syntax highlighting + self.syntax_scheme = "ruby" + self.suffix = "d25" + self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger + self.storage_scheme = RBA::MacroInterpreter::PlainTextWithHashAnnotationsFormat + self.description = "D25 (Text)" + + # Registers the new interpreter + register("d25-dsl") + + end + + # Implements the execute method + def executable(macro) + D25Executable::new(macro, @recipe.generator("script" => macro.path)) + end + + end + + # A recipe implementation allowing the D25 run to be redone + class D25Recipe < RBA::Recipe + + def initialize + super("d25", "D25 recipe") + end + + def executable(params) + + script = params["script"] + if ! script + return + end + + macro = RBA::Macro::macro_by_path(script) + macro || raise("Can't find D25 script #{script} - unable to re-run") + + D25Executable::new(macro, self.generator("script" => script)) + + end + + end + + # Register the recipe + d25_recipe = D25Recipe::new + + # Register the new interpreters + D25Interpreter::new(d25_recipe) + D25PlainTextInterpreter::new(d25_recipe) + + # Creates a new macro category + if RBA::Application::instance + RBA::Application::instance.add_macro_category("d25", "2.5d View", [ "d25" ]) + end + +end + + + diff --git a/src/plugins/tools/view_25d/lay_plugin/gsiDeclLayD25View.cc b/src/plugins/tools/view_25d/lay_plugin/gsiDeclLayD25View.cc new file mode 100644 index 000000000..ea7bc880e --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/gsiDeclLayD25View.cc @@ -0,0 +1,96 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2022 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "gsiDecl.h" +#include "gsiDeclBasic.h" + +#include "layD25View.h" +#include "layLayoutView.h" + +#include "dbLayerProperties.h" +#include "dbRegion.h" + +#include + +#if defined(HAVE_QTBINDINGS) + +# include "gsiQtGuiExternals.h" +# include "gsiQtWidgetsExternals.h" + +FORCE_LINK_GSI_QTGUI +FORCE_LINK_GSI_QTWIDGETS // for Qt5 + +#else +# define QT_EXTERNAL_BASE(x) +#endif + +namespace gsi +{ + +static lay::D25View *open_d25_view (lay::LayoutView *view) +{ + return lay::D25View::open (view); +} + +ClassExt decl_LayoutViewExt ( + gsi::method_ext ("open_d25_view", &open_d25_view, + "@brief Opens the 2.5d view window and returns a reference to the D25View object.\n" + "This method has been introduced in version 0.28.\n" + ) +); + +Class decl_D25View (QT_EXTERNAL_BASE (QDialog) "lay", "D25View", + gsi::method ("clear", &lay::D25View::clear, + "@brief Clears all display entries in the view" + ) + + gsi::method ("begin", &lay::D25View::begin, gsi::arg ("generator"), + "@brief Initiates delivery of display groups" + ) + + gsi::method ("open_display", &lay::D25View::open_display, gsi::arg ("frame_color"), gsi::arg ("fill_color"), gsi::arg ("like"), gsi::arg ("name"), + "@brief Creates a new display group" + ) + + gsi::method ("entry", &lay::D25View::entry, gsi::arg ("data"), gsi::arg ("dbu"), gsi::arg ("zstart"), gsi::arg ("zstop"), + "@brief Creates a new display entry in the group opened with \\open_display" + ) + + gsi::method ("entry", &lay::D25View::entry_edge, gsi::arg ("data"), gsi::arg ("dbu"), gsi::arg ("zstart"), gsi::arg ("zstop"), + "@brief Creates a new display entry in the group opened with \\open_display" + ) + + gsi::method ("entry", &lay::D25View::entry_edge_pair, gsi::arg ("data"), gsi::arg ("dbu"), gsi::arg ("zstart"), gsi::arg ("zstop"), + "@brief Creates a new display entry in the group opened with \\open_display" + ) + + gsi::method ("close_display", &lay::D25View::close_display, + "@brief Finishes the display group" + ) + + gsi::method ("finish", &lay::D25View::finish, + "@brief Finishes the view - call this after the display groups have been created" + ) + + gsi::method ("close", &lay::D25View::close, + "@brief Closes the view" + ), + "@brief The 2.5d View Dialog\n" + "\n" + "This class is used internally to implement the 2.5d feature.\n" + "\n" + "This class has been introduced in version 0.28." +); + +} diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index e3a12080d..c6830127c 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -52,10 +52,9 @@ public: return 0; } - virtual void get_menu_entries (std::vector &menu_entries) const + 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 - experimental")))); + // .. nothing yet .. } virtual bool configure (const std::string & /*name*/, const std::string & /*value*/) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Resources.qrc b/src/plugins/tools/view_25d/lay_plugin/layD25Resources.qrc new file mode 100644 index 000000000..be37f46fe --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Resources.qrc @@ -0,0 +1,10 @@ + + + built-in-macros/_d25_engine.rb + built-in-macros/d25_interpreters.lym + built-in-macros/d25_install.lym + + + templates/d25.lym + + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index af10a8621..019dedecd 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -20,6 +20,8 @@ */ +#include "tlExceptions.h" +#include "tlRecipe.h" #include "layD25View.h" #include "layLayoutView.h" @@ -29,13 +31,17 @@ #include +#include + namespace lay { const double initial_elevation = 15.0; D25View::D25View (lay::Dispatcher *root, lay::LayoutView *view) - : lay::Browser (root, view, "d25_view") + : lay::Browser (root, view, "d25_view"), + dm_rerun_macro (this, &D25View::rerun_macro), + dm_fit (this, &D25View::fit) { mp_ui = new Ui::D25View (); mp_ui->setupUi (this); @@ -43,26 +49,52 @@ D25View::D25View (lay::Dispatcher *root, lay::LayoutView *view) mp_ui->d25_view->setFocusPolicy (Qt::StrongFocus); mp_ui->d25_view->setFocus (); - connect (mp_ui->fit_back, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ())); - connect (mp_ui->fit_front, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ())); - connect (mp_ui->fit_left, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ())); - connect (mp_ui->fit_right, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ())); - connect (mp_ui->fit_top, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ())); - connect (mp_ui->fit_bottom, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ())); - connect (mp_ui->zoom_slider, SIGNAL (valueChanged (int)), this, SLOT (scale_slider_changed (int))); - connect (mp_ui->vzoom_slider, SIGNAL (valueChanged (int)), this, SLOT (vscale_slider_changed (int))); - connect (mp_ui->zoom_factor, SIGNAL (editingFinished ()), this, SLOT (scale_value_edited ())); - connect (mp_ui->vzoom_factor, SIGNAL (editingFinished ()), this, SLOT (vscale_value_edited ())); - connect (mp_ui->d25_view, SIGNAL (scale_factor_changed (double)), this, SLOT (scale_factor_changed (double))); - connect (mp_ui->d25_view, SIGNAL (vscale_factor_changed (double)), this, SLOT (vscale_factor_changed (double))); - connect (mp_ui->d25_view, SIGNAL (init_failed ()), this, SLOT (init_failed ())); + connect (mp_ui->fit_back, SIGNAL (clicked()), this, SLOT (fit_button_clicked())); + connect (mp_ui->fit_front, SIGNAL (clicked()), this, SLOT (fit_button_clicked())); + connect (mp_ui->fit_left, SIGNAL (clicked()), this, SLOT (fit_button_clicked())); + connect (mp_ui->fit_right, SIGNAL (clicked()), this, SLOT (fit_button_clicked())); + connect (mp_ui->fit_top, SIGNAL (clicked()), this, SLOT (fit_button_clicked())); + connect (mp_ui->fit_bottom, SIGNAL (clicked()), this, SLOT (fit_button_clicked())); + connect (mp_ui->zoom_slider, SIGNAL (valueChanged(int)), this, SLOT (scale_slider_changed(int))); + connect (mp_ui->vzoom_slider, SIGNAL (valueChanged(int)), this, SLOT (vscale_slider_changed(int))); + connect (mp_ui->zoom_factor, SIGNAL (editingFinished()), this, SLOT (scale_value_edited())); + connect (mp_ui->vzoom_factor, SIGNAL (editingFinished()), this, SLOT (vscale_value_edited())); + connect (mp_ui->d25_view, SIGNAL (scale_factor_changed(double)), this, SLOT (scale_factor_changed(double))); + connect (mp_ui->d25_view, SIGNAL (vscale_factor_changed(double)), this, SLOT (vscale_factor_changed(double))); + connect (mp_ui->d25_view, SIGNAL (init_failed()), this, SLOT (init_failed())); + connect (mp_ui->rerun_button, SIGNAL (clicked()), this, SLOT (rerun_button_pressed())); + connect (mp_ui->hide_all_action, SIGNAL (triggered()), this, SLOT (hide_all_triggered())); + connect (mp_ui->hide_selected_action, SIGNAL (triggered()), this, SLOT (hide_selected_triggered())); + connect (mp_ui->show_all_action, SIGNAL (triggered()), this, SLOT (show_all_triggered())); + connect (mp_ui->show_selected_action, SIGNAL (triggered()), this, SLOT (show_selected_triggered())); - mp_ui->gl_stack->setCurrentIndex (0); + mp_ui->gl_stack->setCurrentIndex (2); + mp_ui->rerun_button->setEnabled (false); lay::activate_help_links (mp_ui->doc_label); + lay::activate_help_links (mp_ui->empty_label); view->cellviews_changed_event.add (this, &D25View::cellviews_changed); view->layer_list_changed_event.add (this, &D25View::layer_properties_changed); + + QPalette palette = mp_ui->material_list->palette (); + palette.setColor (QPalette::Base, Qt::black); + palette.setColor (QPalette::Text, Qt::white); + mp_ui->material_list->setPalette (palette); + + QFont font = mp_ui->material_list->font (); + font.setWeight (QFont::Bold); + mp_ui->material_list->setFont (font); + + mp_ui->material_list->addAction (mp_ui->select_all_action); + mp_ui->material_list->addAction (mp_ui->unselect_all_action); + mp_ui->material_list->addAction (mp_ui->show_all_action); + mp_ui->material_list->addAction (mp_ui->show_selected_action); + mp_ui->material_list->addAction (mp_ui->hide_all_action); + mp_ui->material_list->addAction (mp_ui->hide_selected_action); + mp_ui->material_list->setContextMenuPolicy (Qt::ActionsContextMenu); + + connect (mp_ui->material_list, SIGNAL (itemChanged (QListWidgetItem *)), this, SLOT (material_item_changed (QListWidgetItem *))); } D25View::~D25View () @@ -84,7 +116,7 @@ D25View::cellviews_changed () void D25View::layer_properties_changed (int) { - mp_ui->d25_view->refresh_view (); + // .. nothing yet .. } void @@ -113,6 +145,164 @@ D25View::menu_activated (const std::string &symbol) } } +D25View * +D25View::open (lay::LayoutView *view) +{ + D25View *d25_view = view->get_plugin (); + if (d25_view) { + + d25_view->show (); + d25_view->activateWindow (); + d25_view->raise (); + + try { + d25_view->activate (); + } catch (...) { + d25_view->deactivate (); + throw; + } + + } + + return d25_view; +} + +void +D25View::close () +{ + hide (); +} + +void +D25View::clear () +{ + if (! mp_ui->d25_view->has_error ()) { + mp_ui->gl_stack->setCurrentIndex (2); + mp_ui->d25_view->clear (); + } + + mp_ui->rerun_button->setEnabled (false); + m_generator.clear (); +} + +void +D25View::begin (const std::string &generator) +{ + clear (); + + if (! mp_ui->d25_view->has_error ()) { + m_generator = generator; + } +} + +void +D25View::open_display (const color_t *frame_color, const color_t *fill_color, const db::LayerProperties *like, const std::string *name) +{ + if (! mp_ui->d25_view->has_error ()) { + mp_ui->d25_view->open_display (frame_color, fill_color, like, name); + } +} + +void +D25View::close_display () +{ + if (! mp_ui->d25_view->has_error ()) { + mp_ui->d25_view->close_display (); + } +} + +void +D25View::entry (const db::Region &data, double dbu, double zstart, double zstop) +{ + if (! mp_ui->d25_view->has_error ()) { + mp_ui->d25_view->entry (data, dbu, zstart, zstop); + } +} + +void +D25View::entry_edge (const db::Edges &data, double dbu, double zstart, double zstop) +{ + if (! mp_ui->d25_view->has_error ()) { + mp_ui->d25_view->entry (data, dbu, zstart, zstop); + } +} + +void +D25View::entry_edge_pair (const db::EdgePairs &data, double dbu, double zstart, double zstop) +{ + if (! mp_ui->d25_view->has_error ()) { + mp_ui->d25_view->entry (data, dbu, zstart, zstop); + } +} + +static void layer_info_to_item (const lay::D25ViewWidget::LayerInfo &info, QListWidgetItem *item, size_t index, QSize icon_size) +{ + if (info.has_name) { + item->setText (tl::to_qstring (info.name)); + } else { + item->setText (tl::to_qstring ("#" + tl::to_string (index + 1))); + } + + QImage img (icon_size, QImage::Format_ARGB32); + img.fill (QColor (floor (info.fill_color [0] * 255 + 0.5), floor (info.fill_color [1] * 255 + 0.5), floor (info.fill_color [2] * 255 + 0.5), floor (info.fill_color [3] * 255 + 0.5))); + + QColor fc (floor (info.frame_color [0] * 255 + 0.5), floor (info.frame_color [1] * 255 + 0.5), floor (info.frame_color [2] * 255 + 0.5), floor (info.frame_color [3] * 255 + 0.5)); + if (fc.alpha () > 0) { + QRgb fc_rgb = fc.rgba (); + for (int x = 0; x < icon_size.width (); ++x) { + img.setPixel (x, 0, fc_rgb); + img.setPixel (x, icon_size.height () - 1, fc_rgb); + } + for (int y = 0; y < icon_size.height (); ++y) { + img.setPixel (0, y, fc_rgb); + img.setPixel (icon_size.width () - 1, y, fc_rgb); + } + } + + QIcon icon; + icon.addPixmap (QPixmap::fromImage (img)); + item->setIcon (icon); +} + +void +D25View::finish () +{ + if (! mp_ui->d25_view->has_error ()) { + + mp_ui->d25_view->finish (); + + QFontMetrics fm (mp_ui->material_list->font ()); + QSize icon_size = fm.size (Qt::TextSingleLine, "WW"); + icon_size.setHeight (icon_size.height () - 2); + mp_ui->material_list->setIconSize (icon_size); + + mp_ui->material_list->clear (); + const std::vector &layers = mp_ui->d25_view->layers (); + for (auto l = layers.begin (); l != layers.end (); ++l) { + QListWidgetItem *item = new QListWidgetItem (mp_ui->material_list); + item->setFlags (item->flags () | Qt::ItemIsUserCheckable); + item->setCheckState (Qt::Checked); + layer_info_to_item (*l, item, l - layers.begin (), icon_size); + } + + mp_ui->d25_view->reset (); + mp_ui->d25_view->set_cam_azimuth (0.0); + mp_ui->d25_view->set_cam_elevation (-initial_elevation); + // NOTE: needs to be delayed to allow the geometry to be updated before (initial call) + dm_fit (); + + mp_ui->rerun_button->setEnabled (true); + mp_ui->gl_stack->setCurrentIndex (0); + + } +} + +void +D25View::fit () +{ + mp_ui->d25_view->fit (); +} + static QString scale_factor_to_string (double f) { return QString (QString::fromUtf8 ("%1")).arg (f, 0, 'g', 3); @@ -123,6 +313,7 @@ D25View::init_failed () { mp_ui->error_text->setPlainText (tl::to_qstring (mp_ui->d25_view->error ())); mp_ui->gl_stack->setCurrentIndex (1); + mp_ui->rerun_button->setEnabled (false); } void @@ -189,6 +380,15 @@ D25View::vscale_factor_changed (double f) mp_ui->vzoom_slider->blockSignals (false); } +void +D25View::material_item_changed (QListWidgetItem *item) +{ + int index = mp_ui->material_list->row (item); + if (index >= 0) { + mp_ui->d25_view->set_material_visible (size_t (index), item->checkState () == Qt::Checked); + } +} + void D25View::deactivated () { @@ -198,18 +398,33 @@ D25View::deactivated () void D25View::activated () { - bool any = mp_ui->d25_view->attach_view (view ()); - if (! any) { - mp_ui->d25_view->attach_view (0); - throw tl::Exception (tl::to_string (tr ("No z data configured for the layers in this view.\nUse \"Tools/Manage Technologies\" to set up a z stack or check if it applies to the layers here."))); - } - + mp_ui->d25_view->attach_view (view ()); mp_ui->d25_view->reset (); mp_ui->d25_view->set_cam_azimuth (0.0); mp_ui->d25_view->set_cam_elevation (-initial_elevation); mp_ui->d25_view->fit (); } +void +D25View::rerun_button_pressed () +{ + // NOTE: we use deferred execution, because otherwise the button won't get repainted properly + dm_rerun_macro (); +} + +void +D25View::rerun_macro () +{ +BEGIN_PROTECTED + + if (! m_generator.empty ()) { + std::map add_pars; + tl::Recipe::make (m_generator, add_pars); + } + +END_PROTECTED +} + void D25View::fit_button_clicked () { @@ -242,6 +457,42 @@ D25View::fit_button_clicked () mp_ui->d25_view->fit (); } +void +D25View::hide_all_triggered () +{ + for (int i = 0; i < mp_ui->material_list->count (); ++i) { + mp_ui->material_list->item (i)->setCheckState (Qt::Unchecked); + } +} + +void +D25View::hide_selected_triggered () +{ + for (int i = 0; i < mp_ui->material_list->count (); ++i) { + if (mp_ui->material_list->item (i)->isSelected ()) { + mp_ui->material_list->item (i)->setCheckState (Qt::Unchecked); + } + } +} + +void +D25View::show_all_triggered () +{ + for (int i = 0; i < mp_ui->material_list->count (); ++i) { + mp_ui->material_list->item (i)->setCheckState (Qt::Checked); + } +} + +void +D25View::show_selected_triggered () +{ + for (int i = 0; i < mp_ui->material_list->count (); ++i) { + if (mp_ui->material_list->item (i)->isSelected ()) { + mp_ui->material_list->item (i)->setCheckState (Qt::Checked); + } + } +} + void D25View::accept () { diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.h b/src/plugins/tools/view_25d/lay_plugin/layD25View.h index a4e420576..724c14e25 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.h @@ -24,9 +24,11 @@ #define HDR_layD25View #include +#include #include "tlObject.h" #include "layBrowser.h" +#include "layViewOp.h" namespace Ui { @@ -38,6 +40,14 @@ namespace lay class LayoutView; } +namespace db +{ + class Region; + class Edges; + class EdgePairs; + struct LayerProperties; +} + namespace lay { @@ -54,6 +64,17 @@ public: virtual void deactivated (); virtual void activated (); + static D25View *open (lay::LayoutView *view); + void close (); + void clear (); + void begin (const std::string &generator); + void open_display (const color_t *frame_color, const color_t *fill_color, const db::LayerProperties *like, const std::string *name); + void close_display (); + void entry (const db::Region &data, double dbu, double zstart, double zstop); + void entry_edge (const db::Edges &data, double dbu, double zstart, double zstop); + void entry_edge_pair (const db::EdgePairs &data, double dbu, double zstart, double zstop); + void finish (); + protected: void accept (); void reject (); @@ -67,12 +88,23 @@ private slots: void vscale_slider_changed (int value); void vscale_value_edited (); void init_failed (); + void rerun_button_pressed (); + void material_item_changed (QListWidgetItem *); + void hide_all_triggered (); + void hide_selected_triggered (); + void show_all_triggered (); + void show_selected_triggered (); private: Ui::D25View *mp_ui; + tl::DeferredMethod dm_rerun_macro; + tl::DeferredMethod dm_fit; + std::string m_generator; void cellviews_changed (); void layer_properties_changed (int); + void rerun_macro (); + void fit (); }; } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 57812aeb6..94e7f2705 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -26,11 +26,16 @@ #include "layLayoutView.h" #include "dbRecursiveShapeIterator.h" -#include "dbD25TechnologyComponent.h" #include "dbEdgeProcessor.h" #include "dbPolygonGenerators.h" #include "dbPolygonTools.h" #include "dbClip.h" +#include "dbRegion.h" +#include "dbEdges.h" +#include "dbEdgePairs.h" +#include "dbOriginalLayerRegion.h" +#include "dbOriginalLayerEdges.h" +#include "dbOriginalLayerEdgePairs.h" #include "tlException.h" #include "tlProgress.h" @@ -200,7 +205,10 @@ D25ViewWidget::D25ViewWidget (QWidget *parent) setFormat (format); m_zmin = m_zmax = 0.0; + m_zset = false; + m_display_open = false; mp_view = 0; + m_has_error = false; reset_viewport (); } @@ -477,6 +485,15 @@ D25ViewWidget::refresh () update (); } +void +D25ViewWidget::set_material_visible (size_t index, bool visible) +{ + if (index < m_layers.size () && m_layers [index].visible != visible) { + m_layers [index].visible = visible; + update (); + } +} + void D25ViewWidget::showEvent (QShowEvent *) { @@ -496,86 +513,22 @@ D25ViewWidget::aspect_ratio () const return double (width ()) / double (height ()); } -bool -D25ViewWidget::attach_view (LayoutView *view) +void +D25ViewWidget::clear () { - mp_view = view; + m_layers.clear (); + m_vertex_chunks.clear (); + m_line_chunks.clear (); - bool any = prepare_view (); - reset (); - - return any; -} - -namespace { - - class ZDataCache - { - public: - ZDataCache () { } - - std::vector operator() (lay::LayoutView *view, int cv_index, int layer_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); - if (l != c->second.end ()) { - return l->second; - } else { - return std::vector (); - } - } - - std::map > &lcache = m_cache [cv_index]; - - const db::D25TechnologyComponent *comp = 0; - - const lay::CellView &cv = view->cellview (cv_index); - if (cv.is_valid () && cv->technology ()) { - const db::Technology *tech = cv->technology (); - comp = dynamic_cast (tech->component_by_name ("d25")); - } - - if (comp) { - - std::multimap 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)) { - db::LayerProperties lp = ly.get_properties (l); - std::multimap::const_iterator z = zi_by_lp.find (lp); - if ((z == zi_by_lp.end () || ! z->first.log_equal (lp)) && ! lp.name.empty ()) { - // If possible, try by name only - lp = db::LayerProperties (lp.name); - z = zi_by_lp.find (lp); - } - while (z != zi_by_lp.end () && z->first.log_equal (lp)) { - lcache[l].push_back (z->second); - ++z; - } - } - } - - } - - std::map >::const_iterator l = lcache.find (layer_index); - if (l != lcache.end ()) { - return l->second; - } else { - return std::vector (); - } - } - - private: - std::map > > m_cache; - }; + m_zset = false; + m_zmin = m_zmax = 0.0; + m_display_open = false; + if (! mp_view) { + m_bbox = db::DBox (-1.0, -1.0, 1.0, 1.0); + } else { + m_bbox = mp_view->viewport ().box (); + } } static void color_to_gl (color_t color, GLfloat (&gl_color) [4]) @@ -586,130 +539,181 @@ static void color_to_gl (color_t color, GLfloat (&gl_color) [4]) gl_color[3] = 1.0f; } -void -D25ViewWidget::lp_to_info (const lay::LayerPropertiesNode &lp, LayerInfo &info) +static void color_to_gl (const color_t *color, GLfloat (&gl_color) [4]) { - color_to_gl (lp.fill_color (true), info.color); + if (! color) { + for (unsigned int i = 0; i < 4; ++i) { + gl_color [i] = 0.0; + } + } else { + color_to_gl (*color, gl_color); + } +} + +static void lp_to_info (const lay::LayerPropertiesNode &lp, D25ViewWidget::LayerInfo &info) +{ + color_to_gl (lp.fill_color (true), info.fill_color); if (lp.dither_pattern (true) == 1 /*hollow*/) { - info.color [3] = 0.0f; + info.fill_color [3] = 0.0f; } color_to_gl (lp.frame_color (true), info.frame_color); - if (lp.frame_color (true) == lp.fill_color (true) && info.color [3] > 0.5) { + if (lp.frame_color (true) == lp.fill_color (true) && info.fill_color [3] > 0.5) { // optimize: don't draw wire frame unless required info.frame_color [3] = 0.0f; } - info.visible = lp.visible (true); -} - -bool -D25ViewWidget::prepare_view () -{ - m_layers.clear (); - m_layer_to_info.clear (); - m_vertex_chunks.clear (); - m_line_chunks.clear (); - - bool zset = false; - m_zmin = m_zmax = 0.0; - - if (! mp_view) { - m_bbox = db::DBox (-1.0, -1.0, 1.0, 1.0); - return false; - } - - m_bbox = mp_view->viewport ().box (); - - ZDataCache zdata; - - // collect and confine to cell bbox - db::DBox cell_bbox; - for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { - - std::vector zinfo; - if (! lp->has_children ()) { - zinfo = zdata (mp_view, lp->cellview_index (), lp->layer_index ()); - } - - for (std::vector::const_iterator zi = zinfo.begin (); zi != zinfo.end (); ++zi) { - const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ()); - cell_bbox += db::CplxTrans (cv->layout ().dbu ()) * cv.cell ()->bbox ((unsigned int) lp->layer_index ()); - } - - } - - bool any = false; - - tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ..."))); - - for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { - - std::vector zinfo; - if (! lp->has_children ()) { - zinfo = zdata (mp_view, lp->cellview_index (), lp->layer_index ()); - } - - for (std::vector::const_iterator zi = zinfo.begin (); zi != zinfo.end (); ++zi) { - - any = true; - - double z0 = zi->zstart (); - double z1 = zi->zstop (); - - m_vertex_chunks.push_back (triangle_chunks_type ()); - m_line_chunks.push_back (line_chunks_type ()); - - LayerInfo info; - lp_to_info (*lp, info); - info.vertex_chunk = &m_vertex_chunks.back (); - info.line_chunk = &m_line_chunks.back (); - - m_layer_to_info.insert (std::make_pair (std::make_pair (lp->cellview_index (), lp->layer_index ()), m_layers.size ())); - m_layers.push_back (info); - - const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ()); - - render_layout (progress, m_vertex_chunks.back (), m_line_chunks.back (), cv->layout (), *cv.cell (), db::CplxTrans (cv->layout ().dbu ()).inverted () * m_bbox, (unsigned int) lp->layer_index (), z0, z1); - - if (! zset) { - m_zmin = z0; - m_zmax = z1; - zset = true; - } else { - m_zmin = std::min (z0, m_zmin); - m_zmax = std::max (z1, m_zmax); - } - - } - - } - - return any; + info.visible = true; } void -D25ViewWidget::refresh_view () +D25ViewWidget::open_display (const color_t *frame_color, const color_t *fill_color, const db::LayerProperties *like, const std::string *name) { - if (! mp_view) { - return; + m_vertex_chunks.push_back (triangle_chunks_type ()); + m_line_chunks.push_back (line_chunks_type ()); + + LayerInfo info; + + info.visible = true; + color_to_gl (frame_color, info.frame_color); + color_to_gl (fill_color, info.fill_color); + + info.has_name = (name != 0 || like != 0); + if (name) { + info.name = *name; + } else if (like) { + info.name = like->to_string (); } - for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { + info.vertex_chunk = &m_vertex_chunks.back (); + info.line_chunk = &m_line_chunks.back (); - std::pair key = std::make_pair (lp->cellview_index (), lp->layer_index ()); - - std::multimap, size_t>::const_iterator l = m_layer_to_info.find (key); - while (l != m_layer_to_info.end () && l->first == key) { - if (l->second < m_layers.size ()) { - lp_to_info (*lp, m_layers [l->second]); + if (like && mp_view) { + for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { + if (! lp->has_children () && lp->source (true).layer_props ().log_equal (*like)) { + lp_to_info (*lp, info); + break; } - ++l; + } + } + + m_layers.push_back (info); + m_display_open = true; +} + +void +D25ViewWidget::close_display () +{ + m_display_open = false; +} + +void +D25ViewWidget::enter (const db::RecursiveShapeIterator *iter, double zstart, double zstop) +{ + tl_assert (m_display_open); + + if (! m_zset) { + m_zmin = std::min (zstart, zstop); + m_zmax = std::max (zstart, zstop); + m_zset = true; + } else { + m_zmin = std::min (m_zmin, std::min (zstart, zstop)); + m_zmax = std::min (m_zmax, std::max (zstart, zstop)); + } + + LayerInfo &info = m_layers.back (); + + // try to establish a default color from the region's origin if required + if (mp_view && info.fill_color [3] == 0.0 && info.frame_color [3] == 0.0) { + + if (iter) { + + if (iter && iter->layout () && iter->layout ()->is_valid_layer (iter->layer ())) { + + db::LayerProperties like = iter->layout ()->get_properties (iter->layer ()); + + for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { + if (! lp->has_children () && lp->source (true).layer_props ().log_equal (like)) { + lp_to_info (*lp, info); + if (! info.has_name) { + info.name = like.to_string (); + info.has_name = true; + } + break; + } + } + + } + + } else { + + // sequential assignment + lay::color_t color = mp_view->get_palette ().luminous_color_by_index (m_layers.size ()); + color_to_gl (color, info.fill_color); + } } +} - refresh (); +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 (); + } + + enter (iter, zstart, zstop); + + tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ..."))); + render_region (progress, *m_layers.back ().vertex_chunk, *m_layers.back ().line_chunk, data, dbu, db::CplxTrans (dbu).inverted () * m_bbox, zstart, zstop); +} + +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 (); + } + + enter (iter, zstart, zstop); + + tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ..."))); + render_edges (progress, *m_layers.back ().vertex_chunk, *m_layers.back ().line_chunk, data, dbu, db::CplxTrans (dbu).inverted () * m_bbox, zstart, zstop); +} + +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 (); + } + + enter (iter, zstart, zstop); + + tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ..."))); + render_edge_pairs (progress, *m_layers.back ().vertex_chunk, *m_layers.back ().line_chunk, data, dbu, db::CplxTrans (dbu).inverted () * m_bbox, zstart, zstop); +} + +void +D25ViewWidget::finish () +{ + // .. nothing yet .. +} + +void +D25ViewWidget::attach_view (LayoutView *view) +{ + mp_view = view; } void @@ -793,31 +797,23 @@ D25ViewWidget::render_wall (D25ViewWidget::triangle_chunks_type &chunks, D25View } void -D25ViewWidget::render_layout (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Layout &layout, const db::Cell &cell, const db::Box &clip_box, unsigned int layer, double zstart, double zstop) +D25ViewWidget::render_region (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Region ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop) { std::vector poly_heap; - // TODO: hidden cells, hierarchy depth ... - - db::RecursiveShapeIterator s (layout, cell, layer, clip_box); - s.shape_flags (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); - for ( ; ! s.at_end (); ++s) { - - db::Polygon polygon; - s->polygon (polygon); - polygon.transform (s.trans ()); + for (db::Region::const_iterator p = region.begin (); !p.at_end (); ++p) { poly_heap.clear (); - db::clip_poly (polygon, clip_box, poly_heap, false /*keep holes*/); + db::clip_poly (*p, clip_box, poly_heap, false /*keep holes*/); for (std::vector::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) { ++progress; - render_polygon (chunks, line_chunks, *p, layout.dbu (), zstart, zstop); + render_polygon (chunks, line_chunks, *p, dbu, zstart, zstop); for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { - render_wall (chunks, line_chunks, *e, layout.dbu (), zstart, zstop); + render_wall (chunks, line_chunks, *e, dbu, zstart, zstop); } } @@ -825,6 +821,43 @@ D25ViewWidget::render_layout (tl::AbsoluteProgress &progress, D25ViewWidget::tri } } +void +D25ViewWidget::render_edges (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Edges &edges, double dbu, const db::Box &clip_box, double zstart, double zstop) +{ + for (db::Edges::const_iterator e = edges.begin (); !e.at_end (); ++e) { + + ++progress; + + std::pair ec = e->clipped (clip_box); + if (ec.first) { + render_wall (chunks, line_chunks, ec.second, dbu, zstart, zstop); + } + + } +} + +void +D25ViewWidget::render_edge_pairs (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::EdgePairs &edge_pairs, double dbu, const db::Box &clip_box, double zstart, double zstop) +{ + for (db::EdgePairs::const_iterator e = edge_pairs.begin (); !e.at_end (); ++e) { + + ++progress; + + std::pair ec; + + ec = e->first ().clipped (clip_box); + if (ec.first) { + render_wall (chunks, line_chunks, ec.second, dbu, zstart, zstop); + } + + ec = e->second ().clipped (clip_box); + if (ec.first) { + render_wall (chunks, line_chunks, ec.second, dbu, zstart, zstop); + } + + } +} + static std::pair find_grid (double v) { for (int p = -12; p < 12; ++p) { @@ -852,22 +885,22 @@ D25ViewWidget::initializeGL () tl_assert (m_gridplane_program == 0); tl_assert (m_lines_program == 0); - bool error = false; + m_has_error = false; try { do_initialize_gl (); } catch (tl::Exception &ex) { m_error = ex.msg (); - error = true; + m_has_error = true; } catch (std::exception &ex) { m_error = ex.what (); - error = true; + m_has_error = true; } catch (...) { m_error = "(unspecific error)"; - error = true; + m_has_error = true; } - if (error) { + if (m_has_error) { delete m_shapes_program; m_shapes_program = 0; @@ -1098,8 +1131,8 @@ D25ViewWidget::paintGL () glEnableVertexAttribArray (positions); for (std::vector::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { - if (l->visible && l->color [3] > 0.5) { - m_shapes_program->setUniformValue ("color", l->color [0], l->color [1], l->color [2], l->color [3]); + if (l->visible && l->fill_color [3] > 0.5) { + m_shapes_program->setUniformValue ("color", l->fill_color [0], l->fill_color [1], l->fill_color [2], l->fill_color [3]); l->vertex_chunk->draw_to (this, positions, GL_TRIANGLES); } } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index 63b069463..af5dd0a54 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -27,6 +27,7 @@ #include "layD25MemChunks.h" #include "layD25Camera.h" +#include "layViewOp.h" #include #include @@ -41,8 +42,11 @@ namespace db { - class Layout; - class Cell; + class Region; + class Edges; + class EdgePairs; + class RecursiveShapeIterator; + struct LayerProperties; } namespace tl @@ -78,6 +82,20 @@ class D25ViewWidget Q_OBJECT public: + typedef lay::mem_chunks triangle_chunks_type; + typedef lay::mem_chunks line_chunks_type; + + struct LayerInfo + { + triangle_chunks_type *vertex_chunk; + line_chunks_type *line_chunk; + GLfloat fill_color [4]; + GLfloat frame_color [4]; + bool visible; + std::string name; + bool has_name; + }; + D25ViewWidget (QWidget *parent); ~D25ViewWidget (); @@ -88,8 +106,7 @@ public: void mouseReleaseEvent (QMouseEvent *event); void mouseMoveEvent (QMouseEvent *event); - bool attach_view(lay::LayoutView *view); - void refresh_view (); + void attach_view(lay::LayoutView *view); QVector3D hit_point_with_scene(const QVector3D &line_dir); void refresh (); @@ -129,6 +146,26 @@ public: return m_error; } + bool has_error () const + { + return m_has_error; + } + + const std::vector &layers () const + { + return m_layers; + } + + void set_material_visible (size_t index, bool visible); + + void clear (); + void open_display (const color_t *frame_color, const color_t *fill_color, const db::LayerProperties *like, const std::string *name); + void close_display (); + void entry (const db::Region &data, double dbu, double zstart, double zstop); + void entry (const db::Edges &data, double dbu, double zstart, double zstop); + void entry (const db::EdgePairs &data, double dbu, double zstart, double zstop); + void finish (); + signals: void scale_factor_changed (double f); void vscale_factor_changed (double f); @@ -143,44 +180,36 @@ public slots: void fit (); private: - typedef lay::mem_chunks triangle_chunks_type; - typedef lay::mem_chunks line_chunks_type; - std::unique_ptr mp_mode; QOpenGLShaderProgram *m_shapes_program, *m_lines_program, *m_gridplane_program; std::string m_error; + bool m_has_error; double m_scale_factor; double m_vscale_factor; QVector3D m_displacement; lay::LayoutView *mp_view; db::DBox m_bbox; double m_zmin, m_zmax; + bool m_zset; + bool m_display_open; std::list m_vertex_chunks; std::list m_line_chunks; - struct LayerInfo { - const triangle_chunks_type *vertex_chunk; - const line_chunks_type *line_chunk; - GLfloat color [4]; - GLfloat frame_color [4]; - bool visible; - }; - std::vector m_layers; - std::multimap, size_t> m_layer_to_info; void initializeGL (); void paintGL (); void resizeGL (int w, int h); void do_initialize_gl (); - bool prepare_view(); - void render_layout (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Layout &layout, const db::Cell &cell, const db::Box &clip_box, unsigned int layer, double zstart, double zstop); + void render_region (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Region ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop); + void render_edges (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Edges ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop); + void render_edge_pairs (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::EdgePairs ®ion, double dbu, const db::Box &clip_box, double zstart, double zstop); void render_polygon (D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Polygon &poly, double dbu, double zstart, double zstop); void render_wall (D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Edge &poly, double dbu, double zstart, double zstop); void reset_viewport (); - static void lp_to_info (const lay::LayerPropertiesNode &lp, D25ViewWidget::LayerInfo &info); + void enter (const db::RecursiveShapeIterator *iter, double zstart, double zstop); }; } diff --git a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro index b05f93e94..220aa3cf8 100644 --- a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro +++ b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro @@ -4,9 +4,13 @@ DESTDIR = $$OUT_PWD/../../../../lay_plugins include($$PWD/../../../lay_plugin.pri) -INCLUDEPATH += $$RDB_INC $$ANT_INC -DEPENDPATH += $$RDB_INC $$ANT_INC +INCLUDEPATH += $$RDB_INC $$ANT_INC $$QTBASIC_INC +DEPENDPATH += $$RDB_INC $$ANT_INC $$QTBASIC_INC + LIBS += -L$$DESTDIR/.. -lklayout_rdb -lklayout_ant +equals(HAVE_QTBINDINGS, "1") { + LIBS += -lklayout_qtbasic -lklayout_QtGui -lklayout_QtCore +} HEADERS = \ layD25View.h \ @@ -16,6 +20,7 @@ HEADERS = \ layD25Camera.h SOURCES = \ + gsiDeclLayD25View.cc \ layD25View.cc \ layD25ViewWidget.cc \ layD25Plugin.cc \ @@ -26,6 +31,9 @@ SOURCES = \ FORMS = \ D25View.ui \ +RESOURCES = \ + layD25Resources.qrc \ + greaterThan(QT_MAJOR_VERSION, 5) { QT += openglwidgets } diff --git a/src/plugins/tools/view_25d/lay_plugin/templates/d25.lym b/src/plugins/tools/view_25d/lay_plugin/templates/d25.lym new file mode 100644 index 000000000..7580c81c6 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/templates/d25.lym @@ -0,0 +1,63 @@ + + + General;;2.5d view generator script (*.lyd25)\nA script generating a 2.5d view + + d25 + + + + false + false + + true + d25_scripts + tools_menu.d25.end + ruby + + +# Read about 2.5d generator scripts in the User Manual in "Various Topics/The 2.5d View" + +# The script utilizes the DRC language with these two extensions +# +# z(layer, options ...): +# +# This function generates a extruded view from the given layer. +# +# Some options control the z extrusion: +# +# z(layer, 0.1 .. 0.2) extrude layer to z = 0.1 to 0.2 um +# z(layer, zstart: 0.1, zstop: 0.2) same as above +# z(layer, zstart: 0.1, height: 0.1) same as above, but with height instead of zstop +# z(layer, height: 200.nm) extrude layer from last z position with a height of 200nm +# +# You can specify display options: +# +# z(..., color: 0xff0000) use bright red for the material color (RGB) +# z(..., frame: 0xff0000) use bright red for the frame color (combine with "fill" for the fill color) +# z(..., fill: 0x00ff00) use bright green for the fill color along (combine with "frame" for the frame color) +# z(..., like: "7/0") borrow style from layout view's style for layer "7/0" +# z(..., name: "M1") assigns a name to show for the material +# +# If no display options are given and layer is an original layer, the colors are taken +# from the original layer's display style. Otherwise KLayout decides about the +# colors itself using the application's palette. +# +# zz(options) { block } +# zz(z(...), z(...), ..., options): +# +# Creates a display group. The display options are the same for all +# extrusion specs within the group. +# +# The options of "zz" are "name", "color", "frame", "fill" and "like". + +z(input(1, 0), 0.1 .. 0.2) +z(input(2, 0), height: 250.nm, color: 0xffbc80) + +zz(like: 7/0, name: "Metal") do + z(input(7, 0), height: 100.nm) + z(input(8, 0), height: 150.nm) +end + + + + diff --git a/testdata/algo/layout_utils_au_sns4.oas b/testdata/algo/layout_utils_au_sns4.oas new file mode 100644 index 000000000..3213ccba4 Binary files /dev/null and b/testdata/algo/layout_utils_au_sns4.oas differ diff --git a/testdata/algo/scale_and_snap4.oas b/testdata/algo/scale_and_snap4.oas new file mode 100644 index 000000000..a92021ed5 Binary files /dev/null and b/testdata/algo/scale_and_snap4.oas differ