Merge pull request #763 from KLayout/25d-enhancements

25d enhancements
This commit is contained in:
Matthias Köfferlein 2021-04-03 15:33:57 +02:00 committed by GitHub
commit 85448966d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 524 additions and 150 deletions

View File

@ -119,6 +119,7 @@ D25TechnologyComponent::D25TechnologyComponent ()
// provide some explanation for the initialization
m_src =
"# Provide z stack information here\n"
"#\n"
"# Each line is one layer. The specification consists of a layer specification, a colon and arguments.\n"
"# The arguments are named (like \"x=...\") or in serial. Parameters are separated by comma or blanks.\n"
"# Named arguments are:\n"
@ -127,7 +128,7 @@ D25TechnologyComponent::D25TechnologyComponent ()
"# zstop The upper z position of the extruded layer in µm\n"
"# height The height of the extruded layer in µm\n"
"#\n"
"# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart', "
"# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart',\n"
"# the upper level of the previous layer will be used.\n"
"#\n"
"# If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to\n"
@ -139,25 +140,52 @@ D25TechnologyComponent::D25TechnologyComponent ()
"# 1: zstop=1.5, zstart=0.5 # same with named parameters\n"
"# 1: height=1.0, zstop=1.5 # same with z stop minus height\n"
"# 1: 1.0 zstop=1.5 # same with height as unnamed parameter\n"
"#\n"
"# VARIABLES\n"
"#\n"
"# You can declare variables with:\n"
"# var name = value\n"
"#\n"
"# You can use variables inside numeric expressions.\n"
"# Example:\n"
"# var hmetal = 0.48\n"
"# 7/0: 0.5 0.5+hmetal*2 # 2x thick metal\n"
"#\n"
"# You cannot use variables inside layer specifications currently.\n"
"#\n"
"# CONDITIONALS\n"
"#\n"
"# You can enable or disable branches of the table using 'if', 'else', 'elseif' and 'end':\n"
"# Example:\n"
"# var thick_m1 = true\n"
"# if thickm1\n"
"# 1: 0.5 1.5\n"
"# else\n"
"# 1: 0.5 1.2\n"
"# end\n"
"\n"
;
}
D25TechnologyComponent::D25TechnologyComponent (const D25TechnologyComponent &d)
: db::TechnologyComponent (d25_component_name (), d25_description ())
{
m_layers = d.m_layers;
m_src = d.m_src;
}
void
D25TechnologyComponent::compile_from_source (const std::string &src)
D25TechnologyComponent::layers_type
D25TechnologyComponent::compile_from_source () const
{
layers_type layers;
int current_line = 0;
m_layers.clear ();
try {
std::vector<std::string> lines = tl::split (src, "\n");
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;
@ -168,12 +196,86 @@ D25TechnologyComponent::compile_from_source (const std::string &src)
// ignore comments
} else if (ex.at_end ()) {
// ignore empty lines
} else if (ex.test ("if")) {
tl::Expression x;
eval.parse (x, ex);
conditional_stack.push_back (x.execute ().to_bool ());
ex.expect_end ();
} else if (ex.test ("else")) {
if (conditional_stack.empty ()) {
throw tl::Exception (tl::to_string (tr ("'else' without 'if'")));
}
conditional_stack.back () = ! conditional_stack.back ();
ex.expect_end ();
} else if (ex.test ("end")) {
if (conditional_stack.empty ()) {
throw tl::Exception (tl::to_string (tr ("'end' without 'if'")));
}
conditional_stack.pop_back ();
ex.expect_end ();
} else if (ex.test ("elsif")) {
if (conditional_stack.empty ()) {
throw tl::Exception (tl::to_string (tr ("'elsif' without 'if'")));
}
tl::Expression x;
eval.parse (x, ex);
conditional_stack.back () = x.execute ().to_bool ();
ex.expect_end ();
} else if (! conditional_stack.empty () && ! conditional_stack.back ()) {
continue;
} else if (ex.test ("var")) {
std::string n;
ex.read_name (n);
ex.expect ("=");
tl::Expression x;
eval.parse (x, ex);
eval.set_var (n, x.execute ());
ex.expect_end ();
} else if (ex.test ("print")) {
tl::Expression x;
eval.parse (x, ex);
ex.expect_end ();
tl::info << x.execute ().to_string ();
} else if (ex.test ("error")) {
tl::Expression x;
eval.parse (x, ex);
ex.expect_end ();
throw tl::Exception (x.execute ().to_string ());
} else {
db::D25LayerInfo info;
if (! m_layers.empty ()) {
info.set_zstart (m_layers.back ().zstop ());
info.set_zstop (m_layers.back ().zstop ());
if (! layers.empty ()) {
info.set_zstart (layers.back ().zstop ());
info.set_zstop (layers.back ().zstop ());
}
tl::Variant z0, z1, h;
@ -191,16 +293,18 @@ D25TechnologyComponent::compile_from_source (const std::string &src)
break;
}
double pv = 0.0;
tl::Expression pvx;
std::string pn;
if (ex.try_read_name (pn)) {
ex.expect ("=");
ex.read (pv);
eval.parse (pvx, ex);
} else {
ex.read (pv);
eval.parse (pvx, ex);
}
double pv = pvx.execute ().to_double ();
ex.test (",");
if (pn.empty ()) {
@ -220,7 +324,7 @@ D25TechnologyComponent::compile_from_source (const std::string &src)
if (args.size () == 0) {
if (z0.is_nil () && z1.is_nil ()) {
if (! h.is_nil ()) {
info.set_zstop (info.zstart () + h.to_double ());
info.set_zstop (info.zstop () + h.to_double ());
}
} else if (z0.is_nil ()) {
info.set_zstop (z1.to_double ());
@ -239,28 +343,28 @@ D25TechnologyComponent::compile_from_source (const std::string &src)
} else if (args.size () == 1) {
if (! h.is_nil ()) {
if (! z0.is_nil ()) {
throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstart already given")));
throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstart already given")));
}
if (! z1.is_nil ()) {
throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop implicitly given")));
throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop implicitly given")));
}
info.set_zstart (args[0]);
info.set_zstop (args[0] + h.to_double ());
} else {
if (! z1.is_nil ()) {
throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop implicitly given")));
throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop implicitly given")));
}
info.set_zstop ((! z0.is_nil () ? z0.to_double () : info.zstart ()) + args[0]);
}
} else if (args.size () == 2) {
if (! z0.is_nil ()) {
throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstart already given")));
throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstart already given")));
}
if (! z1.is_nil ()) {
throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop already given")));
throw tl::Exception (tl::to_string (tr ("Redundant parameters: zstop already given")));
}
if (! h.is_nil ()) {
throw tl::Exception (tl::to_string (tr ("Rundundant parameters: height implicitly given")));
throw tl::Exception (tl::to_string (tr ("Redundant parameters: height implicitly given")));
}
info.set_zstart (args[0]);
info.set_zstop (args[1]);
@ -268,25 +372,30 @@ D25TechnologyComponent::compile_from_source (const std::string &src)
throw tl::Exception (tl::to_string (tr ("Too many parameters (max 2)")));
}
m_layers.push_back (info);
layers.push_back (info);
}
}
if (! conditional_stack.empty ()) {
throw tl::Exception (tl::to_string (tr ("'if', 'else' or 'elsif' without matching 'end'")));
}
} catch (tl::Exception &ex) {
throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (" in line %d")), current_line));
}
m_src = src;
return layers;
}
std::string
D25TechnologyComponent::to_string () const
{
layers_type layers = compile_from_source ();
std::string res;
for (const_iterator i = begin (); i != end (); ++i) {
for (layers_type::const_iterator i = layers.begin (); i != layers.end (); ++i) {
if (! res.empty ()) {
res += "\n";
}
@ -317,11 +426,6 @@ public:
virtual tl::XMLElementBase *xml_element () const
{
return new db::TechnologyComponentXMLElement<D25TechnologyComponent> (d25_component_name (),
tl::make_element ((D25TechnologyComponent::const_iterator (D25TechnologyComponent::*) () const) &D25TechnologyComponent::begin, (D25TechnologyComponent::const_iterator (D25TechnologyComponent::*) () const) &D25TechnologyComponent::end, &D25TechnologyComponent::add, "layer",
tl::make_member (&D25LayerInfo::layer_as_string, &D25LayerInfo::set_layer_from_string, "layer") +
tl::make_member (&D25LayerInfo::zstart, &D25LayerInfo::set_zstart, "zstart") +
tl::make_member (&D25LayerInfo::zstop, &D25LayerInfo::set_zstop, "zstop")
) +
tl::make_member (&D25TechnologyComponent::src, &D25TechnologyComponent::set_src, "src")
);
}

View File

@ -76,55 +76,8 @@ public:
D25TechnologyComponent (const D25TechnologyComponent &d);
typedef std::list<D25LayerInfo> layers_type;
typedef layers_type::const_iterator const_iterator;
typedef layers_type::iterator iterator;
void compile_from_source (const std::string &src);
const_iterator begin () const
{
return m_layers.begin ();
}
iterator begin ()
{
return m_layers.begin ();
}
const_iterator end () const
{
return m_layers.end ();
}
iterator end ()
{
return m_layers.end ();
}
void clear ()
{
m_layers.clear ();
}
void erase (iterator p)
{
m_layers.erase (p);
}
void insert (iterator p, const D25LayerInfo &info)
{
m_layers.insert (p, info);
}
void add (const D25LayerInfo &info)
{
m_layers.push_back (info);
}
size_t size () const
{
return m_layers.size ();
}
layers_type compile_from_source () const;
const std::string &src () const
{
@ -145,7 +98,6 @@ public:
}
private:
layers_type m_layers;
std::string m_src;
};

View File

@ -30,44 +30,73 @@ TEST(1)
{
db::D25TechnologyComponent comp;
comp.compile_from_source ("1/0: 1.0 1.5 # a comment");
comp.set_src ("1/0: 1.0 1.5 # a comment");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5");
comp.set_src ("1/0: zstart=1.0 zstop=1.5");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
comp.compile_from_source ("1/0: zstart=1.0 height=0.5");
comp.set_src ("1/0: zstart=1.0 height=0.5");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
comp.compile_from_source ("1/0: 1.0 height=0.5");
comp.set_src ("1/0: 1.0 height=0.5");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
comp.compile_from_source ("1/0: zstop=1.5 height=0.5");
comp.set_src ("1/0: zstop=1.5 height=0.5");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5");
comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5\nname: height=3");
comp.set_src ("1/0: zstart=1.0 zstop=1.5\nname: height=3");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=1.5, zstop=4.5");
comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5\nname: zstart=4.0 height=3\n\n# a comment line");
comp.set_src ("1/0: zstart=1.0 zstop=1.5\nname: zstart=4.0 height=3\n\n# a comment line");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7");
comp.set_src ("var x=1.0\n1/0: zstart=x zstop=x+0.5\nname: zstart=4.0 height=3\n\n# a comment line");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7");
comp.set_src ("var x=1.0\nif x == 1.0\n1/0: zstart=x zstop=x+0.5\nelse\n1/0: zstart=0 zstop=0\nend\nname: zstart=4.0 height=3\n\n# a comment line");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7");
comp.set_src ("var x=2.0\nif x == 1.0\n1/0: zstart=x zstop=x+0.5\nelse\n1/0: zstart=0 zstop=0\nend\nname: zstart=4.0 height=3\n\n# a comment line");
comp.compile_from_source ();
EXPECT_EQ (comp.to_string (), "1/0: zstart=0, zstop=0\nname: zstart=4, zstop=7");
try {
comp.compile_from_source ("blabla");
comp.set_src ("blabla");
comp.compile_from_source ();
EXPECT_EQ (false, true);
} catch (...) { }
try {
comp.compile_from_source ("1/0: 1 2 3");
comp.set_src ("1/0: 1 2 3");
comp.compile_from_source ();
EXPECT_EQ (false, true);
} catch (...) { }
try {
comp.compile_from_source ("1/0: foo=1 bar=2");
comp.set_src ("1/0: foo=1 bar=2");
comp.compile_from_source ();
EXPECT_EQ (false, true);
} catch (...) { }
try {
comp.compile_from_source ("1/0: 1;2");
comp.set_src ("1/0: 1;*2");
comp.compile_from_source ();
EXPECT_EQ (false, true);
} catch (...) { }
try {
comp.set_src ("error 42");
comp.compile_from_source ();
EXPECT_EQ (false, true);
} catch (...) { }
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE language SYSTEM "klayout_doc.dtd">
<doc>
<title>The 2.5d View</title>
<keyword name="2.5d"/>
<keyword name="3d"/>
<keyword name="2.5d View"/>
<keyword name="z-Stack"/>
<h2-index/>
<p>
The "2.5d view" offers a semi-3d view of the layout. It's not a full 3d view as the layers are only extruded vertically
into layers with a certain thickness. The view cannot model process topology, but it can visualize
wiring congestions in a three-dimensional space or the vertical relative dimensions of features of the process stack.
</p>
<p>
To open the view, use "Tools/2.5d View". Currently, the performance is limited, a rough number for a
practical limit is around 100k polygons. The 2.5d view is only available, if KLayout was compiled with
OpenGL support.
</p>
<p>
<img src="/about/25d_screenshot.png"/>
</p>
<h2>Setup</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:
</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>
</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.
</p>
<p>
If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to
'zstart' and 'zstop'.
</p>
<p>
Here are some examples:
</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>
<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:
</p>
<pre>var thick_m1 = true
if thickm1
1: 0.5 1.5
else
1: 0.5 1.2
end
</pre>
<h2>Navigating the 2.5d View</h2>
<keyword>navigation</keyword>
<keyword>2.5d navigation</keyword>
<p>
The navigation is based on the movement of the camera while the scene is
formed by the extruded layout. The scene can be scaled to provide zoom features.
Scaling and rotation is relative to the pivot point which is indicated by the
compass icon on the ground plane.
</p>
<p>
This is a short list of the navigation controls which act on the camera:
</p>
<ul>
<li> Dragging with the right mouse button down: change azimuth and elevation angle </li>
<li> Dragging with the middle mouse button down: move the pivot up and down or left and right </li>
<li> Mouse wheel: moves the pivot forward and backward </li>
<li> Control key + mouse wheel: magnify or shrink the layout </li>
<li> Press and hold shift key: switch to top level view (see below) </li>
<li> Up/down keys: move the pivot forward or backward </li>
<li> Left/right keys: move the pivot to the left or the right </li>
<li> Control + up/down keys: change the elevation angle </li>
<li> Control + left/right keys: change the azimuth angle </li>
</ul>
<p>
In top level view, the navigation is slightly different:
</p>
<ul>
<li> Dragging with the right mouse button down: change azimuth angle </li>
<li> mouse wheel: magnify or shrink the layout </li>
<li> Up/down/left/right keys: move the pivot on the horizontal plane </li>
</ul>
</doc>

View File

@ -18,6 +18,7 @@
<topic href="/about/variant_notation.xml"/>
<topic href="/about/lef_def_import.xml"/>
<topic href="/about/connectivity.xml"/>
<topic href="/about/25d_view.xml"/>
<topic href="/about/symbolic_layers.xml"/>
<topic href="/about/layer_sources.xml"/>
<topic href="/about/macro_editor.xml"/>

View File

@ -47,6 +47,8 @@
<file alias="lvs_ref_global.xml">doc/about/lvs_ref_global.xml</file>
<file alias="lvs_ref_netter.xml">doc/about/lvs_ref_netter.xml</file>
<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>
</qresource>
<qresource prefix="/help/manual">
<file alias="adjust_origin.xml">doc/manual/adjust_origin.xml</file>

View File

@ -3942,7 +3942,7 @@ MainWindow::menu_activated (const std::string &symbol)
if (current_view ()) {
current_view ()->menu_activated (symbol);
} else {
throw tl::Exception (tl::to_string (QObject::tr ("No view is active")));
throw tl::Exception (tl::to_string (QObject::tr ("This function needs a layout but none was available")));
}
}

View File

@ -44,6 +44,12 @@
<family>Monospace</family>
</font>
</property>
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
<property name="acceptRichText">
<bool>false</bool>
</property>
</widget>
</item>
</layout>

View File

@ -95,6 +95,7 @@ BookmarkItem::to_string () const
BrowserPanel::BrowserPanel (QWidget *parent)
: QWidget (parent),
m_back_dm (this, &BrowserPanel::back),
m_new_url_dm (this, &BrowserPanel::new_url),
mp_dispatcher (0)
{
init ();
@ -125,6 +126,7 @@ BrowserPanel::init ()
mp_ui->browser->addAction (mp_ui->action_find);
mp_ui->browser->addAction (mp_ui->action_bookmark);
mp_ui->browser->setOpenLinks (false);
mp_ui->browser_bookmark_view->addAction (mp_ui->action_delete_bookmark);
mp_ui->browser_bookmark_view->setContextMenuPolicy (Qt::ActionsContextMenu);
@ -138,7 +140,8 @@ BrowserPanel::init ()
connect (mp_ui->search_edit, SIGNAL (textEdited (const QString &)), this, SLOT (search_text_changed (const QString &)));
connect (mp_ui->search_edit, SIGNAL (returnPressed ()), this, SLOT (search_edited ()));
connect (mp_ui->search_button, SIGNAL (clicked ()), this, SLOT (search_edited ()));
connect (mp_ui->browser, SIGNAL (textChanged ()), this, SLOT (text_changed ()));
connect (mp_ui->browser, SIGNAL (sourceChanged (const QUrl &)), this, SLOT (source_changed ()));
connect (mp_ui->browser, SIGNAL (anchorClicked (const QUrl &)), this, SLOT (anchor_clicked (const QUrl &)));
connect (mp_ui->browser, SIGNAL (backwardAvailable (bool)), mp_ui->back_pb, SLOT (setEnabled (bool)));
connect (mp_ui->browser, SIGNAL (forwardAvailable (bool)), mp_ui->forward_pb, SLOT (setEnabled (bool)));
connect (mp_ui->outline_tree, SIGNAL (itemActivated (QTreeWidgetItem *, int)), this, SLOT (outline_item_clicked (QTreeWidgetItem *)));
@ -218,7 +221,7 @@ BrowserPanel::title () const
std::string
BrowserPanel::url () const
{
return m_cached_url;
return tl::to_string (mp_ui->browser->source ().toString ());
}
void
@ -416,13 +419,24 @@ BrowserPanel::search_text_changed (const QString &text)
}
void
BrowserPanel::text_changed ()
BrowserPanel::source_changed ()
{
m_new_url_dm ();
}
void
BrowserPanel::anchor_clicked (const QUrl &url)
{
mp_ui->browser->setSource (url);
source_changed ();
}
void
BrowserPanel::new_url ()
{
QString title = mp_ui->browser->document ()->metaInformation (QTextDocument::DocumentTitle);
if (title != m_current_title) {
m_current_title = title;
emit title_changed (title);
}
m_current_title = title;
emit title_changed (title);
// refresh on-page search
page_search_edited ();

View File

@ -441,7 +441,9 @@ protected slots:
void page_search_next();
void search_text_changed(const QString &text);
void search_edited ();
void text_changed ();
void source_changed ();
void anchor_clicked (const QUrl &url);
void new_url ();
void outline_item_clicked (QTreeWidgetItem *item);
void bookmark_item_selected (QTreeWidgetItem *item);
void delete_bookmark ();
@ -462,6 +464,7 @@ private:
Ui::BrowserPanel *mp_ui;
bool m_schedule_back;
tl::DeferredMethod<BrowserPanel> m_back_dm;
tl::DeferredMethod<BrowserPanel> m_new_url_dm;
std::string m_search_url, m_search_query_item;
QString m_current_title;
QList<QTextEdit::ExtraSelection> m_search_selection;

View File

@ -72,7 +72,13 @@ D25TechnologyComponentEditor::commit ()
}
std::string src = tl::to_string (src_te->toPlainText ());
data->compile_from_source (src);
// test-compile before setting it
db::D25TechnologyComponent tc;
tc.set_src (src);
tc.compile_from_source ();
data->set_src (src);
}
void

View File

@ -5,13 +5,35 @@
<highlighting>
<list name="Control Keywords">
<item> zstart </item>
<item> zstop </item>
<item> height </item>
</list>
<list name="Expression Keywords">
<item> true </item>
<item> false </item>
<item> nil </item>
</list>
<contexts>
<context name="Normal" attribute="Normal Text">
<context name="Normal" attribute="Normal Text" fallthrough="true" fallthroughContext="Error" lineEndContext="Normal">
<RegExpr attribute="Normal" String="\s*" context="#stay"/>
<StringDetect attribute="Symbol" String="var" context="Expect Assignment"/>
<StringDetect attribute="Symbol" String="print" context="Expression"/>
<StringDetect attribute="Symbol" String="error" context="Expression"/>
<StringDetect attribute="Symbol" String="if" context="Expression"/>
<StringDetect attribute="Symbol" String="elsif" context="Expression"/>
<StringDetect attribute="Symbol" String="else" context="Expect Lineend"/>
<StringDetect attribute="Symbol" String="end" context="Expect Lineend"/>
<DetectChar attribute="String" char="&quot;" context="Quoted String"/>
<DetectChar attribute="String" char="'" context="Apostrophed String"/>
<DetectChar attribute="Comment" char="#" context="Comment"/>
<DetectChar attribute="Raw String" char="'" context="Apostrophed String"/>
<RegExpr attribute="Normal" String=":" context="After LD"/>
@ -22,22 +44,52 @@
<DetectChar attribute="Normal" char="/" context="#stay"/>
<RegExpr attribute="Raw String" String="[_a-zA-Z]\w*" context="#stay"/>
<RegExpr attribute="Error" String="[^\s]" context="Error"/>
</context>
<context name="Comment" attribute="Comment" lineEndContext="Normal">
</context>
<context name="After LD" attribute="Normal" lineEndContext="Normal">
<context name="Expect Lineend" attribute="Normal" lineEndContext="Normal" fallthrough="true" fallthroughContext="Error">
<RegExpr attribute="Normal" String="\s*" context="#stay"/>
<DetectChar attribute="Comment" char="#" context="Comment"/>
</context>
<context name="Expression" fallthrough="true" fallthroughContext="Error" lineEndContext="Normal">
<RegExpr attribute="Normal" String="\s*" context="#stay"/>
<DetectChar attribute="Comment" char="#" context="Comment"/>
<keyword attribute="Symbol" String="Expression Keywords" context="#stay"/>
<keyword attribute="Symbol" String="Control Keywords" context="Expect Expression"/>
<DetectChar attribute="String" char="&quot;" context="Quoted String"/>
<DetectChar attribute="String" char="'" context="Apostrophed String"/>
<RegExpr attribute="Name" String="[_a-zA-Z]\w*" context="#stay"/>
<RegExpr attribute="Float" String="\-?[0-9]([0-9]|_[0-9])*(\.[0-9]([0-9]|_[0-9])*)?([eE]\-?[1-9]([0-9]|_[0-9])*(\.[0-9]*)?)?" context="#stay"/>
<DetectChar attribute="Normal" char="," context="#stay"/>
<DetectChar attribute="Normal" char="=" context="#stay"/>
<StringDetect attribute="Symbol" String="zstart" context="#stay"/>
<StringDetect attribute="Symbol" String="zstop" context="#stay"/>
<StringDetect attribute="Symbol" String="height" context="#stay"/>
<RegExpr attribute="Error" String="[^\s]" context="Error"/>
<DetectChar attribute="Normal" char="(" context="#stay"/>
<DetectChar attribute="Normal" char=")" context="#stay"/>
<DetectChar attribute="Normal" char="[" context="#stay"/>
<DetectChar attribute="Normal" char="]" context="#stay"/>
<RegExpr attribute="Normal" String="[\^\*\.\+\-%/!=&lt;&gt;&amp;|,\?:]" context="#stay"/>
</context>
<context name="Expect Expression" attribute="Normal" lineEndContext="Error" fallthrough="true" fallthroughContext="Error">
<RegExpr attribute="Normal" String="\s*" context="#stay"/>
<DetectChar attribute="Normal" char="=" context="Expression"/>
</context>
<context name="Expect Assignment" attribute="Normal" lineEndContext="Error" fallthrough="true" fallthroughContext="Error">
<RegExpr attribute="Normal" String="\s*" context="#stay"/>
<RegExpr attribute="Name" String="[_a-zA-Z]\w*" context="Expect Expression"/>
</context>
<context name="After LD" attribute="Normal" lineEndContext="Error" fallthrough="true" fallthroughContext="Expression">
<RegExpr attribute="Normal" String="\s*" context="#stay"/>
<DetectChar attribute="Comment" char="#" context="Error"/>
</context>
<context name="Error" attribute="Error" lineEndContext="Normal">
@ -46,19 +98,21 @@
<context name="Quoted String" attribute="String" lineEndContext="Error">
<StringDetect attribute="String" String="\\" context="#stay"/>
<RegExpr attribute="String" String="\\\&quot;" context="#stay"/>
<DetectChar char="&quot;" attribute="String" context="Normal"/>
<DetectChar char="&quot;" attribute="String" context="#pop"/>
</context>
<context name="Apostrophed String" attribute="Raw String" lineEndContext="Error">
<StringDetect attribute="String" String="\\" context="#stay"/>
<RegExpr attribute="String" String="\\\'" context="#stay"/>
<DetectChar char="'" attribute="Raw String" context="Normal"/>
<DetectChar char="'" attribute="Raw String" context="#pop"/>
</context>
</contexts>
<itemDatas>
<itemData name="Normal Text" defStyleNum="dsNormal"/>
<itemData name="Name" defStyleNum="dsNormal"/>
<itemData name="Comment" defStyleNum="dsComment"/>
<itemData name="Float" defStyleNum="dsFloat"/>
@ -73,4 +127,12 @@
</itemDatas>
</highlighting>
<general>
<comments>
<comment name="singleLine" start="#"/>
</comments>
<keywords casesensitive="1" weakDeliminator="!?"/>
</general>
</language>

View File

@ -350,9 +350,9 @@
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<widget class="QLabel" name="doc_label">
<property name="text">
<string>Press and hold SHIFT for top view</string>
<string>Press and hold SHIFT for top view (&lt;a href=&quot;int:/about/25d_view.xml&quot;&gt;more&lt;/a&gt;)</string>
</property>
</widget>
</item>

View File

@ -43,7 +43,7 @@ D25Camera::~D25Camera ()
void
D25Camera::init ()
{
m_fov = 90.0;
m_fov = 45.0;
m_cam_azimuth = m_cam_elevation = 0.0;
m_top_view = false;
}

View File

@ -89,7 +89,7 @@ public:
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"))));
menu_entries.push_back (lay::menu_item ("lay::d25_view", "d25_view:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("2.5d View - experimental"))));
}
virtual bool configure (const std::string & /*name*/, const std::string & /*value*/)

View File

@ -23,6 +23,7 @@
#include "layD25View.h"
#include "layLayoutView.h"
#include "layQtTools.h"
#include "ui_D25View.h"
@ -53,6 +54,8 @@ D25View::D25View (QWidget *parent)
connect (mp_ui->d25_view, SIGNAL (init_failed ()), this, SLOT (init_failed ()));
mp_ui->gl_stack->setCurrentIndex (0);
lay::activate_help_links (mp_ui->doc_label);
}
D25View::~D25View ()

View File

@ -246,40 +246,23 @@ D25ViewWidget::wheelEvent (QWheelEvent *event)
} else {
// compute vector of line of sight
std::pair<QVector3D, QVector3D> ray = camera_normal (cam_perspective () * cam_trans (), px, py);
// by definition the ray goes through the camera position
QVector3D hp = hit_point_with_scene (ray.second);
double d = event->angleDelta ().y () * (1.0 / (90 * 16));
if (! (event->modifiers () & Qt::ControlModifier)) {
// No Ctrl is closeup
// No Ctrl is "move horizontally along the azimuth axis"
double f = event->angleDelta ().y () * (1.0 / (90 * 8));
m_displacement += -((f / m_scale_factor) * std::min (cam_dist (), double ((cam_position () - hp).length ()))) * ray.second;
QMatrix4x4 t;
t.rotate (cam_azimuth (), 0.0, 1.0, 0.0);
QVector3D cd = t.inverted ().map (QVector3D (0, 0, cam_dist ()));
m_displacement += d * cd;
} else {
// "Ctrl" is zoom
double f = exp (event->angleDelta ().y () * (1.0 / (90 * 8)));
QVector3D initial_displacement = m_displacement;
QVector3D displacement = m_displacement;
m_scale_factor *= f;
displacement += hp * (1.0 - f) / m_scale_factor;
// normalize the scene translation so the scene does not "flee"
QMatrix4x4 ct = cam_trans ();
initial_displacement = ct.map (initial_displacement);
displacement = ct.map (displacement);
lay::normalize_scene_trans (cam_perspective (), displacement, m_scale_factor, initial_displacement.z ());
m_displacement = ct.inverted ().map (displacement);
m_scale_factor *= exp (d);
emit scale_factor_changed (m_scale_factor);
@ -294,8 +277,65 @@ void
D25ViewWidget::keyPressEvent (QKeyEvent *event)
{
if (event->key () == Qt::Key_Shift) {
mp_mode.reset (0);
set_top_view (true);
} else if (event->key () == Qt::Key_Up || event->key () == Qt::Key_Down) {
if (! top_view () && (event->modifiers () & Qt::ControlModifier) != 0) {
// Ctrl + up/down changes elevation
double d = (event->key () == Qt::Key_Up ? 2 : -2);
set_cam_elevation (std::max (-90.0, std::min (90.0, cam_elevation () + d)));
} else {
// Move "into" or "out"
double d = (event->key () == Qt::Key_Up ? 0.1 : -0.1);
QMatrix4x4 t;
t.rotate (cam_azimuth (), 0.0, 1.0, 0.0);
QVector3D cd = t.inverted ().map (QVector3D (0, 0, cam_dist ()));
set_displacement (displacement () + d * cd);
}
} else if (event->key () == Qt::Key_Left || event->key () == Qt::Key_Right) {
if (! top_view () && (event->modifiers () & Qt::ControlModifier) != 0) {
// Ctrl + left/right changes azumith
double d = (event->key () == Qt::Key_Right ? 2 : -2);
double a = cam_azimuth () + d;
if (a < -180.0) {
a += 360.0;
} else if (a > 180.0) {
a -= 360.0;
}
set_cam_azimuth (a);
} else {
// Move "left" and "right"
double d = (event->key () == Qt::Key_Left ? 0.1 : -0.1);
QMatrix4x4 t;
t.rotate (cam_azimuth (), 0.0, 1.0, 0.0);
QVector3D cd = t.inverted ().map (QVector3D (cam_dist (), 0, 0));
set_displacement (displacement () + d * cd);
}
}
}
@ -435,17 +475,17 @@ namespace {
const db::D25LayerInfo *operator() (lay::LayoutView *view, int cv_index, int layer_index)
{
std::map<int, std::map<int, const db::D25LayerInfo *> >::const_iterator c = m_cache.find (cv_index);
std::map<int, std::map<int, db::D25LayerInfo> >::const_iterator c = m_cache.find (cv_index);
if (c != m_cache.end ()) {
std::map<int, const db::D25LayerInfo *>::const_iterator l = c->second.find (layer_index);
std::map<int, db::D25LayerInfo>::const_iterator l = c->second.find (layer_index);
if (l != c->second.end ()) {
return l->second;
return &l->second;
} else {
return 0;
}
}
std::map<int, const db::D25LayerInfo *> &lcache = m_cache [cv_index];
std::map<int, db::D25LayerInfo> &lcache = m_cache [cv_index];
const db::D25TechnologyComponent *comp = 0;
@ -457,16 +497,18 @@ namespace {
if (comp) {
std::map<db::LayerProperties, const db::D25LayerInfo *, db::LPLogicalLessFunc> zi_by_lp;
for (db::D25TechnologyComponent::const_iterator i = comp->begin (); i != comp->end (); ++i) {
zi_by_lp.insert (std::make_pair (i->layer (), i.operator-> ()));
std::map<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)) {
const db::LayerProperties &lp = ly.get_properties (l);
std::map<db::LayerProperties, const db::D25LayerInfo *, db::LPLogicalLessFunc>::const_iterator z = zi_by_lp.find (lp);
std::map<db::LayerProperties, db::D25LayerInfo, db::LPLogicalLessFunc>::const_iterator z = zi_by_lp.find (lp);
if (z == zi_by_lp.end () && ! lp.name.empty ()) {
// If possible, try by name only
z = zi_by_lp.find (db::LayerProperties (lp.name));
@ -485,7 +527,7 @@ namespace {
private:
std::map<int, std::map<int, const db::D25LayerInfo *> > m_cache;
std::map<int, std::map<int, db::D25LayerInfo> > m_cache;
};
}
@ -955,9 +997,12 @@ D25ViewWidget::paintGL ()
vertexes.add (-0.25 * compass_rad, 0.0, 0.6 * compass_rad);
vertexes.add (0.0, 0.0, -0.8 * compass_rad);
vertexes.add (0.0, 0.0, -0.8 * compass_rad);
vertexes.add (0.25 * compass_rad, 0.0, 0.6 * compass_rad);
vertexes.add (0.25 * compass_rad, 0.0, 0.6 * compass_rad);
vertexes.add (-0.25 * compass_rad, 0.0, 0.6 * compass_rad);
vertexes.draw_to (this, positions, GL_TRIANGLES);
vertexes.draw_to (this, positions, GL_LINES);
// draw base plane
@ -1029,8 +1074,8 @@ D25ViewWidget::paintGL ()
glDisable (GL_DEPTH_TEST);
int cube_size = 64;
int cube_margin = 20;
int cube_size = 32;
int cube_margin = 40;
QMatrix4x4 into_top_right_corner;
into_top_right_corner.translate (1.0 - 2.0 / width () * (cube_margin + cube_size / 2), 1.0 - 2.0 / height () * (cube_margin + cube_size / 2));