mirror of https://github.com/KLayout/klayout.git
Merge pull request #1019 from KLayout/25d-with-booleans
25d with booleans
This commit is contained in:
commit
9fc7f9cfb6
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -511,19 +511,52 @@ VariantsCollectorBase::create_var_instances_non_tl_invariant (db::Cell &in_cell,
|
|||
std::map<db::cell_index_type, std::map<db::ICplxTrans, db::cell_index_type> >::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<db::ICplxTrans, db::cell_index_type> &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<db::ICplxTrans, db::cell_index_type>::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<db::ICplxTrans, db::cell_index_type>::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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<bool> conditional_stack;
|
||||
|
||||
std::vector<std::string> lines = tl::split (m_src, "\n");
|
||||
for (std::vector<std::string>::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<double> 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<D25TechnologyComponent> (d25_component_name (),
|
||||
tl::make_member (&D25TechnologyComponent::src, &D25TechnologyComponent::set_src, "src")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
static tl::RegisteredClass<db::TechnologyComponentProvider> tc_decl (new D25TechnologyComponentProvider (), 3100, d25_component_name ().c_str ());
|
||||
|
||||
}
|
||||
|
|
@ -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<D25LayerInfo> 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
|
||||
|
|
@ -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<db::CellInst> (*mp_subject_layout)).to_string()).c_str(),
|
||||
mp_intruder_layout->cell_name (inst2->object ().cell_index ()), int (inst2->size ()), (inst2->bbox(db::box_convert<db::CellInst> (*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<db::ICplxTrans, std::list<std::pair<db::cell_index_type, db::ICplxTrans> > > 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<TS, TI, TR>::compute_contexts (local_processor_contexts<TS,
|
|||
const typename local_processor_cell_contexts<TS, TI, TR>::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) {
|
||||
|
|
|
|||
|
|
@ -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<db::Edge, db::properties_id_type, EdgeCompareOpWithTolerance, std_compare_func<db::properties_id_type> > (EdgeCompareOpWithTolerance (tolerance), std_compare_func<db::properties_id_type> ());
|
||||
}
|
||||
|
||||
pair_compare_func<db::EdgePair, db::properties_id_type, EdgePairCompareOpWithTolerance, std_compare_func<db::properties_id_type> >
|
||||
make_edge_pair_compare_func (db::Coord tolerance)
|
||||
{
|
||||
return pair_compare_func<db::EdgePair, db::properties_id_type, EdgePairCompareOpWithTolerance, std_compare_func<db::properties_id_type> > (EdgePairCompareOpWithTolerance (tolerance), std_compare_func<db::properties_id_type> ());
|
||||
}
|
||||
|
||||
pair_compare_func<db::Box, db::properties_id_type, BoxCompareOpWithTolerance, std_compare_func<db::properties_id_type> >
|
||||
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<db::EdgePair, db::properties_id_type> > &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<db::Box, db::properties_id_type> > &shapes, PropertyMapper &pn)
|
||||
{
|
||||
|
|
@ -828,6 +875,8 @@ do_compare_layouts (const db::Layout &a, const db::Cell *top_a, const db::Layout
|
|||
std::vector <std::pair <db::Box, db::properties_id_type> > boxes_b;
|
||||
std::vector <std::pair <db::Edge, db::properties_id_type> > edges_a;
|
||||
std::vector <std::pair <db::Edge, db::properties_id_type> > edges_b;
|
||||
std::vector <std::pair <db::EdgePair, db::properties_id_type> > edge_pairs_a;
|
||||
std::vector <std::pair <db::EdgePair, db::properties_id_type> > 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 <std::pair <db::Edge, db::properties_id_type> > &a, const std::vector <std::pair <db::Edge, db::properties_id_type> > &b);
|
||||
void end_edge_differences ();
|
||||
void begin_edge_pair_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &b);
|
||||
void end_edge_pair_differences ();
|
||||
void begin_text_differences ();
|
||||
void detailed_diff (const db::PropertiesRepository &pr, const std::vector <std::pair <db::Text, db::properties_id_type> > &a, const std::vector <std::pair <db::Text, db::properties_id_type> > &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 <std::pair <db::EdgePair, db::properties_id_type> > &a, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > &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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,6 +119,9 @@ public:
|
|||
virtual void begin_edge_differences () { }
|
||||
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::Edge, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::Edge, db::properties_id_type> > & /*b*/) { }
|
||||
virtual void end_edge_differences () { }
|
||||
virtual void begin_edge_pair_differences () { }
|
||||
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::EdgePair, db::properties_id_type> > & /*b*/) { }
|
||||
virtual void end_edge_pair_differences () { }
|
||||
virtual void begin_text_differences () { }
|
||||
virtual void detailed_diff (const db::PropertiesRepository & /*pr*/, const std::vector <std::pair <db::Text, db::properties_id_type> > & /*a*/, const std::vector <std::pair <db::Text, db::properties_id_type> > & /*b*/) { }
|
||||
virtual void end_text_differences () { }
|
||||
|
|
|
|||
|
|
@ -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<db::ScaleAndGridReducer> 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<db::cell_index_type> 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<db::Point> 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<db::Point> heap;
|
||||
std::vector<db::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<db::CellInstArray> 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<db::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<db::CellInstArray>::const_iterator i = new_insts.begin (); i != new_insts.end (); ++i) {
|
||||
c->insert (*i);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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 (...) { }
|
||||
}
|
||||
|
|
@ -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<db::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));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ SOURCES = \
|
|||
dbPolygonToolsTests.cc \
|
||||
dbTechnologyTests.cc \
|
||||
dbStreamLayerTests.cc \
|
||||
dbD25TechnologyComponentTests.cc \
|
||||
dbVectorTests.cc \
|
||||
dbVariableWidthPathTests.cc \
|
||||
dbTransTests.cc \
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
</text>
|
||||
|
|
|
|||
|
|
@ -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<std::string, std::string> > attrs;
|
||||
e->attributes (attrs);
|
||||
for (std::vector< std::pair<std::string, std::string> >::const_iterator a = attrs.begin (); a != attrs.end (); ++a) {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@
|
|||
<widget class="QLabel" name="interpreterLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
|
|
@ -224,25 +223,56 @@
|
|||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Priority</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Prolog</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="prolog"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="epilog"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Epilog</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="priority">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>for autorun: 0 = first, 1 = second ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="prolog">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="epilog"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 154 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 73 KiB |
|
|
@ -18,97 +18,187 @@
|
|||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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 <link href="/manual/drc.xml"/>).
|
||||
The DRC language is used to import or generate polygon layers which are then
|
||||
extruded and placed on a certain z level.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
To create a new script, use "Tools/2.5d View/New 2.5d Script". This will create a new script in the
|
||||
macro editor.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="/about/25d_screenshot.png"/>
|
||||
</p>
|
||||
|
||||
<h2>Setup</h2>
|
||||
<h2>2.5d Script Anatomy</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Each entry is a single line. Empty lines are ignored. Everything after a '#' character is
|
||||
considered a comment.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li> <b>zstart</b>: The lower z position of the extruded layer in µm </li>
|
||||
<li> <b>zstop</b>: The upper z position of the extruded layer in µm </li>
|
||||
<li> <b>height</b>: The height of the extruded layer in µm </li>
|
||||
<li>You should not use external sources ("source" statement) as the 2.5d view is related to the loaded layout</li>
|
||||
<li>Report generation or "output" statements are permitted, but do not make much sense in the context
|
||||
of 2.5d view scripts.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
'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:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><p><tt>z(</tt>layer [, options]<tt>)</tt></p>
|
||||
<p>Extrudes the given layer. "layer" is a DRC layer (polygon, edge or even edge pair). "options" declare the z extrusion and display parameters.</p>
|
||||
</li>
|
||||
<li><p><tt>zz(</tt> [options] <tt>) {</tt> block <tt>}</tt></p>
|
||||
<p>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.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>"z" Function (plane extrusion)</h3>
|
||||
<keyword name="z"/>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to
|
||||
'zstart' and 'zstop'.
|
||||
Options for this function are:
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li><b>zstart</b>: specifies the bottom coordinate of the extruded sheet. If this option is not given, the top coordinate of the previous "z" statement is used.</li>
|
||||
<li><b>zstop</b>: specifies the top coordinate of the extruded sheet. Alternatively you can use "height".</li>
|
||||
<li><b>height</b>: specifies the extrusion height. Alternatively you can use "zstop".</li>
|
||||
<li><b>color</b>: 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.</li>
|
||||
<li><b>frame</b>: 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.</li>
|
||||
<li><b>fill</b>: 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".</li>
|
||||
<li><b>like</b>: 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).</li>
|
||||
<li><b>name</b>: gives the material a name for displaying in the material list.</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
Here are some examples:
|
||||
Examples for the extrusion options:
|
||||
</p>
|
||||
|
||||
<pre>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"
|
||||
</pre>
|
||||
|
||||
<h4>Variables</h4>
|
||||
|
||||
<p>
|
||||
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
|
||||
(<link href="/about/expressions.xml"/>).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Here is an example:
|
||||
</p>
|
||||
|
||||
<pre>var hmetal = 0.48\n"
|
||||
7/0: 0.5 0.5+hmetal*2 # 2x thick metal\n"
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<h4>Conditionals</h4>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>var thick_m1 = true
|
||||
if thickm1
|
||||
1: 0.5 1.5
|
||||
else
|
||||
1: 0.5 1.2
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<h3>"zz" Function (material groups)</h3>
|
||||
<keyword name="zz"/>
|
||||
|
||||
<p>
|
||||
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:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
zz( display options ... ) do
|
||||
z(layer1, extrusion options ... )
|
||||
z(layer2, extrusion options ... )
|
||||
...
|
||||
end
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
The "z" calls do not need to have colors or other display options as they are
|
||||
taken from "zz".
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Material groups allow forming more complex, stacked geometries. Here is an example
|
||||
forming a simple FinFET geometry using boolean and a sizing operation:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
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
|
||||
</pre>
|
||||
|
||||
<p>
|
||||
Which renders this result:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<img src="/about/25d_screenshot2.png"/>
|
||||
</p>
|
||||
|
||||
<h2>Navigating the 2.5d View</h2>
|
||||
<keyword>navigation</keyword>
|
||||
<keyword>2.5d navigation</keyword>
|
||||
<keyword name="navigation"/>
|
||||
<keyword name="2.5d view navigation"/>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<h2>Other controls</h2>
|
||||
<h2>Other Controls</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
<h2>Material Visibility</h2>
|
||||
|
||||
<p>
|
||||
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.
|
||||
</p>
|
||||
|
||||
</doc>
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ static std::string version (C *)
|
|||
return C::version ();
|
||||
}
|
||||
|
||||
template <class C>
|
||||
static void add_macro_category (C *c, const std::string &name, const std::string &description, const std::vector<std::string> &folders)
|
||||
{
|
||||
c->add_macro_category (name, description, folders);
|
||||
}
|
||||
|
||||
template <class C>
|
||||
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<C, const std::string &, const std::string &, const std::vector<std::string> &> ("add_macro_category", &add_macro_category<C>, 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<C *> ("instance", &C::instance,
|
||||
"@brief Return the singleton instance of the application\n"
|
||||
"\n"
|
||||
|
|
|
|||
|
|
@ -686,6 +686,22 @@ ApplicationBase::init_app ()
|
|||
|
||||
if (mc) {
|
||||
|
||||
// create the basic macro categories
|
||||
|
||||
if (ruby_interpreter ().available ()) {
|
||||
std::vector<std::string> folders;
|
||||
folders.push_back ("macros");
|
||||
folders.push_back ("ruby");
|
||||
mc->add_macro_category ("macros", "Ruby", folders);
|
||||
}
|
||||
|
||||
if (python_interpreter ().available ()) {
|
||||
std::vector<std::string> 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<std::string> 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<std::string> &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);
|
||||
|
|
|
|||
|
|
@ -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<std::string> &folders);
|
||||
|
||||
/**
|
||||
* @brief Return true, if undo buffering is enabled
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
<file alias="packages.xml">doc/about/packages.xml</file>
|
||||
<file alias="25d_view.xml">doc/about/25d_view.xml</file>
|
||||
<file alias="25d_screenshot.png">doc/about/25d_screenshot.png</file>
|
||||
<file alias="25d_screenshot2.png">doc/about/25d_screenshot2.png</file>
|
||||
</qresource>
|
||||
<qresource prefix="/help/manual">
|
||||
<file alias="adjust_origin.xml">doc/manual/adjust_origin.xml</file>
|
||||
|
|
|
|||
|
|
@ -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<std::string> &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 ();
|
||||
|
|
|
|||
|
|
@ -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<std::string> &folders);
|
||||
|
||||
/**
|
||||
* @brief Adds a temporary macro
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>D25TechnologyComponentEditor</class>
|
||||
<widget class="QFrame" name="D25TechnologyComponentEditor">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>549</width>
|
||||
<height>434</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><html>2.5d Vertical stack information (see <a href="int:/about/25d_view.xml">here</a> for details)</html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="lnum_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Line</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QTextEdit" name="src_te">
|
||||
<property name="lineWrapMode">
|
||||
<enum>QTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -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 <QResource>
|
||||
#include <QBuffer>
|
||||
|
||||
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 <db::D25TechnologyComponent *> (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 <db::D25TechnologyComponent *> (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<lay::TechnologyEditorProvider> editor_decl (new D25TechnologyComponentEditorProvider (), 3100, "d25");
|
||||
|
||||
} // namespace lay
|
||||
|
||||
|
|
@ -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 <memory>
|
||||
|
||||
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<lay::GenericSyntaxHighlighterAttributes> mp_hl_attributes, mp_hl_basic_attributes;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -35,8 +35,8 @@
|
|||
|
||||
namespace db
|
||||
{
|
||||
struct LayerProperties;
|
||||
class Layout;
|
||||
struct LayerProperties;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
|
|
|||
|
|
@ -46,6 +46,8 @@
|
|||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
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<lym::Macro> 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<std::string> *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<std::string> *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<std::string> *already_executed)
|
||||
{
|
||||
autorun_for (*this, true);
|
||||
autorun_for (*this, false, already_executed);
|
||||
}
|
||||
|
||||
void MacroCollection::autorun_early (std::set<std::string> *already_executed)
|
||||
{
|
||||
autorun_for (*this, true, already_executed);
|
||||
}
|
||||
|
||||
void MacroCollection::dump (int l)
|
||||
|
|
|
|||
|
|
@ -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<std::string> *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<std::string> *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);
|
||||
|
|
|
|||
|
|
@ -59,6 +59,42 @@
|
|||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="rerun_button">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Execute script again</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../lay/lay/layResources.qrc">
|
||||
<normaloff>:/run.png</normaloff>:/run.png</iconset>
|
||||
</property>
|
||||
<property name="autoRaise">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>10</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="zoom_slider">
|
||||
<property name="sizePolicy">
|
||||
|
|
@ -343,6 +379,9 @@
|
|||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="gl_stack">
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
|
|
@ -358,7 +397,60 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="lay::D25ViewWidget" name="d25_view"/>
|
||||
<widget class="QFrame" name="frame_3">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="lay::D25ViewWidget" name="d25_view">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QListWidget" name="material_list">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
|
@ -419,6 +511,21 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="empty_label">
|
||||
<property name="text">
|
||||
<string>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>.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
|
@ -482,6 +589,36 @@
|
|||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="select_all_action">
|
||||
<property name="text">
|
||||
<string>Select All</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="unselect_all_action">
|
||||
<property name="text">
|
||||
<string>Unselect All</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="show_all_action">
|
||||
<property name="text">
|
||||
<string>Show All</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="hide_all_action">
|
||||
<property name="text">
|
||||
<string>Hide All</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="show_selected_action">
|
||||
<property name="text">
|
||||
<string>Show Selected</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="hide_selected_action">
|
||||
<property name="text">
|
||||
<string>Hide Selected</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
|
@ -510,5 +647,37 @@
|
|||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>select_all_action</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>material_list</receiver>
|
||||
<slot>selectAll()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>716</x>
|
||||
<y>336</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>unselect_all_action</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>material_list</receiver>
|
||||
<slot>clearSelection()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>716</x>
|
||||
<y>336</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description/>
|
||||
<version/>
|
||||
<category/>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>true</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<group-name/>
|
||||
<menu-path/>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
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
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
|
|
@ -0,0 +1,171 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description/>
|
||||
<version/>
|
||||
<category/>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>false</autorun>
|
||||
<autorun-early>true</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>false</show-in-menu>
|
||||
<group-name/>
|
||||
<menu-path/>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
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
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
|
|
@ -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 <limits>
|
||||
|
||||
#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<lay::LayoutView> 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<lay::D25View> 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."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
@ -52,10 +52,9 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
virtual void get_menu_entries (std::vector<lay::MenuEntry> &menu_entries) const
|
||||
virtual void get_menu_entries (std::vector<lay::MenuEntry> & /*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*/)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<RCC>
|
||||
<qresource prefix="/built-in-macros">
|
||||
<file alias="_d25_engine.rb">built-in-macros/_d25_engine.rb</file>
|
||||
<file alias="d25_interpreters.lym">built-in-macros/d25_interpreters.lym</file>
|
||||
<file alias="d25_install.lym">built-in-macros/d25_install.lym</file>
|
||||
</qresource>
|
||||
<qresource prefix="/d25-templates">
|
||||
<file alias="d25.lym">templates/d25.lym</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
*/
|
||||
|
||||
#include "tlExceptions.h"
|
||||
#include "tlRecipe.h"
|
||||
|
||||
#include "layD25View.h"
|
||||
#include "layLayoutView.h"
|
||||
|
|
@ -29,13 +31,17 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QFontMetrics>
|
||||
|
||||
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<lay::D25View> ();
|
||||
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<lay::D25ViewWidget::LayerInfo> &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<std::string, tl::Variant> 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 ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,9 +24,11 @@
|
|||
#define HDR_layD25View
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
#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<D25View> dm_rerun_macro;
|
||||
tl::DeferredMethod<D25View> dm_fit;
|
||||
std::string m_generator;
|
||||
|
||||
void cellviews_changed ();
|
||||
void layer_properties_changed (int);
|
||||
void rerun_macro ();
|
||||
void fit ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<db::D25LayerInfo> operator() (lay::LayoutView *view, int cv_index, int layer_index)
|
||||
{
|
||||
std::map<int, std::map<int, std::vector<db::D25LayerInfo> > >::const_iterator c = m_cache.find (cv_index);
|
||||
if (c != m_cache.end ()) {
|
||||
std::map<int, std::vector<db::D25LayerInfo> >::const_iterator l = c->second.find (layer_index);
|
||||
if (l != c->second.end ()) {
|
||||
return l->second;
|
||||
} else {
|
||||
return std::vector<db::D25LayerInfo> ();
|
||||
}
|
||||
}
|
||||
|
||||
std::map<int, std::vector<db::D25LayerInfo> > &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<const db::D25TechnologyComponent *> (tech->component_by_name ("d25"));
|
||||
}
|
||||
|
||||
if (comp) {
|
||||
|
||||
std::multimap<db::LayerProperties, db::D25LayerInfo, db::LPLogicalLessFunc> 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<db::LayerProperties, db::D25LayerInfo, db::LPLogicalLessFunc>::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<int, std::vector<db::D25LayerInfo> >::const_iterator l = lcache.find (layer_index);
|
||||
if (l != lcache.end ()) {
|
||||
return l->second;
|
||||
} else {
|
||||
return std::vector<db::D25LayerInfo> ();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<int, std::map<int, std::vector<db::D25LayerInfo> > > 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<db::D25LayerInfo> zinfo;
|
||||
if (! lp->has_children ()) {
|
||||
zinfo = zdata (mp_view, lp->cellview_index (), lp->layer_index ());
|
||||
}
|
||||
|
||||
for (std::vector<db::D25LayerInfo>::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<db::D25LayerInfo> zinfo;
|
||||
if (! lp->has_children ()) {
|
||||
zinfo = zdata (mp_view, lp->cellview_index (), lp->layer_index ());
|
||||
}
|
||||
|
||||
for (std::vector<db::D25LayerInfo>::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<size_t, size_t> key = std::make_pair (lp->cellview_index (), lp->layer_index ());
|
||||
|
||||
std::multimap<std::pair<size_t, size_t>, 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<db::OriginalLayerRegion *> (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<db::OriginalLayerEdges *> (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<db::OriginalLayerEdgePairs *> (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<db::Polygon> 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<db::Polygon>::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<bool, db::Edge> 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<bool, db::Edge> 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<double, double> 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<LayerInfo>::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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "layD25MemChunks.h"
|
||||
#include "layD25Camera.h"
|
||||
#include "layViewOp.h"
|
||||
|
||||
#include <QOpenGLWidget>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
|
|
@ -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<GLfloat, 1024 * 18> triangle_chunks_type;
|
||||
typedef lay::mem_chunks<GLfloat, 1024 * 6> 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<LayerInfo> &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<GLfloat, 1024 * 18> triangle_chunks_type;
|
||||
typedef lay::mem_chunks<GLfloat, 1024 * 6> line_chunks_type;
|
||||
|
||||
std::unique_ptr<D25InteractionMode> 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<triangle_chunks_type> m_vertex_chunks;
|
||||
std::list<line_chunks_type> 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<LayerInfo> m_layers;
|
||||
std::multimap<std::pair<size_t, size_t>, 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);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<klayout-macro>
|
||||
<description>General;;2.5d view generator script (*.lyd25)\nA script generating a 2.5d view</description>
|
||||
<version/>
|
||||
<category>d25</category>
|
||||
<prolog/>
|
||||
<epilog/>
|
||||
<doc/>
|
||||
<autorun>false</autorun>
|
||||
<autorun-early>false</autorun-early>
|
||||
<shortcut/>
|
||||
<show-in-menu>true</show-in-menu>
|
||||
<group-name>d25_scripts</group-name>
|
||||
<menu-path>tools_menu.d25.end</menu-path>
|
||||
<interpreter>ruby</interpreter>
|
||||
<dsl-interpreter-name/>
|
||||
<text>
|
||||
# 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
|
||||
|
||||
</text>
|
||||
</klayout-macro>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue