From c4e5367b8a4bc27b40de2c4a57918b433229685d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 5 Apr 2020 18:22:45 +0200 Subject: [PATCH 01/27] First setup. --- .../tools/view_25d/lay_plugin/D25View.ui | 59 +++++++++ .../tools/view_25d/lay_plugin/layD25Plugin.cc | 112 ++++++++++++++++ .../tools/view_25d/lay_plugin/layD25View.cc | 65 ++++++++++ .../tools/view_25d/lay_plugin/layD25View.h | 65 ++++++++++ .../view_25d/lay_plugin/layD25ViewWidget.cc | 41 ++++++ .../view_25d/lay_plugin/layD25ViewWidget.h | 44 +++++++ .../tools/view_25d/lay_plugin/layXORPlugin.cc | 122 ++++++++++++++++++ .../tools/view_25d/lay_plugin/lay_plugin.pro | 21 +++ src/plugins/tools/view_25d/view_25d.pro | 6 + 9 files changed, 535 insertions(+) create mode 100644 src/plugins/tools/view_25d/lay_plugin/D25View.ui create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25View.cc create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25View.h create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h create mode 100644 src/plugins/tools/view_25d/lay_plugin/layXORPlugin.cc create mode 100644 src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro create mode 100644 src/plugins/tools/view_25d/view_25d.pro diff --git a/src/plugins/tools/view_25d/lay_plugin/D25View.ui b/src/plugins/tools/view_25d/lay_plugin/D25View.ui new file mode 100644 index 000000000..f28b5eddf --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/D25View.ui @@ -0,0 +1,59 @@ + + + D25View + + + + 0 + 0 + 576 + 649 + + + + 2.5d View + + + + 6 + + + 9 + + + 9 + + + 9 + + + 9 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + lay::D25View + QOpenGLWidget +
layD25View.h
+
+
+ + buttonBox + + + +
diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc new file mode 100644 index 000000000..1883bdf36 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -0,0 +1,112 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layD25View.h" +#include "layDispatcher.h" + +#include "layPlugin.h" + +namespace lay +{ + +class D25Plugin + : public lay::Plugin +{ +public: + D25Plugin (Plugin *parent, lay::LayoutView *view) + : lay::Plugin (parent), mp_view (view) + { + mp_dialog = new lay::D25View (0); + } + + ~D25Plugin () + { + delete mp_dialog; + mp_dialog = 0; + } + + void menu_activated (const std::string &symbol) + { + if (symbol == "lay::d25_view") { + + if (mp_dialog->exec_dialog (mp_view)) { + + // ... implementation is in layD25ToolDialog.cc ... + + } + + } + } + +private: + lay::LayoutView *mp_view; + lay::D25ToolDialog *mp_dialog; +}; + +class D25PluginDeclaration + : public lay::PluginDeclaration +{ +public: + D25PluginDeclaration () + { + // .. nothing yet .. + } + + virtual void get_options (std::vector < std::pair > &options) const + { + // .. nothing yet .. + } + + virtual lay::ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const + { + // .. nothing yet .. + return 0; + } + + virtual void get_menu_entries (std::vector &menu_entries) const + { + lay::PluginDeclaration::get_menu_entries (menu_entries); + menu_entries.push_back (lay::menu_item ("lay::d25_view", "d25_view:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("2.5d View")))); + } + + virtual bool configure (const std::string & /*name*/, const std::string & /*value*/) + { + return false; + } + + virtual void config_finalize () + { + // .. nothing yet .. + } + + lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutView *view) const + { + return new D25Plugin (root, view); + } +}; + +static tl::RegisteredClass config_decl (new lay::D25PluginDeclaration (), 3000, "lay::D25Plugin"); + +} + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc new file mode 100644 index 000000000..cd2c5518b --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -0,0 +1,65 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layD25View.h" + +#include "ui_D25View.h" + +#include + +namespace lay +{ + +D25View::D25View (QWidget *parent) + : QDialog (parent), mp_view (0) +{ + mp_ui = new Ui::D25View (); + mp_ui->setupUi (this); + + // @@@ +} + +D25View::~D25View () +{ + delete mp_ui; + mp_ui = 0; +} + +int +D25View::exec_dialog (lay::LayoutView *view) +{ + mp_view.reset (view); + + // @@@ + + return QDialog::exec (); +} + +void +D25View::accept () +{ + // @@@ +} + +} + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.h b/src/plugins/tools/view_25d/lay_plugin/layD25View.h new file mode 100644 index 000000000..78526bd36 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.h @@ -0,0 +1,65 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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_layD25View +#define HDR_layD25View + +#include + +#include "tlObject.h" + +namespace Ui +{ + class D25View; +} + +namespace lay +{ + class LayoutView; +} + +namespace lay +{ + +class D25View + : public QDialog +{ +Q_OBJECT + +public: + D25View (QWidget *parent); + ~D25View (); + + int exec_dialog (lay::LayoutView *view); + +protected: + void accept (); + +private: + Ui::D25View *mp_ui; + tl::weak_ptr mp_view; +}; + +} + +#endif + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc new file mode 100644 index 000000000..2cfffbebb --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -0,0 +1,41 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layD25ViewWidget.h" + +namespace lay +{ + +D25ViewWidget::D25ViewWidget (QWidget *parent) + : QOpenGLWidget (parent), mp_view (0) +{ + // @@@ +} + +D25View::~D25View () +{ + // @@@ +} + +} + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h new file mode 100644 index 000000000..428f466f3 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -0,0 +1,44 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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_layD25ViewWidget +#define HDR_layD25ViewWidget + +#include + +namespace lay +{ + +class D25ViewWidget + : public QOpenGLWidget +{ +Q_OBJECT + +public: + D25ViewWidget (QWidget *parent); + ~D25ViewWidget (); +}; + +} + +#endif + diff --git a/src/plugins/tools/view_25d/lay_plugin/layXORPlugin.cc b/src/plugins/tools/view_25d/lay_plugin/layXORPlugin.cc new file mode 100644 index 000000000..f5bd4895e --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layXORPlugin.cc @@ -0,0 +1,122 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layXORToolDialog.h" +#include "layDispatcher.h" + +#include "layPlugin.h" + +namespace lay +{ + +class XORPlugin + : public lay::Plugin +{ +public: + XORPlugin (Plugin *parent, lay::LayoutView *view) + : lay::Plugin (parent), mp_view (view) + { + mp_dialog = new lay::XORToolDialog (0); + } + + ~XORPlugin () + { + delete mp_dialog; + mp_dialog = 0; + } + + void menu_activated (const std::string &symbol) + { + if (symbol == "lay::xor_tool") { + + if (mp_dialog->exec_dialog (mp_view)) { + + // ... implementation is in layXORToolDialog.cc ... + + } + + } + } + +private: + lay::LayoutView *mp_view; + lay::XORToolDialog *mp_dialog; +}; + +class XORPluginDeclaration + : public lay::PluginDeclaration +{ +public: + XORPluginDeclaration () + { + // .. nothing yet .. + } + + virtual void get_options (std::vector < std::pair > &options) const + { + options.push_back (std::pair (cfg_xor_input_mode, "all")); + options.push_back (std::pair (cfg_xor_output_mode, "rdb")); + options.push_back (std::pair (cfg_xor_nworkers, "1")); + options.push_back (std::pair (cfg_xor_layer_offset, "")); + options.push_back (std::pair (cfg_xor_axorb, "true")); + options.push_back (std::pair (cfg_xor_anotb, "false")); + options.push_back (std::pair (cfg_xor_bnota, "false")); + options.push_back (std::pair (cfg_xor_summarize, "false")); + options.push_back (std::pair (cfg_xor_tolerances, "")); + options.push_back (std::pair (cfg_xor_tiling, "")); + options.push_back (std::pair (cfg_xor_region_mode, "all")); + } + + virtual lay::ConfigPage *config_page (QWidget * /*parent*/, std::string & /*title*/) const + { + // .. nothing yet .. + return 0; + } + + virtual void get_menu_entries (std::vector &menu_entries) const + { + lay::PluginDeclaration::get_menu_entries (menu_entries); + menu_entries.push_back (lay::menu_item ("lay::xor_tool", "xor_tool:edit", "tools_menu.post_verification_group", tl::to_string (QObject::tr ("XOR Tool")))); + } + + virtual bool configure (const std::string & /*name*/, const std::string & /*value*/) + { + return false; + } + + virtual void config_finalize () + { + // .. nothing yet .. + } + + lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutView *view) const + { + return new XORPlugin (root, view); + } +}; + +static tl::RegisteredClass config_decl (new lay::XORPluginDeclaration (), 3000, "lay::XORPlugin"); + +} + diff --git a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro new file mode 100644 index 000000000..5b3d29d47 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro @@ -0,0 +1,21 @@ + +TARGET = xor_ui +DESTDIR = $$OUT_PWD/../../../../lay_plugins + +include($$PWD/../../../lay_plugin.pri) + +INCLUDEPATH += $$RDB_INC $$ANT_INC +DEPENDPATH += $$RDB_INC $$ANT_INC +LIBS += -L$$DESTDIR/.. -lklayout_rdb -lklayout_ant + +HEADERS = \ + layD25View.h \ + layD25ViewWidget.h \ + +SOURCES = \ + layD25View.cc \ + layD25ViewWidget.cc \ + layD25Plugin.cc + +FORMS = \ + D25View.ui \ diff --git a/src/plugins/tools/view_25d/view_25d.pro b/src/plugins/tools/view_25d/view_25d.pro new file mode 100644 index 000000000..f1dd4434b --- /dev/null +++ b/src/plugins/tools/view_25d/view_25d.pro @@ -0,0 +1,6 @@ + +TEMPLATE = subdirs + +!equals(HAVE_QT, "0") { + SUBDIRS = lay_plugin +} From 1e2601d154c4648b056a6202e75ad7c1e60f4f0b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 6 Apr 2020 23:22:22 +0200 Subject: [PATCH 02/27] Fixed some build errors --- src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc | 2 +- src/plugins/tools/view_25d/lay_plugin/layD25View.cc | 3 ++- src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index 1883bdf36..d409321b2 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -61,7 +61,7 @@ public: private: lay::LayoutView *mp_view; - lay::D25ToolDialog *mp_dialog; + lay::D25View *mp_dialog; }; class D25PluginDeclaration diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index cd2c5518b..18a4f2681 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -22,6 +22,7 @@ #include "layD25View.h" +#include "layLayoutView.h" #include "ui_D25View.h" @@ -31,7 +32,7 @@ namespace lay { D25View::D25View (QWidget *parent) - : QDialog (parent), mp_view (0) + : QDialog (parent) { mp_ui = new Ui::D25View (); mp_ui->setupUi (this); diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 2cfffbebb..c3fadabb0 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -27,12 +27,12 @@ namespace lay { D25ViewWidget::D25ViewWidget (QWidget *parent) - : QOpenGLWidget (parent), mp_view (0) + : QOpenGLWidget (parent) { // @@@ } -D25View::~D25View () +D25ViewWidget::~D25ViewWidget () { // @@@ } From b7eb150f0320b70029c455822fe38eef6f158c0b Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 6 Apr 2020 23:52:51 +0200 Subject: [PATCH 03/27] Fixed some bugs. --- .../tools/view_25d/lay_plugin/D25View.ui | 27 +++++++++++++++---- .../tools/view_25d/lay_plugin/layD25Plugin.cc | 2 +- .../tools/view_25d/lay_plugin/lay_plugin.pro | 2 +- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/D25View.ui b/src/plugins/tools/view_25d/lay_plugin/D25View.ui index f28b5eddf..52ea2c8c4 100644 --- a/src/plugins/tools/view_25d/lay_plugin/D25View.ui +++ b/src/plugins/tools/view_25d/lay_plugin/D25View.ui @@ -30,7 +30,7 @@ 9 - + @@ -38,7 +38,7 @@ Qt::Horizontal - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + QDialogButtonBox::Close @@ -46,14 +46,31 @@ - lay::D25View + lay::D25ViewWidget QOpenGLWidget -
layD25View.h
+
layD25ViewWidget.h
buttonBox - + + + buttonBox + rejected() + D25View + accept() + + + 530 + 626 + + + 443 + 643 + + + + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index d409321b2..12cd9d03c 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -73,7 +73,7 @@ public: // .. nothing yet .. } - virtual void get_options (std::vector < std::pair > &options) const + virtual void get_options (std::vector < std::pair > & /*options*/) const { // .. nothing yet .. } diff --git a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro index 5b3d29d47..062d2eed4 100644 --- a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro +++ b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro @@ -1,5 +1,5 @@ -TARGET = xor_ui +TARGET = d25_ui DESTDIR = $$OUT_PWD/../../../../lay_plugins include($$PWD/../../../lay_plugin.pri) From a4c2cd34cfeb9085dc7e34f1d2f6d1a5662fd780 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 6 Apr 2020 23:55:30 +0200 Subject: [PATCH 04/27] Fixed some bugs. --- src/plugins/tools/view_25d/lay_plugin/layD25View.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index 18a4f2681..7a194252c 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -59,6 +59,7 @@ D25View::exec_dialog (lay::LayoutView *view) void D25View::accept () { + QDialog::accept (); // @@@ } From 7472bd4955a68f54f65ba67a1a459b6d2bcc8215 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 10 Apr 2020 22:40:53 +0200 Subject: [PATCH 05/27] WIP: experiments on OpenGL view. --- .../tools/view_25d/lay_plugin/layD25Plugin.cc | 2 + .../view_25d/lay_plugin/layD25ViewWidget.cc | 331 +++++++++++++++++- .../view_25d/lay_plugin/layD25ViewWidget.h | 34 +- 3 files changed, 363 insertions(+), 4 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index 12cd9d03c..7f92fcd62 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -27,6 +27,8 @@ #include "layPlugin.h" +#include + namespace lay { diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index c3fadabb0..e6d572686 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -22,19 +22,344 @@ #include "layD25ViewWidget.h" +#include "tlException.h" + +#include +#include + +#include "math.h" namespace lay { D25ViewWidget::D25ViewWidget (QWidget *parent) - : QOpenGLWidget (parent) + : QOpenGLWidget (parent), + m_program (0), m_dragging (false), m_rotating (false), m_cam_azimuth (0.0), m_cam_elevation (0.0) { - // @@@ + QSurfaceFormat format; + format.setDepthBufferSize (24); + format.setSamples (4); // more -> widget extends beyond boundary! + setFormat (format); + + m_cam_position = QVector3D (0.0, 0.0, 3.0); // @@@ } D25ViewWidget::~D25ViewWidget () { - // @@@ + // Make sure the context is current and then explicitly + // destroy all underlying OpenGL resources. + makeCurrent(); + + delete m_program; + + doneCurrent(); +} + +void +D25ViewWidget::initializeGL () +{ + QOpenGLFunctions::initializeOpenGLFunctions(); + + glEnable (GL_DEPTH_TEST); + glEnable (GL_BLEND); + // @@@ dark background + // glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // @@@ white background + glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + + static const char *vertexShaderSource = + "attribute highp vec4 posAttr;\n" + "uniform highp mat4 matrix;\n" + "attribute lowp vec4 colAttr;\n" + "varying lowp vec4 col;\n" + "void main() {\n" + " col = colAttr;\n" + " gl_Position = matrix * posAttr;\n" + "}\n"; + + static const char *fragmentShaderSource = + "varying lowp vec4 col;\n" + "void main() {\n" + " gl_FragColor = col;\n" + "}\n"; + + m_program = new QOpenGLShaderProgram (this); + if (! m_program->addShaderFromSourceCode (QOpenGLShader::Vertex, vertexShaderSource)) { + throw tl::Exception (std::string ("Vertex shader compilation failed:\n") + tl::to_string (m_program->log ())); + } + if (! m_program->addShaderFromSourceCode (QOpenGLShader::Fragment, fragmentShaderSource)) { + throw tl::Exception (std::string ("Fragment shader compilation failed:\n") + tl::to_string (m_program->log ())); + } + if (! m_program->link ()) { + throw tl::Exception (std::string ("Linking failed:\n") + tl::to_string (m_program->log ())); + } + + m_posAttr = m_program->attributeLocation ("posAttr"); + m_colAttr = m_program->attributeLocation ("colAttr"); + m_matrixUniform = m_program->uniformLocation ("matrix"); +} + +static QVector3D cam_direction (double azimuth, double elevation) +{ + // positive azimuth: camera looks left + // positive elevation: camera looks up + double y = sin (elevation * M_PI / 180.0); + double r = cos (elevation * M_PI / 180.0); + double x = r * sin (azimuth * M_PI / 180.0); + double z = r * cos (azimuth * M_PI / 180.0); + return QVector3D (x, y, -z); +} + +void +D25ViewWidget::wheelEvent (QWheelEvent *event) +{ + double cal = 0.6; + + int dx = event->pos ().x () - width () / 2; + int dy = -(event->pos ().y () - height () / 2); + + double da = atan (dx * cal * 2.0 / height ()) * 180 / M_PI; + double de = atan (dy * cal * 2.0 / height ()) * 180 / M_PI; + + m_cam_position += (event->angleDelta ().y () * (1.0 / (45 * 8))) * cam_direction (m_cam_azimuth + da, m_cam_elevation + de); + + update_cam_trans (); +} + +void +D25ViewWidget::mousePressEvent (QMouseEvent *event) +{ + m_dragging = m_rotating = false; + if (event->button () == Qt::MidButton) { + m_dragging = true; + } else if (event->button () == Qt::LeftButton) { + m_rotating = true; + } + + m_start_pos = event->pos (); + m_start_cam_position = m_cam_position; + m_start_cam_azimuth = m_cam_azimuth; + m_start_cam_elevation = m_cam_elevation; +} + +void +D25ViewWidget::mouseReleaseEvent (QMouseEvent *event) +{ + m_dragging = false; +} + +void +D25ViewWidget::mouseMoveEvent (QMouseEvent *event) +{ + double focus_dist = 4.0; // 4 times focal length + + if (m_dragging) { + + // for the chosen perspective transformation: + double cal = 0.6 * focus_dist; + + QPoint d = event->pos () - m_start_pos; + double f = cal * 2.0 / double (height ()); + double dx = d.x () * f; + double dy = -d.y () * f; + + QVector3D xv (cos (m_start_cam_azimuth * M_PI / 180.0), 0.0, -sin (m_start_cam_azimuth * M_PI / 180.0)); + double re = sin (m_start_cam_elevation * M_PI / 180.0); + QVector3D yv (-re * xv.z (), cos (m_start_cam_elevation * M_PI / 180.0), re * xv.x ()); + QVector3D drag = xv * dx + yv * dy; + + // "-drag" because we're not dragging the camera, we're dragging the scene + m_cam_position = m_start_cam_position - drag; + + update_cam_trans (); + + } else if (m_rotating) { + + QPoint d = event->pos () - m_start_pos; + + double ax = atan (d.x () / (0.5 * height ())) * 180 / M_PI; + double ay = atan (-d.y () / (0.5 * height ())) * 180 / M_PI; + + m_cam_elevation = m_start_cam_elevation + ay; + m_cam_azimuth = m_start_cam_azimuth + ax; + + m_cam_position = (cam_direction (m_cam_azimuth, m_cam_elevation) * -focus_dist) + cam_direction (m_start_cam_azimuth, m_start_cam_elevation) * focus_dist + m_start_cam_position; + + update_cam_trans (); + + } +} + +void +D25ViewWidget::update_cam_trans () +{ +printf("@@@ e=%g a=%g x,y,z=%g,%g,%g\n", m_cam_elevation, m_cam_azimuth, m_cam_position.x(), m_cam_position.y(), m_cam_position.z()); fflush(stdout); + QMatrix4x4 t; + + // third: elevation + t.rotate (-m_cam_elevation, 1.0, 0.0, 0.0); + + // second: azimuth + t.rotate (m_cam_azimuth, 0.0, 1.0, 0.0); + + // first: translate the origin into the cam's position + t.translate (-m_cam_position); + + m_cam_trans = t; + + update (); +} + +void +D25ViewWidget::paintGL () +{ + const qreal retinaScale = devicePixelRatio (); + glViewport (0, 0, width () * retinaScale, height () * retinaScale); + + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glClearColor (1.0, 1.0, 1.0, 1.0); + + m_program->bind (); + + QMatrix4x4 matrix; + matrix.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); + matrix *= m_cam_trans; + + m_program->setUniformValue (m_matrixUniform, matrix); + + glEnableVertexAttribArray (m_posAttr); + glEnableVertexAttribArray (m_colAttr); + + GLfloat vertices[] = { + 0.0f, 0.707f, -1.0, + -0.5f, -0.5f, -1.0, + 0.5f, -0.5f, -1.0, + -0.6 + 0.0f, 0.0707f, -1.0, + -0.6 + -0.05f, -0.05f, -1.0, + -0.6 + 0.05f, -0.05f, -1.0, + 0.0f, 0.707f, -1.5, + -0.5f, -0.5f, -1.5, + 0.5f, -0.5f, -1.5, + 0.0f, 0.707f, -2.0, + -0.5f, -0.5f, -2.0, + 0.5f, -0.5f, -2.0 + }; + + GLfloat colors[] = { + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f + }; + + glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, vertices); + glVertexAttribPointer (m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors); + + glDrawArrays (GL_TRIANGLES, 0, 12); + + GLfloat plane_vertices[] = { + -1.05, 0.0, -2.05, -1.05, 0.0, 0.05, 1.05, 0.0, 0.05, + -1.05, 0.0, -2.05, 1.05, 0.0, 0.05, 1.05, 0.0, -2.05 + }; + + GLfloat plane_colors[] = { + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f + }; + + glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, plane_vertices); + glVertexAttribPointer (m_colAttr, 4, GL_FLOAT, GL_FALSE, 0, plane_colors); + + glDrawArrays (GL_TRIANGLES, 0, 6); + + GLfloat gridline_vertices[] = { + -1.0, 0.0, -2.0, -1.0, 0.0, 0.0, + -0.75, 0.0, -2.0, -0.75, 0.0, 0.0, + -0.5, 0.0, -2.0, -0.5, 0.0, 0.0, + -0.25, 0.0, -2.0, -0.25, 0.0, 0.0, + 0.0, 0.0, -2.0, 0.0, 0.0, 0.0, + 0.25, 0.0, -2.0, 0.25, 0.0, 0.0, + 0.5, 0.0, -2.0, 0.5, 0.0, 0.0, + 0.75, 0.0, -2.0, 0.75, 0.0, 0.0, + 1.0, 0.0, -2.0, 1.0, 0.0, 0.0, + 1.0, 0.0, -2.0, -1.0, 0.0, -2.0, + 1.0, 0.0, -1.75, -1.0, 0.0, -1.75, + 1.0, 0.0, -1.5 , -1.0, 0.0, -1.5, + 1.0, 0.0, -1.25, -1.0, 0.0, -1.25, + 1.0, 0.0, -1.0, -1.0, 0.0, -1.0, + 1.0, 0.0, -0.75, -1.0, 0.0, -0.75, + 1.0, 0.0, -0.5 , -1.0, 0.0, -0.5, + 1.0, 0.0, -0.25, -1.0, 0.0, -0.25, + 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 + }; + + GLfloat gridline_colors[] = { + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f, + 1.0f, 1.0f, 1.0f, 0.2f + }; + + glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, gridline_vertices); + glVertexAttribPointer (m_colAttr, 4, GL_FLOAT, GL_FALSE, 0, gridline_colors); + + glLineWidth (2.0); + glDrawArrays (GL_LINES, 0, 36); + + glDisableVertexAttribArray (m_posAttr); + glDisableVertexAttribArray (m_colAttr); + + m_program->release (); +} + +void +D25ViewWidget::resizeGL (int /*w*/, int /*h*/) +{ + update_cam_trans (); } } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index 428f466f3..aec8bbb33 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -24,18 +24,50 @@ #define HDR_layD25ViewWidget #include +#include +#include +#include +#include +#include +#include +#include namespace lay { class D25ViewWidget - : public QOpenGLWidget + : public QOpenGLWidget, + private QOpenGLFunctions { Q_OBJECT public: D25ViewWidget (QWidget *parent); ~D25ViewWidget (); + + void wheelEvent (QWheelEvent *event); + void mousePressEvent (QMouseEvent *event); + void mouseReleaseEvent (QMouseEvent *event); + void mouseMoveEvent (QMouseEvent *event); + +private: + QOpenGLShaderProgram *m_program; + GLuint m_posAttr; + GLuint m_colAttr; + GLuint m_matrixUniform; + QMatrix4x4 m_cam_trans; + bool m_dragging, m_rotating; + QVector3D m_cam_position; + double m_cam_azimuth, m_cam_elevation; + QPoint m_start_pos; + QVector3D m_start_cam_position; + double m_start_cam_azimuth, m_start_cam_elevation; + + void initializeGL (); + void paintGL (); + void resizeGL (int w, int h); + + void update_cam_trans (); }; } From 731dfffe1e03bece968086cab003d6c8294b8bb2 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 11 Apr 2020 11:21:36 +0200 Subject: [PATCH 06/27] WIP --- .../view_25d/lay_plugin/layD25MemChunks.cc | 0 .../view_25d/lay_plugin/layD25MemChunks.h | 0 .../unit_tests/layD25MemChunksTests.cc | 486 ++++++++++++++++++ .../tools/view_25d/unit_tests/unit_tests.pro | 19 + 4 files changed, 505 insertions(+) create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h create mode 100644 src/plugins/tools/view_25d/unit_tests/layD25MemChunksTests.cc create mode 100644 src/plugins/tools/view_25d/unit_tests/unit_tests.pro diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc new file mode 100644 index 000000000..e69de29bb diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h new file mode 100644 index 000000000..e69de29bb diff --git a/src/plugins/tools/view_25d/unit_tests/layD25MemChunksTests.cc b/src/plugins/tools/view_25d/unit_tests/layD25MemChunksTests.cc new file mode 100644 index 000000000..ab34661b6 --- /dev/null +++ b/src/plugins/tools/view_25d/unit_tests/layD25MemChunksTests.cc @@ -0,0 +1,486 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "dbDXFReader.h" +#include "dbTestSupport.h" +#include "tlUnitTest.h" + +#include + +static db::LayerMap string2lm (const char *map) +{ + db::LayerMap lm; + unsigned int ln = 0; + tl::Extractor ex (map); + while (! ex.at_end ()) { + std::string n; + int l; + ex.read_word_or_quoted (n); + ex.test (":"); + ex.read (l); + ex.test (","); + lm.map (n, ln++, db::LayerProperties (l, 0)); + } + return lm; +} + +static void do_run_test (tl::TestBase *_this, const std::string &fn, const std::string &fn_au, const db::DXFReaderOptions &opt, bool as_oas) +{ + db::LoadLayoutOptions options; + options.set_options (new db::DXFReaderOptions (opt)); + + db::Layout layout; + + { + tl::InputStream stream (fn); + db::Reader reader (stream); + reader.read (layout, options); + } + + db::compare_layouts (_this, layout, fn_au, as_oas ? db::WriteOAS : db::WriteGDS2, 1); +} + +static void run_test (tl::TestBase *_this, const char *file, const char *file_au, const db::DXFReaderOptions &opt = db::DXFReaderOptions (), bool as_oas = false) +{ + std::string fn = tl::testsrc_private () + "/testdata/dxf/" + file; + std::string fn_au = tl::testsrc_private () + std::string ("/testdata/dxf/") + file_au; + + do_run_test (_this, fn, fn_au, opt, as_oas); +} + +static void run_test_public (tl::TestBase *_this, const char *file, const char *file_au, const db::DXFReaderOptions &opt = db::DXFReaderOptions (), bool as_oas = false) +{ + std::string fn = tl::testsrc () + "/testdata/dxf/" + file; + std::string fn_au = tl::testsrc () + std::string ("/testdata/dxf/") + file_au; + + do_run_test (_this, fn, fn_au, opt, as_oas); +} + +TEST(KeepLN1) +{ + db::DXFReaderOptions opt; + run_test_public (_this, "keep_ln.dxf.gz", "keep_ln1_au.oas.gz", opt, true /*because of layer names*/); +} + +TEST(KeepLN2) +{ + db::DXFReaderOptions opt; + opt.keep_layer_names = true; + run_test_public (_this, "keep_ln.dxf.gz", "keep_ln2_au.oas.gz", opt, true /*because of layer names*/); +} + +TEST(1a) +{ + run_test (_this, "t1.dxf.gz", "t1a_au.gds.gz"); +} + +TEST(1b) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.01; + opt.unit = 5.0; + run_test (_this, "t1.dxf.gz", "t1b_au.gds.gz", opt); +} + +TEST(2) +{ + run_test (_this, "t2.dxf.gz", "t2_au.gds.gz"); +} + +TEST(3) +{ + run_test (_this, "t3.dxf.gz", "t3_au.gds.gz"); +} + +TEST(4) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("Metal:1,Metal2:5"); + opt.create_other_layers = true; + run_test (_this, "t4.dxf.gz", "t4_au.gds.gz", opt); +} + +TEST(5) +{ + run_test (_this, "t5.dxf.gz", "t5_au.gds.gz"); +} + +TEST(6) +{ + run_test (_this, "t6.dxf.gz", "t6_au.gds.gz"); +} + +TEST(7) +{ + run_test (_this, "t7.dxf.gz", "t7_au.gds.gz"); +} + +TEST(8) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("Metal:4,Kommentare:3,Bemassung:2"); + opt.create_other_layers = true; + run_test (_this, "t8.dxf.gz", "t8_au.gds.gz", opt); +} + +TEST(9) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("Bemassung:2,Metal:5,Kommentare:4"); + opt.create_other_layers = true; + run_test (_this, "t9.dxf.gz", "t9_au.gds.gz", opt); +} + +TEST(10) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("METAL:1,KOMMENTARE:4"); + opt.create_other_layers = true; + run_test (_this, "t10.dxf.gz", "t10_au.gds.gz", opt); +} + +TEST(11) +{ + run_test (_this, "t11.dxf.gz", "t11_au.gds.gz"); +} + +TEST(12) +{ + run_test (_this, "t12.dxf.gz", "t12_au.gds.gz"); +} + +TEST(14) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("'A11-STRUKTUR__E_TYP_':10,A21_NITRID:11,'B11-KONTAKT':9,'B11-STRUKTUR':3,HELLFELD:7,MASKE:5,NORM_MIN_MAX_WAFER:6,RASTER:2,_BEGRENZUNG_A11_A21_A31_B1:8"); + opt.create_other_layers = true; + run_test (_this, "t14.dxf.gz", "t14_au.gds.gz", opt); +} + +TEST(15) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20"); + opt.create_other_layers = true; + run_test (_this, "t15.dxf.gz", "t15_au.gds.gz", opt); +} + +TEST(16) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20"); + opt.create_other_layers = true; + run_test (_this, "t16.dxf.gz", "t16_au.gds.gz", opt); +} + +TEST(17) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20"); + opt.create_other_layers = true; + run_test (_this, "t17.dxf.gz", "t17_au.gds.gz", opt); +} + +TEST(18) +{ + run_test (_this, "t18.dxf.gz", "t18_au.gds.gz"); +} + +TEST(19) +{ + run_test (_this, "t19.dxf.gz", "t19_au.gds.gz"); +} + +TEST(20) +{ + run_test (_this, "t20.dxf.gz", "t20_au.gds.gz"); +} + +TEST(21) +{ + run_test (_this, "t21.dxf.gz", "t21_au.gds.gz"); +} + +TEST(22) +{ + run_test (_this, "t22.dxf.gz", "t22_au.gds.gz"); +} + +TEST(23a) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 0; + opt.circle_points = 10; + run_test (_this, "t23.dxf.gz", "t23a_au.gds.gz", opt); +} + +TEST(23b) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 1; + opt.circle_points = 10; + run_test (_this, "t23.dxf.gz", "t23b_au.gds.gz", opt); +} + +TEST(23c) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 2; + opt.circle_points = 10; + run_test (_this, "t23.dxf.gz", "t23c_au.gds.gz", opt); +} + +TEST(23d) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 3; + opt.circle_points = 10; + run_test (_this, "t23.dxf.gz", "t23d_au.gds.gz", opt); +} + +TEST(23e) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 4; + opt.circle_points = 10; + run_test (_this, "t23.dxf.gz", "t23e_au.gds.gz", opt); +} + +TEST(26a) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 0; + opt.circle_points = 100; + run_test (_this, "t26.dxf.gz", "t26a_au.gds.gz", opt); +} + +TEST(26b) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 1; + opt.circle_points = 100; + run_test (_this, "t26.dxf.gz", "t26b_au.gds.gz", opt); +} + +TEST(26c) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 2; + opt.circle_points = 100; + run_test (_this, "t26.dxf.gz", "t26c_au.gds.gz", opt); +} + +TEST(26d) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 3; + opt.circle_points = 100; + run_test (_this, "t26.dxf.gz", "t26d_au.gds.gz", opt); +} + +TEST(26e) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 4; + opt.circle_points = 100; + run_test (_this, "t26.dxf.gz", "t26e_au.gds.gz", opt); +} + +TEST(27a) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 0; + opt.circle_points = 10; + run_test (_this, "t27.dxf.gz", "t27a_au.gds.gz", opt); +} + +TEST(27b) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 1; + opt.circle_points = 10; + run_test (_this, "t27.dxf.gz", "t27b_au.gds.gz", opt); +} + +TEST(27c) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 2; + opt.circle_points = 10; + run_test (_this, "t27.dxf.gz", "t27c_au.gds.gz", opt); +} + +TEST(27d) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 3; + opt.circle_points = 10; + run_test (_this, "t27.dxf.gz", "t27d_au.gds.gz", opt); +} + +TEST(27e) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 4; + opt.circle_points = 10; + run_test (_this, "t27.dxf.gz", "t27e_au.gds.gz", opt); +} + +TEST(28) +{ + run_test (_this, "t28.dxf.gz", "t28_au.gds.gz"); +} + +TEST(29) +{ + run_test (_this, "t29.dxf.gz", "t29_au.gds.gz"); +} + +TEST(29a) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 4; + opt.circle_points = 1000; + opt.circle_accuracy = 1; + run_test (_this, "t29.dxf.gz", "t29a_au.gds.gz", opt); +} + +TEST(29b) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 4; + opt.circle_points = 1000; + opt.circle_accuracy = 0.1; + run_test (_this, "t29.dxf.gz", "t29b_au.gds.gz", opt); +} + +TEST(29c) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 4; + opt.circle_points = 1000; + opt.circle_accuracy = 0.01; + run_test (_this, "t29.dxf.gz", "t29c_au.gds.gz", opt); +} + +TEST(29d) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1; + opt.polyline_mode = 4; + opt.circle_points = 1000; + opt.circle_accuracy = 0.001; + run_test (_this, "t29.dxf.gz", "t29d_au.gds.gz", opt); +} + +TEST(30) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1000; + opt.polyline_mode = 4; + opt.circle_points = 1000; + opt.circle_accuracy = 0.001; + run_test (_this, "t30.dxf.gz", "t30d_au.gds.gz", opt); +} + +// accuracy +TEST(31) +{ + db::DXFReaderOptions opt; + opt.dbu = 0.001; + opt.unit = 1000; + + opt.contour_accuracy = 0; + run_test (_this, "t31.dxf.gz", "t31a_au.gds.gz", opt); + + opt.contour_accuracy = 0.005; + run_test (_this, "t31.dxf.gz", "t31b_au.gds.gz", opt); + + opt.contour_accuracy = 0.01; + run_test (_this, "t31.dxf.gz", "t31c_au.gds.gz", opt); + + opt.contour_accuracy = 0.02; + run_test (_this, "t31.dxf.gz", "t31d_au.gds.gz", opt); +} + +// issue #198 +TEST(32) +{ + db::DXFReaderOptions opt; + opt.layer_map = string2lm ("L11D0:1,L12D0:2"); + opt.create_other_layers = false; + opt.polyline_mode = 3; + + opt.contour_accuracy = 0.0; + run_test_public (_this, "round_path.dxf.gz", "t32a_au.gds.gz", opt); + + opt.contour_accuracy = 0.1; + run_test_public (_this, "round_path.dxf.gz", "t32b_au.gds.gz", opt); + + opt.contour_accuracy = 1.0; + run_test_public (_this, "round_path.dxf.gz", "t32c_au.gds.gz", opt); + + opt.polyline_mode = 4; + run_test_public (_this, "round_path.dxf.gz", "t32d_au.gds.gz", opt); + + opt.polyline_mode = 2; + run_test_public (_this, "round_path.dxf.gz", "t32e_au.gds.gz", opt); +} diff --git a/src/plugins/tools/view_25d/unit_tests/unit_tests.pro b/src/plugins/tools/view_25d/unit_tests/unit_tests.pro new file mode 100644 index 000000000..22fd790b2 --- /dev/null +++ b/src/plugins/tools/view_25d/unit_tests/unit_tests.pro @@ -0,0 +1,19 @@ + +DESTDIR_UT = $$OUT_PWD/../../../.. + +TARGET = view_25d_tests + +include($$PWD/../../../../lib_ut.pri) + +SOURCES = \ + layD25MemChunksTests.cc \ + +INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../lay_plugin $$PWD/../../../common +DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../lay_plugin $$PWD/../../../common + +LIBS += -L$$DESTDIR_UT -lklayout_db -lklayout_tl -lklayout_gsi + +PLUGINPATH = $$OUT_PWD/../../../../lay_plugins +QMAKE_RPATHDIR += $$PLUGINPATH + +LIBS += -L$$PLUGINPATH -ld25_ui From b5a51f15d09e9739e077e639272a4e342cca8dc9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 11 Apr 2020 11:21:59 +0200 Subject: [PATCH 07/27] WIP --- .../tools/view_25d/lay_plugin/D25View.ui | 2 +- .../view_25d/lay_plugin/layD25MemChunks.cc | 23 + .../view_25d/lay_plugin/layD25MemChunks.h | 222 ++++++++ .../tools/view_25d/lay_plugin/layD25View.cc | 9 +- .../view_25d/lay_plugin/layD25ViewWidget.cc | 469 ++++++++++++---- .../view_25d/lay_plugin/layD25ViewWidget.h | 35 +- .../tools/view_25d/lay_plugin/lay_plugin.pro | 4 +- .../unit_tests/layD25MemChunksTests.cc | 510 ++---------------- src/plugins/tools/view_25d/view_25d.pro | 2 +- 9 files changed, 699 insertions(+), 577 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/D25View.ui b/src/plugins/tools/view_25d/lay_plugin/D25View.ui index 52ea2c8c4..3e8f0fc83 100644 --- a/src/plugins/tools/view_25d/lay_plugin/D25View.ui +++ b/src/plugins/tools/view_25d/lay_plugin/D25View.ui @@ -30,7 +30,7 @@ 9 - + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc index e69de29bb..c80a2d5a7 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc @@ -0,0 +1,23 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layD25MemChunks.h" diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h index e69de29bb..034aa5377 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h @@ -0,0 +1,222 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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_layD25MemChunks +#define HDR_layD25MemChunks + +#include + +#include "tlObject.h" +#include // for memcpy + +namespace lay +{ + +/** + * @brief Provides a semi-contiguous array of objects + * + * The objects are kept in chunks of ChunkLen items. + * The blocks can be accessed individually. The array can be + * cleared and new items can be added. No insert or delete. + * + * This object is intended to be used for keeping vertex, + * color or point data for OpenGL. + */ +template +class mem_chunks + : public QDialog +{ +public: + + struct chunk { + public: + chunk () + : m_len (0), m_next (0) + { + // .. nothing yet .. + } + + chunk (const chunk &other) + : m_len (0), m_next (0) + { + operator= (other); + } + + chunk &operator= (const chunk &other) + { + if (this != &other) { + memcpy (&m_objects, &other.m_objects, sizeof (m_objects)); + m_len = other.m_len; + } + return *this; + } + + const Obj *front () const { return m_objects; } + size_t size () const { return m_len; } + const chunk *next () const { return m_next; } + + private: + friend class mem_chunks; + + Obj m_objects [ChunkLen]; + size_t m_len; + chunk *m_next; + }; + + class iterator + { + public: + iterator (chunk *ch = 0) + : mp_chunk (ch) + { + // .. nothing yet .. + } + + bool operator== (iterator other) const + { + return mp_chunk == other.mp_chunk; + } + + bool operator!= (iterator other) const + { + return mp_chunk != other.mp_chunk; + } + + const chunk &operator* () const + { + return *mp_chunk; + } + + const chunk *operator-> () const + { + return mp_chunk; + } + + void operator++ () + { + mp_chunk = mp_chunk->next (); + } + + private: + const chunk *mp_chunk; + }; + + /** + * @brief Default constructor + * Creates an empty array + */ + mem_chunks () + : mp_chunks (0), mp_last_chunk (0) + { + // .. nothing yet .. + } + + /** + * @brief Destructor + */ + ~mem_chunks () + { + clear (); + } + + /** + * @brief Copy constructor + */ + mem_chunks (const mem_chunks &other) + : mp_chunks (0), mp_last_chunk (0) + { + operator= (other); + } + + /** + * @brief Assignment + */ + mem_chunks &operator= (const mem_chunks &other) + { + if (this != &other) { + clear (); + const chunk *ch = other.mp_chunks; + while (ch) { + if (! mp_chunks) { + mp_last_chunk = mp_chunks = new chunk (*ch); + } else { + mp_last_chunk->m_next = new chunk (*ch); + mp_last_chunk = mp_last_chunk->m_next; + } + ch = ch->next (); + } + } + + return *this; + } + + /** + * @brief Clears the array + */ + void clear () + { + chunk *ch = mp_chunks; + mp_chunks = 0; + mp_last_chunk = 0; + while (ch) { + chunk *del = ch; + ch = ch->m_next; + delete del; + } + } + + /** + * @brief Adds an element to the array + */ + void add (const Obj &element) + { + if (! mp_last_chunk) { + mp_chunks = mp_last_chunk = new chunk (); + } + + if (mp_last_chunk->m_len >= ChunkLen) { + mp_last_chunk->m_next = new chunk (); + mp_last_chunk = mp_last_chunk->m_next; + } + + mp_last_chunk->m_objects [mp_last_chunk->m_len++] = element; + } + + /** + * @brief begin iterator + */ + iterator begin () const { return iterator (mp_chunks); } + + /** + * @brief end iterator + */ + iterator end () const { return iterator (); } + +private: + chunk *mp_chunks; + chunk *mp_last_chunk; +}; + +} + +#endif + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index 7a194252c..44f905517 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -50,10 +50,13 @@ int D25View::exec_dialog (lay::LayoutView *view) { mp_view.reset (view); + mp_ui->d25_view->attach_view (view); - // @@@ - - return QDialog::exec (); + int ret = QDialog::exec (); + + mp_ui->d25_view->attach_view (0); + + return ret; } void diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index e6d572686..b204800c0 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -22,6 +22,13 @@ #include "layD25ViewWidget.h" +#include "layLayoutView.h" + +#include "dbRecursiveShapeIterator.h" +#include "dbEdgeProcessor.h" +#include "dbPolygonGenerators.h" +#include "dbPolygonTools.h" + #include "tlException.h" #include @@ -32,9 +39,11 @@ namespace lay { +// ------------------------------------------------------------------------------ + D25ViewWidget::D25ViewWidget (QWidget *parent) : QOpenGLWidget (parent), - m_program (0), m_dragging (false), m_rotating (false), m_cam_azimuth (0.0), m_cam_elevation (0.0) + m_shapes_program (0), m_dragging (false), m_rotating (false), m_cam_azimuth (0.0), m_cam_elevation (0.0) { QSurfaceFormat format; format.setDepthBufferSize (24); @@ -50,7 +59,7 @@ D25ViewWidget::~D25ViewWidget () // destroy all underlying OpenGL resources. makeCurrent(); - delete m_program; + delete m_shapes_program; doneCurrent(); } @@ -63,40 +72,110 @@ D25ViewWidget::initializeGL () glEnable (GL_DEPTH_TEST); glEnable (GL_BLEND); // @@@ dark background - // glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // @@@ white background - glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + // @@@ glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); - static const char *vertexShaderSource = - "attribute highp vec4 posAttr;\n" - "uniform highp mat4 matrix;\n" - "attribute lowp vec4 colAttr;\n" - "varying lowp vec4 col;\n" + static const char *shapes_vertex_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "layout (location = 0) in vec4 posAttr;\n" + "\n" + "void main() {\n" + " gl_Position = posAttr;\n" + "}\n"; + + static const char *shapes_geometry_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "\n" + "uniform vec4 color;\n" + "uniform vec3 illum;\n" + "out lowp vec4 vertexColor;\n" + "uniform mat4 matrix;\n" + "layout (triangles) in;\n" + "layout (triangle_strip, max_vertices = 3) out;\n" + "\n" + "void main() {\n" + " vec4 p0 = gl_in[0].gl_Position;\n" + " vec4 p1 = gl_in[1].gl_Position;\n" + " vec4 p2 = gl_in[2].gl_Position;\n" + " vec3 n = cross(p1.xyz - p0.xyz, p2.xyz - p0.xyz);\n" + " vertexColor.rgb = color.rgb * (max(0.0, dot(normalize(n), illum)) * 0.5 + 0.5);\n" + " vertexColor.a = 1.0;\n" + " gl_Position = matrix * p0;\n" + " EmitVertex();\n" + " gl_Position = matrix * p1;\n" + " EmitVertex();\n" + " gl_Position = matrix * p2;\n" + " EmitVertex();\n" + " EndPrimitive();\n" + "}\n"; + + static const char *shapes_fragment_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "in lowp vec4 vertexColor;\n" + "out lowp vec4 fragColor;\n" + "void main() {\n" + " fragColor = vertexColor;\n" + "}\n"; + + m_shapes_program = new QOpenGLShaderProgram (this); + if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Vertex, shapes_vertex_shader_source)) { + throw tl::Exception (std::string ("Shapes vertex shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); + } + if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Geometry, shapes_geometry_shader_source)) { + throw tl::Exception (std::string ("Shapes geometry shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); + } + if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Fragment, shapes_fragment_shader_source)) { + throw tl::Exception (std::string ("Shapes fragment shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); + } + if (! m_shapes_program->link ()) { + throw tl::Exception (std::string ("Shapes shader program linking failed failed:\n") + tl::to_string (m_shapes_program->log ())); + } + + // grid plane shader source + + static const char *gridplan_vertex_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "layout (location = 0) in vec4 posAttr;\n" + "uniform mat4 matrix;\n" + "\n" "void main() {\n" - " col = colAttr;\n" " gl_Position = matrix * posAttr;\n" "}\n"; - static const char *fragmentShaderSource = - "varying lowp vec4 col;\n" + static const char *gridplan_fragment_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "uniform lowp vec4 color;\n" + "out lowp vec4 fragColor;\n" "void main() {\n" - " gl_FragColor = col;\n" + " fragColor = color;\n" "}\n"; - m_program = new QOpenGLShaderProgram (this); - if (! m_program->addShaderFromSourceCode (QOpenGLShader::Vertex, vertexShaderSource)) { - throw tl::Exception (std::string ("Vertex shader compilation failed:\n") + tl::to_string (m_program->log ())); + m_gridplane_program = new QOpenGLShaderProgram (this); + if (! m_gridplane_program->addShaderFromSourceCode (QOpenGLShader::Vertex, gridplan_vertex_shader_source)) { + throw tl::Exception (std::string ("Grid plane vertex shader compilation failed:\n") + tl::to_string (m_gridplane_program->log ())); } - if (! m_program->addShaderFromSourceCode (QOpenGLShader::Fragment, fragmentShaderSource)) { - throw tl::Exception (std::string ("Fragment shader compilation failed:\n") + tl::to_string (m_program->log ())); + if (! m_gridplane_program->addShaderFromSourceCode (QOpenGLShader::Fragment, gridplan_fragment_shader_source)) { + throw tl::Exception (std::string ("Grid plane fragment shader compilation failed:\n") + tl::to_string (m_gridplane_program->log ())); } - if (! m_program->link ()) { - throw tl::Exception (std::string ("Linking failed:\n") + tl::to_string (m_program->log ())); + if (! m_gridplane_program->link ()) { + throw tl::Exception (std::string ("Grid plane shader program linking failed:\n") + tl::to_string (m_gridplane_program->log ())); } - - m_posAttr = m_program->attributeLocation ("posAttr"); - m_colAttr = m_program->attributeLocation ("colAttr"); - m_matrixUniform = m_program->uniformLocation ("matrix"); } static QVector3D cam_direction (double azimuth, double elevation) @@ -143,7 +222,7 @@ D25ViewWidget::mousePressEvent (QMouseEvent *event) } void -D25ViewWidget::mouseReleaseEvent (QMouseEvent *event) +D25ViewWidget::mouseReleaseEvent (QMouseEvent * /*event*/) { m_dragging = false; } @@ -210,6 +289,225 @@ printf("@@@ e=%g a=%g x,y,z=%g,%g,%g\n", m_cam_elevation, m_cam_azimuth, m update (); } +void +D25ViewWidget::attach_view (LayoutView *view) +{ + if (mp_view != view) { + + mp_view = view; + m_layers.clear (); + m_vertex_chunks.clear (); + + if (mp_view) { + prepare_view (); + } + + } +} + +void +D25ViewWidget::prepare_view () +{ + double z = 0.0, dz = 0.2; // @@@ + + for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { + + if (! lp->has_children () && lp->visible (true) && lp->cellview_index () >= 0 && lp->cellview_index () < int (mp_view->cellviews ())) { + + lay::color_t color = lp->fill_color (true); + + m_vertex_chunks.push_back (chunks_type ()); + + LayerInfo info; + // @@@ use alpha? + info.color[0] = (color & 0xff) / 255.0f; + info.color[1] = ((color >> 8) & 0xff) / 255.0f; + info.color[2] = ((color >> 16) & 0xff) / 255.0f; + info.color[3] = 1.0; + info.vertex_chunk = &m_vertex_chunks.back (); + + m_layers.push_back (info); + + const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ()); + render_layout (m_vertex_chunks.back (), cv->layout (), *cv.cell (), (unsigned int) lp->layer_index (), z, z + dz); + + z += dz; // @@@ + + } + + } +} + +void +D25ViewWidget::render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop) +{ + if (poly.hull ().size () > 4) { + + std::vector poly_heap; + + db::split_polygon (poly, poly_heap); + for (std::vector::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) { + render_polygon (chunks, *p, dbu, zstart, zstop); + } + + } else if (poly.hull ().size () >= 3) { + + db::Point pts [4]; + std::copy (poly.hull ().begin (), poly.hull ().end (), &pts [0]); + + // triangle bottom + + chunks.add (pts[0].x () * dbu); + chunks.add (zstart); + chunks.add (pts[0].y () * dbu); + + chunks.add (pts[2].x () * dbu); + chunks.add (zstart); + chunks.add (pts[2].y () * dbu); + + chunks.add (pts[1].x () * dbu); + chunks.add (zstart); + chunks.add (pts[1].y () * dbu); + + // triangle top + + chunks.add (pts[0].x () * dbu); + chunks.add (zstop); + chunks.add (pts[0].y () * dbu); + + chunks.add (pts[1].x () * dbu); + chunks.add (zstop); + chunks.add (pts[1].y () * dbu); + + chunks.add (pts[2].x () * dbu); + chunks.add (zstop); + chunks.add (pts[2].y () * dbu); + + if (poly.hull ().size () == 4) { + + // triangle bottom + + chunks.add (pts[0].x () * dbu); + chunks.add (zstart); + chunks.add (pts[0].y () * dbu); + + chunks.add (pts[3].x () * dbu); + chunks.add (zstart); + chunks.add (pts[3].y () * dbu); + + chunks.add (pts[2].x () * dbu); + chunks.add (zstart); + chunks.add (pts[2].y () * dbu); + + // triangle top + + chunks.add (pts[0].x () * dbu); + chunks.add (zstop); + chunks.add (pts[0].y () * dbu); + + chunks.add (pts[2].x () * dbu); + chunks.add (zstop); + chunks.add (pts[2].y () * dbu); + + chunks.add (pts[3].x () * dbu); + chunks.add (zstop); + chunks.add (pts[3].y () * dbu); + + } + + } +} + +void +D25ViewWidget::render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &edge, double dbu, double zstart, double zstop) +{ + chunks.add (edge.p1 ().x () * dbu); + chunks.add (zstart); + chunks.add (edge.p1 ().y () * dbu); + + chunks.add (edge.p2 ().x () * dbu); + chunks.add (zstop); + chunks.add (edge.p2 ().y () * dbu); + + chunks.add (edge.p1 ().x () * dbu); + chunks.add (zstop); + chunks.add (edge.p1 ().y () * dbu); + + chunks.add (edge.p1 ().x () * dbu); + chunks.add (zstart); + chunks.add (edge.p1 ().y () * dbu); + + chunks.add (edge.p2 ().x () * dbu); + chunks.add (zstart); + chunks.add (edge.p2 ().y () * dbu); + + chunks.add (edge.p2 ().x () * dbu); + chunks.add (zstop); + chunks.add (edge.p2 ().y () * dbu); +} + +void +D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop) +{ + db::EdgeProcessor ep; + std::vector poly_heap; + + // @@@ hidden cells, hierarchy depth ... + db::RecursiveShapeIterator s (layout, cell, layer); + 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 ()); + + if (polygon.holes () == 0 && polygon.hull ().size () <= 4) { + + render_polygon (chunks, polygon, layout.dbu (), zstart, zstop); + + for (db::Polygon::polygon_edge_iterator e = polygon.begin_edge (); ! e.at_end (); ++e) { + render_wall (chunks, *e, layout.dbu (), zstart, zstop); + } + + } else { + + poly_heap.clear (); + ep.clear (); + + ep.insert_sequence (polygon.begin_edge ()); + { + db::PolygonContainer pc (poly_heap); + db::PolygonGenerator out (pc, true /*resolve holes*/, false /*min coherence for splitting*/); + db::SimpleMerge op; + ep.process (out, op); + } + + for (std::vector::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) { + render_polygon (chunks, *p, layout.dbu (), zstart, zstop); + } + + poly_heap.clear (); + ep.clear (); + + ep.insert_sequence (polygon.begin_edge ()); + { + db::PolygonContainer pc (poly_heap); + db::PolygonGenerator out (pc, false /*don't resolve holes*/, false /*min coherence for splitting*/); + db::SimpleMerge op; + ep.process (out, op); + } + + for (std::vector::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) { + for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) { + render_wall (chunks, *e, layout.dbu (), zstart, zstop); + } + } + + } + + } +} + void D25ViewWidget::paintGL () { @@ -217,70 +515,52 @@ D25ViewWidget::paintGL () glViewport (0, 0, width () * retinaScale, height () * retinaScale); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glClearColor (1.0, 1.0, 1.0, 1.0); + // @@@ white background: glClearColor (1.0, 1.0, 1.0, 1.0); - m_program->bind (); + const int positions = 0; + + m_shapes_program->bind (); QMatrix4x4 matrix; matrix.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); matrix *= m_cam_trans; - m_program->setUniformValue (m_matrixUniform, matrix); + m_shapes_program->setUniformValue ("matrix", matrix); + m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); - glEnableVertexAttribArray (m_posAttr); - glEnableVertexAttribArray (m_colAttr); + glEnableVertexAttribArray (positions); - GLfloat vertices[] = { - 0.0f, 0.707f, -1.0, - -0.5f, -0.5f, -1.0, - 0.5f, -0.5f, -1.0, - -0.6 + 0.0f, 0.0707f, -1.0, - -0.6 + -0.05f, -0.05f, -1.0, - -0.6 + 0.05f, -0.05f, -1.0, - 0.0f, 0.707f, -1.5, - -0.5f, -0.5f, -1.5, - 0.5f, -0.5f, -1.5, - 0.0f, 0.707f, -2.0, - -0.5f, -0.5f, -2.0, - 0.5f, -0.5f, -2.0 - }; + for (std::list::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { - GLfloat colors[] = { - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 1.0f, 0.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f - }; + m_shapes_program->setUniformValue ("color", l->color [0], l->color [1], l->color [2], l->color [3]); - glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, vertices); - glVertexAttribPointer (m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors); + for (chunks_type::iterator c = l->vertex_chunk->begin (); c != l->vertex_chunk->end (); ++c) { + glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, c->front ()); + glDrawArrays (GL_TRIANGLES, 0, c->size () / 3); + } - glDrawArrays (GL_TRIANGLES, 0, 12); + } + + glDisableVertexAttribArray (positions); + + m_shapes_program->release (); + + m_gridplane_program->bind (); + + glEnableVertexAttribArray (positions); + + m_gridplane_program->setUniformValue ("matrix", matrix); + + // @@@ GLfloat plane_vertices[] = { -1.05, 0.0, -2.05, -1.05, 0.0, 0.05, 1.05, 0.0, 0.05, -1.05, 0.0, -2.05, 1.05, 0.0, 0.05, 1.05, 0.0, -2.05 }; - GLfloat plane_colors[] = { - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f - }; + m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.2f); - glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, plane_vertices); - glVertexAttribPointer (m_colAttr, 4, GL_FLOAT, GL_FALSE, 0, plane_colors); + glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, plane_vertices); glDrawArrays (GL_TRIANGLES, 0, 6); @@ -305,55 +585,16 @@ D25ViewWidget::paintGL () 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 }; - GLfloat gridline_colors[] = { - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f, - 1.0f, 1.0f, 1.0f, 0.2f - }; + m_shapes_program->setUniformValue ("vertexColor", 1.0, 1.0, 1.0, 0.2f); - glVertexAttribPointer (m_posAttr, 3, GL_FLOAT, GL_FALSE, 0, gridline_vertices); - glVertexAttribPointer (m_colAttr, 4, GL_FLOAT, GL_FALSE, 0, gridline_colors); + glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, gridline_vertices); glLineWidth (2.0); glDrawArrays (GL_LINES, 0, 36); - glDisableVertexAttribArray (m_posAttr); - glDisableVertexAttribArray (m_colAttr); + glDisableVertexAttribArray (positions); - m_program->release (); + m_shapes_program->release (); } void diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index aec8bbb33..63fb4fad5 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -32,9 +32,21 @@ #include #include +#include "dbPolygon.h" + +#include "layD25MemChunks.h" + +namespace db +{ + class Layout; + class Cell; +} + namespace lay { +class LayoutView; + class D25ViewWidget : public QOpenGLWidget, private QOpenGLFunctions @@ -50,11 +62,12 @@ public: void mouseReleaseEvent (QMouseEvent *event); void mouseMoveEvent (QMouseEvent *event); + void attach_view (lay::LayoutView *view); + private: - QOpenGLShaderProgram *m_program; - GLuint m_posAttr; - GLuint m_colAttr; - GLuint m_matrixUniform; + typedef lay::mem_chunks chunks_type; + + QOpenGLShaderProgram *m_shapes_program, *m_gridplane_program; QMatrix4x4 m_cam_trans; bool m_dragging, m_rotating; QVector3D m_cam_position; @@ -62,12 +75,26 @@ private: QPoint m_start_pos; QVector3D m_start_cam_position; double m_start_cam_azimuth, m_start_cam_elevation; + lay::LayoutView *mp_view; + + std::list m_vertex_chunks; + + struct LayerInfo { + const chunks_type *vertex_chunk; + GLfloat color [4]; + }; + + std::list m_layers; void initializeGL (); void paintGL (); void resizeGL (int w, int h); void update_cam_trans (); + void prepare_view (); + void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop); + void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop); + void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop); }; } diff --git a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro index 062d2eed4..1de5fe5b5 100644 --- a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro +++ b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro @@ -11,11 +11,13 @@ LIBS += -L$$DESTDIR/.. -lklayout_rdb -lklayout_ant HEADERS = \ layD25View.h \ layD25ViewWidget.h \ + layD25MemChunks.h SOURCES = \ layD25View.cc \ layD25ViewWidget.cc \ - layD25Plugin.cc + layD25Plugin.cc \ + layD25MemChunks.cc FORMS = \ D25View.ui \ diff --git a/src/plugins/tools/view_25d/unit_tests/layD25MemChunksTests.cc b/src/plugins/tools/view_25d/unit_tests/layD25MemChunksTests.cc index ab34661b6..5482762a0 100644 --- a/src/plugins/tools/view_25d/unit_tests/layD25MemChunksTests.cc +++ b/src/plugins/tools/view_25d/unit_tests/layD25MemChunksTests.cc @@ -21,466 +21,70 @@ */ -#include "dbDXFReader.h" -#include "dbTestSupport.h" +#include "layD25MemChunks.h" #include "tlUnitTest.h" -#include - -static db::LayerMap string2lm (const char *map) +TEST(1_Basic) { - db::LayerMap lm; - unsigned int ln = 0; - tl::Extractor ex (map); - while (! ex.at_end ()) { - std::string n; - int l; - ex.read_word_or_quoted (n); - ex.test (":"); - ex.read (l); - ex.test (","); - lm.map (n, ln++, db::LayerProperties (l, 0)); - } - return lm; + lay::mem_chunks ch; + EXPECT_EQ (ch.begin () == ch.end (), true); + + ch.add (1); + EXPECT_EQ (ch.begin () == ch.end (), false); + EXPECT_EQ (ch.begin ()->size (), size_t (1)); + EXPECT_EQ (ch.begin ()->front () [0], 1); + + ch.add (17); + EXPECT_EQ (ch.begin () == ch.end (), false); + EXPECT_EQ (ch.begin ()->size (), size_t (2)); + EXPECT_EQ (ch.begin ()->front () [0], 1); + EXPECT_EQ (ch.begin ()->front () [1], 17); + + lay::mem_chunks::iterator c = ch.begin (); + EXPECT_EQ (c == ch.end (), false); + ++c; + EXPECT_EQ (c == ch.end (), true); + + ch.add (42); + c = ch.begin (); + EXPECT_EQ (c == ch.end (), false); + EXPECT_EQ (c->size (), size_t (2)); + EXPECT_EQ (c->front () [0], 1); + EXPECT_EQ (c->front () [1], 17); + ++c; + EXPECT_EQ (c == ch.end (), false); + EXPECT_EQ (c->size (), size_t (1)); + EXPECT_EQ (c->front () [0], 42); + ++c; + EXPECT_EQ (c == ch.end (), true); + + ch.clear (); + EXPECT_EQ (ch.begin () == ch.end (), true); } -static void do_run_test (tl::TestBase *_this, const std::string &fn, const std::string &fn_au, const db::DXFReaderOptions &opt, bool as_oas) +TEST(2_Copy) { - db::LoadLayoutOptions options; - options.set_options (new db::DXFReaderOptions (opt)); + lay::mem_chunks ch1; + ch1.add (1); + ch1.add (17); + ch1.add (42); - db::Layout layout; + lay::mem_chunks ch (ch1); - { - tl::InputStream stream (fn); - db::Reader reader (stream); - reader.read (layout, options); - } + lay::mem_chunks::iterator c = ch.begin (); - db::compare_layouts (_this, layout, fn_au, as_oas ? db::WriteOAS : db::WriteGDS2, 1); -} - -static void run_test (tl::TestBase *_this, const char *file, const char *file_au, const db::DXFReaderOptions &opt = db::DXFReaderOptions (), bool as_oas = false) -{ - std::string fn = tl::testsrc_private () + "/testdata/dxf/" + file; - std::string fn_au = tl::testsrc_private () + std::string ("/testdata/dxf/") + file_au; - - do_run_test (_this, fn, fn_au, opt, as_oas); -} - -static void run_test_public (tl::TestBase *_this, const char *file, const char *file_au, const db::DXFReaderOptions &opt = db::DXFReaderOptions (), bool as_oas = false) -{ - std::string fn = tl::testsrc () + "/testdata/dxf/" + file; - std::string fn_au = tl::testsrc () + std::string ("/testdata/dxf/") + file_au; - - do_run_test (_this, fn, fn_au, opt, as_oas); -} - -TEST(KeepLN1) -{ - db::DXFReaderOptions opt; - run_test_public (_this, "keep_ln.dxf.gz", "keep_ln1_au.oas.gz", opt, true /*because of layer names*/); -} - -TEST(KeepLN2) -{ - db::DXFReaderOptions opt; - opt.keep_layer_names = true; - run_test_public (_this, "keep_ln.dxf.gz", "keep_ln2_au.oas.gz", opt, true /*because of layer names*/); -} - -TEST(1a) -{ - run_test (_this, "t1.dxf.gz", "t1a_au.gds.gz"); -} - -TEST(1b) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.01; - opt.unit = 5.0; - run_test (_this, "t1.dxf.gz", "t1b_au.gds.gz", opt); -} - -TEST(2) -{ - run_test (_this, "t2.dxf.gz", "t2_au.gds.gz"); -} - -TEST(3) -{ - run_test (_this, "t3.dxf.gz", "t3_au.gds.gz"); -} - -TEST(4) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("Metal:1,Metal2:5"); - opt.create_other_layers = true; - run_test (_this, "t4.dxf.gz", "t4_au.gds.gz", opt); -} - -TEST(5) -{ - run_test (_this, "t5.dxf.gz", "t5_au.gds.gz"); -} - -TEST(6) -{ - run_test (_this, "t6.dxf.gz", "t6_au.gds.gz"); -} - -TEST(7) -{ - run_test (_this, "t7.dxf.gz", "t7_au.gds.gz"); -} - -TEST(8) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("Metal:4,Kommentare:3,Bemassung:2"); - opt.create_other_layers = true; - run_test (_this, "t8.dxf.gz", "t8_au.gds.gz", opt); -} - -TEST(9) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("Bemassung:2,Metal:5,Kommentare:4"); - opt.create_other_layers = true; - run_test (_this, "t9.dxf.gz", "t9_au.gds.gz", opt); -} - -TEST(10) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("METAL:1,KOMMENTARE:4"); - opt.create_other_layers = true; - run_test (_this, "t10.dxf.gz", "t10_au.gds.gz", opt); -} - -TEST(11) -{ - run_test (_this, "t11.dxf.gz", "t11_au.gds.gz"); -} - -TEST(12) -{ - run_test (_this, "t12.dxf.gz", "t12_au.gds.gz"); -} - -TEST(14) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("'A11-STRUKTUR__E_TYP_':10,A21_NITRID:11,'B11-KONTAKT':9,'B11-STRUKTUR':3,HELLFELD:7,MASKE:5,NORM_MIN_MAX_WAFER:6,RASTER:2,_BEGRENZUNG_A11_A21_A31_B1:8"); - opt.create_other_layers = true; - run_test (_this, "t14.dxf.gz", "t14_au.gds.gz", opt); -} - -TEST(15) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20"); - opt.create_other_layers = true; - run_test (_this, "t15.dxf.gz", "t15_au.gds.gz", opt); -} - -TEST(16) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20"); - opt.create_other_layers = true; - run_test (_this, "t16.dxf.gz", "t16_au.gds.gz", opt); -} - -TEST(17) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("TEXT:4,IGBT:5,Wire:7,Ceramic:11,LAYER_1:14,Diode:18,'DBC TOP Plate':19,'Terminal Position':20"); - opt.create_other_layers = true; - run_test (_this, "t17.dxf.gz", "t17_au.gds.gz", opt); -} - -TEST(18) -{ - run_test (_this, "t18.dxf.gz", "t18_au.gds.gz"); -} - -TEST(19) -{ - run_test (_this, "t19.dxf.gz", "t19_au.gds.gz"); -} - -TEST(20) -{ - run_test (_this, "t20.dxf.gz", "t20_au.gds.gz"); -} - -TEST(21) -{ - run_test (_this, "t21.dxf.gz", "t21_au.gds.gz"); -} - -TEST(22) -{ - run_test (_this, "t22.dxf.gz", "t22_au.gds.gz"); -} - -TEST(23a) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 0; - opt.circle_points = 10; - run_test (_this, "t23.dxf.gz", "t23a_au.gds.gz", opt); -} - -TEST(23b) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 1; - opt.circle_points = 10; - run_test (_this, "t23.dxf.gz", "t23b_au.gds.gz", opt); -} - -TEST(23c) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 2; - opt.circle_points = 10; - run_test (_this, "t23.dxf.gz", "t23c_au.gds.gz", opt); -} - -TEST(23d) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 3; - opt.circle_points = 10; - run_test (_this, "t23.dxf.gz", "t23d_au.gds.gz", opt); -} - -TEST(23e) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 4; - opt.circle_points = 10; - run_test (_this, "t23.dxf.gz", "t23e_au.gds.gz", opt); -} - -TEST(26a) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 0; - opt.circle_points = 100; - run_test (_this, "t26.dxf.gz", "t26a_au.gds.gz", opt); -} - -TEST(26b) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 1; - opt.circle_points = 100; - run_test (_this, "t26.dxf.gz", "t26b_au.gds.gz", opt); -} - -TEST(26c) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 2; - opt.circle_points = 100; - run_test (_this, "t26.dxf.gz", "t26c_au.gds.gz", opt); -} - -TEST(26d) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 3; - opt.circle_points = 100; - run_test (_this, "t26.dxf.gz", "t26d_au.gds.gz", opt); -} - -TEST(26e) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 4; - opt.circle_points = 100; - run_test (_this, "t26.dxf.gz", "t26e_au.gds.gz", opt); -} - -TEST(27a) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 0; - opt.circle_points = 10; - run_test (_this, "t27.dxf.gz", "t27a_au.gds.gz", opt); -} - -TEST(27b) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 1; - opt.circle_points = 10; - run_test (_this, "t27.dxf.gz", "t27b_au.gds.gz", opt); -} - -TEST(27c) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 2; - opt.circle_points = 10; - run_test (_this, "t27.dxf.gz", "t27c_au.gds.gz", opt); -} - -TEST(27d) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 3; - opt.circle_points = 10; - run_test (_this, "t27.dxf.gz", "t27d_au.gds.gz", opt); -} - -TEST(27e) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 4; - opt.circle_points = 10; - run_test (_this, "t27.dxf.gz", "t27e_au.gds.gz", opt); -} - -TEST(28) -{ - run_test (_this, "t28.dxf.gz", "t28_au.gds.gz"); -} - -TEST(29) -{ - run_test (_this, "t29.dxf.gz", "t29_au.gds.gz"); -} - -TEST(29a) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 4; - opt.circle_points = 1000; - opt.circle_accuracy = 1; - run_test (_this, "t29.dxf.gz", "t29a_au.gds.gz", opt); -} - -TEST(29b) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 4; - opt.circle_points = 1000; - opt.circle_accuracy = 0.1; - run_test (_this, "t29.dxf.gz", "t29b_au.gds.gz", opt); -} - -TEST(29c) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 4; - opt.circle_points = 1000; - opt.circle_accuracy = 0.01; - run_test (_this, "t29.dxf.gz", "t29c_au.gds.gz", opt); -} - -TEST(29d) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1; - opt.polyline_mode = 4; - opt.circle_points = 1000; - opt.circle_accuracy = 0.001; - run_test (_this, "t29.dxf.gz", "t29d_au.gds.gz", opt); -} - -TEST(30) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1000; - opt.polyline_mode = 4; - opt.circle_points = 1000; - opt.circle_accuracy = 0.001; - run_test (_this, "t30.dxf.gz", "t30d_au.gds.gz", opt); -} - -// accuracy -TEST(31) -{ - db::DXFReaderOptions opt; - opt.dbu = 0.001; - opt.unit = 1000; - - opt.contour_accuracy = 0; - run_test (_this, "t31.dxf.gz", "t31a_au.gds.gz", opt); - - opt.contour_accuracy = 0.005; - run_test (_this, "t31.dxf.gz", "t31b_au.gds.gz", opt); - - opt.contour_accuracy = 0.01; - run_test (_this, "t31.dxf.gz", "t31c_au.gds.gz", opt); - - opt.contour_accuracy = 0.02; - run_test (_this, "t31.dxf.gz", "t31d_au.gds.gz", opt); -} - -// issue #198 -TEST(32) -{ - db::DXFReaderOptions opt; - opt.layer_map = string2lm ("L11D0:1,L12D0:2"); - opt.create_other_layers = false; - opt.polyline_mode = 3; - - opt.contour_accuracy = 0.0; - run_test_public (_this, "round_path.dxf.gz", "t32a_au.gds.gz", opt); - - opt.contour_accuracy = 0.1; - run_test_public (_this, "round_path.dxf.gz", "t32b_au.gds.gz", opt); - - opt.contour_accuracy = 1.0; - run_test_public (_this, "round_path.dxf.gz", "t32c_au.gds.gz", opt); - - opt.polyline_mode = 4; - run_test_public (_this, "round_path.dxf.gz", "t32d_au.gds.gz", opt); - - opt.polyline_mode = 2; - run_test_public (_this, "round_path.dxf.gz", "t32e_au.gds.gz", opt); + EXPECT_EQ (c == ch.end (), false); + EXPECT_EQ (c->size (), size_t (2)); + EXPECT_EQ (c->front () [0], 1); + EXPECT_EQ (c->front () [1], 17); + ++c; + EXPECT_EQ (c == ch.end (), false); + EXPECT_EQ (c->size (), size_t (1)); + EXPECT_EQ (c->front () [0], 42); + ++c; + EXPECT_EQ (c == ch.end (), true); + + ch1.clear (); + ch = ch1; + EXPECT_EQ (ch.begin () == ch.end (), true); } diff --git a/src/plugins/tools/view_25d/view_25d.pro b/src/plugins/tools/view_25d/view_25d.pro index f1dd4434b..1f10c85ca 100644 --- a/src/plugins/tools/view_25d/view_25d.pro +++ b/src/plugins/tools/view_25d/view_25d.pro @@ -2,5 +2,5 @@ TEMPLATE = subdirs !equals(HAVE_QT, "0") { - SUBDIRS = lay_plugin + SUBDIRS = lay_plugin unit_tests } From 56d406aaad231a773bb670147fe6dadb0351908d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 11 Apr 2020 12:02:30 +0200 Subject: [PATCH 08/27] WIP --- .../tools/view_25d/lay_plugin/layD25ViewWidget.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index b204800c0..e27129f2f 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -94,6 +94,7 @@ D25ViewWidget::initializeGL () "#undef mediump\n" "\n" "uniform vec4 color;\n" + "uniform vec4 ambient;\n" "uniform vec3 illum;\n" "out lowp vec4 vertexColor;\n" "uniform mat4 matrix;\n" @@ -104,8 +105,9 @@ D25ViewWidget::initializeGL () " vec4 p0 = gl_in[0].gl_Position;\n" " vec4 p1 = gl_in[1].gl_Position;\n" " vec4 p2 = gl_in[2].gl_Position;\n" - " vec3 n = cross(p1.xyz - p0.xyz, p2.xyz - p0.xyz);\n" - " vertexColor.rgb = color.rgb * (max(0.0, dot(normalize(n), illum)) * 0.5 + 0.5);\n" + " vec3 n = cross(p2.xyz - p0.xyz, p1.xyz - p0.xyz);\n" + " float dp = dot(normalize(n), illum);\n" + " vertexColor.rgb = color.rgb * (dp * 0.5 + 0.5) - (min(0.0, dp) * 0.5 * ambient.rgb);\n" " vertexColor.a = 1.0;\n" " gl_Position = matrix * p0;\n" " EmitVertex();\n" @@ -526,7 +528,8 @@ D25ViewWidget::paintGL () matrix *= m_cam_trans; m_shapes_program->setUniformValue ("matrix", matrix); - m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); + m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, -2.0).normalized ()); + m_shapes_program->setUniformValue ("ambient", QVector4D (0.5, 0.5, 0.5, 0.5)); glEnableVertexAttribArray (positions); From 7077bac647dfa49f15f80a9a3bddec9dd9ba3d30 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 11 Apr 2020 22:46:35 +0200 Subject: [PATCH 09/27] WIP. --- .../view_25d/lay_plugin/layD25ViewUtils.cc | 164 +++++++++++++++++ .../view_25d/lay_plugin/layD25ViewUtils.h | 80 +++++++++ .../view_25d/lay_plugin/layD25ViewWidget.cc | 124 ++++++++++--- .../view_25d/lay_plugin/layD25ViewWidget.h | 7 + .../tools/view_25d/lay_plugin/lay_plugin.pro | 6 +- .../unit_tests/layD25ViewUtilsTests.cc | 168 ++++++++++++++++++ .../tools/view_25d/unit_tests/unit_tests.pro | 1 + 7 files changed, 527 insertions(+), 23 deletions(-) create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.h create mode 100644 src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc new file mode 100644 index 000000000..b194e55fa --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc @@ -0,0 +1,164 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layD25ViewUtils.h" + +#include +#include + +#include + +namespace lay +{ + +const double epsilon = 1e-10; + +std::pair +cutpoint_line_with_plane (const QVector3D &line, const QVector3D &dir, const QVector3D &plane, const QVector3D &plane_normal) +{ + double dn = QVector3D::dotProduct (dir, plane_normal); + if (fabs (dn) < epsilon) { + return std::make_pair (false, QVector3D ()); + } else { + return std::make_pair (true, line + dir * QVector3D::dotProduct (plane - line, plane_normal) / dn); + } +} + +std::pair +cutpoint_line_with_face (const QVector3D &line, const QVector3D &dir, const QVector3D &plane, const QVector3D &u, const QVector3D &v) +{ + QVector3D n = QVector3D::crossProduct (u, v); + std::pair r = cutpoint_line_with_plane (line, dir, plane, n); + if (! r.first) { + return r; + } + + double pu = QVector3D::dotProduct (r.second - plane, u); + double pv = QVector3D::dotProduct (r.second - plane, v); + + // test whether the cut point is inside the face + if (pu < -epsilon || pu > u.lengthSquared () + epsilon || pv < -epsilon || pv > v.lengthSquared () + epsilon) { + return std::make_pair (false, QVector3D ()); + } else { + return r; + } +} + +static std::pair plane_or_face (const QVector3D &line, const QVector3D &line_dir, const QVector3D &corner, const QVector3D &u, const QVector3D &v, bool face) +{ + if (face) { + return cutpoint_line_with_face (line, line_dir, corner, u, v); + } else { + return cutpoint_line_with_plane (line, line_dir, corner, QVector3D::crossProduct (u, v)); + } +} + +std::pair +hit_point_with_cuboid (const QVector3D &line, const QVector3D &line_dir, const QVector3D &corner, const QVector3D &dim) +{ + std::vector > cutpoints; + cutpoints.reserve (6); // 6 faces + + for (int pass = 0; pass < 2; ++pass) { + + bool face = (pass == 0); + + if (face) { + bool in_x = (line.x () > corner.x () - epsilon) && (line.x () < corner.x () + dim.x () + epsilon); + bool in_y = (line.y () > corner.y () - epsilon) && (line.y () < corner.y () + dim.y () + epsilon); + bool in_z = (line.z () > corner.z () - epsilon) && (line.z () < corner.z () + dim.z () + epsilon); + if (in_x && in_y && in_z) { + // inside cuboid + return std::make_pair (true, line); + } + } + + cutpoints.clear (); + + // front + cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (dim.x (), 0, 0), QVector3D (0, dim.y (), 0), face)); + // back + cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (0, 0, dim.z ()), QVector3D (dim.x (), 0, 0), QVector3D (0, dim.y (), 0), face)); + + if (face) { + // bottom + cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), face)); + // top + cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (0, dim.y (), 0), QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), face)); + // left + cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (0, 0, dim.z ()), QVector3D (0, dim.y (), 0), face)); + // right + cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), QVector3D (0, dim.y (), 0), face)); + } + + double min_dist = 0.0; + int min_dist_index = -1; + QVector3D ld_norm = line_dir.normalized (); + + for (std::vector >::const_iterator i = cutpoints.begin (); i != cutpoints.end (); ++i) { + if (i->first) { + double dist = QVector3D::dotProduct (i->second - line, ld_norm); + if (dist < -epsilon) { + // ignore all cutpoints behind us + } else if (min_dist_index < 0) { + min_dist = dist; + min_dist_index = int (i - cutpoints.begin ()); + } else if (dist < min_dist) { + min_dist = dist; + min_dist_index = int (i - cutpoints.begin ()); + } + } + } + + if (min_dist_index >= 0) { + return cutpoints [min_dist_index]; + } + + } + + return std::make_pair (false, QVector3D ()); +} + +std::pair +camera_normal (const QMatrix4x4 &camera_trans, double x, double y) +{ + QVector3D p = camera_trans.inverted ().map (QVector3D (x, y, 1.0)); + + QVector4D pv = camera_trans.row (3); + + QMatrix4x4 m (camera_trans); + + float values[] = { + float (x * pv.x ()), float (x * pv.y ()), float (x * pv.z ()), 0.0f, + float (y * pv.x ()), float (y * pv.y ()), float (y * pv.z ()), 0.0f, + float (pv.x ()), float (pv.y ()), float (pv.z ()), 0.0f, + 0.0f, 0.0f, 0.0f, 0.0f + }; + m -= QMatrix4x4 (values); + + QMatrix3x3 nm = m.normalMatrix (); + + QVector3D u (nm (2, 0), nm (2, 1), nm (2, 2)); + return (std::make_pair (p, u.normalized ())); +} + +} diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.h new file mode 100644 index 000000000..c875c771d --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.h @@ -0,0 +1,80 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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_layD25ViewUtils +#define HDR_layD25ViewUtils + +#include "layPluginCommon.h" + +#include +#include +#include + +namespace lay +{ + +/** + * @brief Computes the cutpoint between a line and a plane + * + * The line is given by a point and a direction (line, line_dir). + * The plane is given by a point and a normal vector (plane, plane_normal) + * The "first" component of the returned pair is false if not hit is present. + */ + +LAY_PLUGIN_PUBLIC std::pair +cutpoint_line_with_plane (const QVector3D &line, const QVector3D &line_dir, const QVector3D &plane, const QVector3D &plane_normal); + +/** + * @brief Computes the cutpoint between a line and a face + * + * The line is given by a point and a direction (line, line_dir). + * The face is given by a plane point and two vectors spanning the face. + * The "first" component of the returned pair is false if not hit is present. + */ + +LAY_PLUGIN_PUBLIC std::pair +cutpoint_line_with_face (const QVector3D &line, const QVector3D &dir, const QVector3D &plane, const QVector3D &u, const QVector3D &v); + +/** + * @brief Determines a good hit point of a view line and a cuboid + * + * "corner, dim" are the coordinates for the cuboid (corner is the bottom, left, foremost corner, dim + * is (width, height, depth) + * "line, line_dir" is the view line where "line_dir" is pointing from the camera to the object. + * The returned point is a suitable hit point. + * The "first" component of the returned pair is false if no hit is present. + */ +LAY_PLUGIN_PUBLIC std::pair +hit_point_with_cuboid (const QVector3D &line, const QVector3D &line_dir, const QVector3D &corner, const QVector3D &dim); + +/** + * @brief For a given pixel coordinate and camera transformation matrix compute a line containing all points corresponding to this pixel + * + * The returned pair contains a point and a direction vector describing the line. + */ +LAY_PLUGIN_PUBLIC std::pair +camera_normal (const QMatrix4x4 &camera_trans, double x, double y); + +} + +#endif + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index e27129f2f..dadf2d297 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -22,6 +22,7 @@ #include "layD25ViewWidget.h" +#include "layD25ViewUtils.h" #include "layLayoutView.h" #include "dbRecursiveShapeIterator.h" @@ -50,7 +51,9 @@ D25ViewWidget::D25ViewWidget (QWidget *parent) format.setSamples (4); // more -> widget extends beyond boundary! setFormat (format); - m_cam_position = QVector3D (0.0, 0.0, 3.0); // @@@ + m_cam_position = QVector3D (0.0, 0.0, 4.0); // @@@ + m_scale_factor = 1.0; + m_focus_dist = 0.0; } D25ViewWidget::~D25ViewWidget () @@ -194,19 +197,36 @@ static QVector3D cam_direction (double azimuth, double elevation) void D25ViewWidget::wheelEvent (QWheelEvent *event) { - double cal = 0.6; + double px = (event->pos ().x () - width () / 2) * 2.0 / width (); + double py = -(event->pos ().y () - height () / 2) * 2.0 / height (); - int dx = event->pos ().x () - width () / 2; - int dy = -(event->pos ().y () - height () / 2); + double f = exp (event->angleDelta ().y () * (1.0 / (90 * 8))); - double da = atan (dx * cal * 2.0 / height ()) * 180 / M_PI; - double de = atan (dy * cal * 2.0 / height ()) * 180 / M_PI; + // compute vector of line of sight + std::pair ray = camera_normal (m_cam_trans, px, py); - m_cam_position += (event->angleDelta ().y () * (1.0 / (45 * 8))) * cam_direction (m_cam_azimuth + da, m_cam_elevation + de); + // by definition the ray goes through the camera position + std::pair hp = hit_point_with_scene (m_cam_position, ray.second); + + QVector3D pm = m_cam_trans.map(hp.second); + printf("@@@ mouse=%g,%g back=%g,%g\n", px, py, pm.x(), pm.y()); + printf("@@@ before: hp=%g,%g,%g d=%g,%g,%g s=%g\n", hp.second.x(), hp.second.y(), hp.second.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor); fflush(stdout); + + m_displacement = hp.second * (1.0 - f) + m_displacement * f; + m_scale_factor *= f; update_cam_trans (); } +std::pair +D25ViewWidget::hit_point_with_scene (const QVector3D &line, const QVector3D &line_dir) +{ + QVector3D corner = QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())) * m_scale_factor + m_displacement; + QVector3D dim = QVector3D (m_bbox.width (), m_zmax - m_zmin, m_bbox.height ()) * m_scale_factor; + + return lay::hit_point_with_cuboid (line, line_dir, corner, dim); +} + void D25ViewWidget::mousePressEvent (QMouseEvent *event) { @@ -221,6 +241,19 @@ D25ViewWidget::mousePressEvent (QMouseEvent *event) m_start_cam_position = m_cam_position; m_start_cam_azimuth = m_cam_azimuth; m_start_cam_elevation = m_cam_elevation; + m_start_displacement = m_displacement; + + m_focus_dist = 2.0; + + if (m_dragging || m_rotating) { + + QVector3D cd = cam_direction (m_start_cam_azimuth, m_start_cam_elevation); + std::pair hp = hit_point_with_scene (m_cam_position, cd); + if (hp.first) { + m_focus_dist = std::max (m_focus_dist, double ((m_cam_position - hp.second).length ())); + } + + } } void @@ -232,12 +265,10 @@ D25ViewWidget::mouseReleaseEvent (QMouseEvent * /*event*/) void D25ViewWidget::mouseMoveEvent (QMouseEvent *event) { - double focus_dist = 4.0; // 4 times focal length - if (m_dragging) { // for the chosen perspective transformation: - double cal = 0.6 * focus_dist; + double cal = 0.6 * m_focus_dist; QPoint d = event->pos () - m_start_pos; double f = cal * 2.0 / double (height ()); @@ -249,13 +280,14 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) QVector3D yv (-re * xv.z (), cos (m_start_cam_elevation * M_PI / 180.0), re * xv.x ()); QVector3D drag = xv * dx + yv * dy; - // "-drag" because we're not dragging the camera, we're dragging the scene - m_cam_position = m_start_cam_position - drag; + m_displacement = m_start_displacement + drag; update_cam_trans (); } else if (m_rotating) { + double focus_dist = 4.0; // @@@ + QPoint d = event->pos () - m_start_pos; double ax = atan (d.x () / (0.5 * height ())) * 180 / M_PI; @@ -274,9 +306,12 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) void D25ViewWidget::update_cam_trans () { -printf("@@@ e=%g a=%g x,y,z=%g,%g,%g\n", m_cam_elevation, m_cam_azimuth, m_cam_position.x(), m_cam_position.y(), m_cam_position.z()); fflush(stdout); +printf("@@@ e=%g a=%g x,y,z=%g,%g,%g d=%g,%g,%g s=%g f=%g\n", m_cam_elevation, m_cam_azimuth, m_cam_position.x(), m_cam_position.y(), m_cam_position.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor, m_focus_dist); fflush(stdout); QMatrix4x4 t; + // finally add perspective + t.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); + // third: elevation t.rotate (-m_cam_elevation, 1.0, 0.0, 0.0); @@ -312,6 +347,10 @@ D25ViewWidget::prepare_view () { double z = 0.0, dz = 0.2; // @@@ + m_bbox = db::DBox (); + bool zset = false; + m_zmin = m_zmax = 0.0; + for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { if (! lp->has_children () && lp->visible (true) && lp->cellview_index () >= 0 && lp->cellview_index () < int (mp_view->cellviews ())) { @@ -322,9 +361,9 @@ D25ViewWidget::prepare_view () LayerInfo info; // @@@ use alpha? - info.color[0] = (color & 0xff) / 255.0f; + info.color[0] = ((color >> 16) & 0xff) / 255.0f; info.color[1] = ((color >> 8) & 0xff) / 255.0f; - info.color[2] = ((color >> 16) & 0xff) / 255.0f; + info.color[2] = (color & 0xff) / 255.0f; info.color[3] = 1.0; info.vertex_chunk = &m_vertex_chunks.back (); @@ -333,6 +372,17 @@ D25ViewWidget::prepare_view () const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ()); render_layout (m_vertex_chunks.back (), cv->layout (), *cv.cell (), (unsigned int) lp->layer_index (), z, z + dz); + m_bbox += db::DBox (cv.cell ()->bbox ((unsigned int) lp->layer_index ())) * cv->layout ().dbu (); + + if (! zset) { + m_zmin = z; + m_zmax = z + dz; + zset = true; + } else { + m_zmin = std::min (z, m_zmin); + m_zmax = std::max (z + dz, m_zmax); + } + z += dz; // @@@ } @@ -513,6 +563,7 @@ D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layo void D25ViewWidget::paintGL () { + printf("@@@ width=%d,height=%d\n", width(),height()); // @@@ const qreal retinaScale = devicePixelRatio (); glViewport (0, 0, width () * retinaScale, height () * retinaScale); @@ -523,12 +574,19 @@ D25ViewWidget::paintGL () m_shapes_program->bind (); - QMatrix4x4 matrix; - matrix.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); - matrix *= m_cam_trans; + QMatrix4x4 scene_trans; + + // provide the displacement and scaling + scene_trans.translate (m_displacement); + scene_trans.scale (m_scale_factor); + // this way we can use y as z coordinate when drawing + scene_trans.scale (1.0, 1.0, -1.0); + + m_shapes_program->setUniformValue ("matrix", m_cam_trans * scene_trans); + + // NOTE: z axis of illum points towards the scene because we include the z inversion in the scene transformation matrix + m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); - m_shapes_program->setUniformValue ("matrix", matrix); - m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, -2.0).normalized ()); m_shapes_program->setUniformValue ("ambient", QVector4D (0.5, 0.5, 0.5, 0.5)); glEnableVertexAttribArray (positions); @@ -552,7 +610,8 @@ D25ViewWidget::paintGL () glEnableVertexAttribArray (positions); - m_gridplane_program->setUniformValue ("matrix", matrix); + // @@@ m_gridplane_program->setUniformValue ("matrix", m_cam_trans * m_scene_trans); + m_gridplane_program->setUniformValue ("matrix", QMatrix4x4 ()); // @@@ // @@@ @@ -567,6 +626,7 @@ D25ViewWidget::paintGL () glDrawArrays (GL_TRIANGLES, 0, 6); +#if 0 GLfloat gridline_vertices[] = { -1.0, 0.0, -2.0, -1.0, 0.0, 0.0, -0.75, 0.0, -2.0, -0.75, 0.0, 0.0, @@ -587,6 +647,28 @@ D25ViewWidget::paintGL () 1.0, 0.0, -0.25, -1.0, 0.0, -0.25, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 }; +#else + GLfloat gridline_vertices[] = { + -1.0, -1.0, 0.0, -1.0, 1.0, 0.0, + -0.75, -1.0, 0.0, -0.75, 1.0, 0.0, + -0.5, -1.0, 0.0, -0.5, 1.0, 0.0, + -0.25, -1.0, 0.0, -0.25, 1.0, 0.0, + 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, + 0.25, -1.0, 0.0, 0.25, 1.0, 0.0, + 0.5, -1.0, 0.0, 0.5, 1.0, 0.0, + 0.75, -1.0, 0.0, 0.75, 1.0, 0.0, + 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, + 1.0, -1.0, 0.0, -1.0, -1.0, 0.0, + 1.0, -0.75, 0.0, -1.0, -0.75, 0.0, + 1.0, -0.5, 0.0, -1.0, -0.5, 0.0, + 1.0, -0.25, 0.0, -1.0, -0.25, 0.0, + 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, + 1.0, 0.25, 0.0, -1.0, 0.25, 0.0, + 1.0, 0.5, 0.0, -1.0, 0.5, 0.0, + 1.0, 0.75, 0.0, -1.0, 0.75, 0.0, + 1.0, 1.0, 0.0, -1.0, 1.0, 0.0 + }; +#endif m_shapes_program->setUniformValue ("vertexColor", 1.0, 1.0, 1.0, 0.2f); diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index 63fb4fad5..26a0653ba 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -71,11 +71,17 @@ private: QMatrix4x4 m_cam_trans; bool m_dragging, m_rotating; QVector3D m_cam_position; + double m_scale_factor; double m_cam_azimuth, m_cam_elevation; + QVector3D m_displacement; + double m_focus_dist; QPoint m_start_pos; QVector3D m_start_cam_position; double m_start_cam_azimuth, m_start_cam_elevation; + QVector3D m_start_displacement; lay::LayoutView *mp_view; + db::DBox m_bbox; + double m_zmin, m_zmax; std::list m_vertex_chunks; @@ -95,6 +101,7 @@ private: void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop); void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop); void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop); + std::pair hit_point_with_scene (const QVector3D &line, const QVector3D &line_dir); }; } diff --git a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro index 1de5fe5b5..6afb49ac2 100644 --- a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro +++ b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro @@ -11,13 +11,15 @@ LIBS += -L$$DESTDIR/.. -lklayout_rdb -lklayout_ant HEADERS = \ layD25View.h \ layD25ViewWidget.h \ - layD25MemChunks.h + layD25MemChunks.h \ + layD25ViewUtils.h SOURCES = \ layD25View.cc \ layD25ViewWidget.cc \ layD25Plugin.cc \ - layD25MemChunks.cc + layD25MemChunks.cc \ + layD25ViewUtils.cc FORMS = \ D25View.ui \ diff --git a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc new file mode 100644 index 000000000..e5cf71c65 --- /dev/null +++ b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc @@ -0,0 +1,168 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layD25ViewUtils.h" +#include "tlUnitTest.h" + +static std::string v2s (const QVector3D &v) +{ + return tl::to_string (v.x ()) + "," + tl::to_string (v.y ()) + "," + tl::to_string (v.z ()); +} + +static std::string v2s_2d (const QVector3D &v) +{ + return tl::to_string (v.x ()) + "," + tl::to_string (v.y ()); +} + +TEST(1_CutPoint) +{ + std::pair r; + + r = lay::cutpoint_line_with_plane (QVector3D (0, 0, 0), QVector3D (0, 0, 1), QVector3D (0, 0, 0), QVector3D (1, 0, 0)); + EXPECT_EQ (r.first, false); + + r = lay::cutpoint_line_with_plane (QVector3D (1, 2, 3), QVector3D (0, 0, 2), QVector3D (4, 5, 6), QVector3D (0, 0, 1)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "1,2,6"); + + r = lay::cutpoint_line_with_plane (QVector3D (1, 2, 3), QVector3D (0, 0, -1), QVector3D (4, 5, 6), QVector3D (1, 1, 1)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "1,2,12"); +} + +TEST(2_Face) +{ + std::pair r; + + r = lay::cutpoint_line_with_face (QVector3D (0, 0, 0), QVector3D (0, 0, 1), QVector3D (0, 0, 0), QVector3D (0, 1, 0), QVector3D (0, 0, 1)); + EXPECT_EQ (r.first, false); + + r = lay::cutpoint_line_with_face (QVector3D (1, 2, 3), QVector3D (0, 0, 2), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0)); + EXPECT_EQ (r.first, false); + + r = lay::cutpoint_line_with_face (QVector3D (4, 5, 3), QVector3D (0, 0, 3), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "4,5,6"); + + r = lay::cutpoint_line_with_face (QVector3D (4, 7, 3), QVector3D (0, 0, 1), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0)); + EXPECT_EQ (r.first, false); + + r = lay::cutpoint_line_with_face (QVector3D (4, 6, 3), QVector3D (0, 0, 2), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "4,6,6"); + + r = lay::cutpoint_line_with_face (QVector3D (5, 6, 3), QVector3D (0, 0, -1), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "5,6,6"); + + r = lay::cutpoint_line_with_face (QVector3D (6, 6, 3), QVector3D (0, 0, 1), QVector3D (4, 5, 6), QVector3D (0, 1, 0), QVector3D (1, 0, 0)); + EXPECT_EQ (r.first, false); +} + +TEST(3_HitWithCuboid) +{ + std::pair r; + + r = lay::hit_point_with_cuboid (QVector3D (0, 0, 0), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "0,0,3"); + + r = lay::hit_point_with_cuboid (QVector3D (1, 1, 4), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "1,1,4"); + + r = lay::hit_point_with_cuboid (QVector3D (1, 1, 6), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); + EXPECT_EQ (r.first, false); + + r = lay::hit_point_with_cuboid (QVector3D (5, -6, 0), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "5,-6,3"); + + r = lay::hit_point_with_cuboid (QVector3D (5, -6, 4), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "5,-6,5"); + + r = lay::hit_point_with_cuboid (QVector3D (5, -6, 6), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); + EXPECT_EQ (r.first, false); +} + +TEST(4_CameraNormal) +{ + QMatrix4x4 matrix; + matrix.perspective (60.0f, 1.5, 0.1f, 100.0f); + + std::pair ray; + QVector3D p; + + ray = lay::camera_normal (matrix, 0.0, 0.0); + EXPECT_EQ (v2s (ray.second.normalized ()), "0,0,-1"); + + ray = lay::camera_normal (matrix, 1.0, 0.0); + EXPECT_EQ (v2s (ray.second), "0.654654,0,-0.755929"); + + p = matrix.map (ray.first); + EXPECT_EQ (v2s_2d (p), "1,0"); + + p = matrix.map (ray.first + ray.second); + EXPECT_EQ (v2s_2d (p), "1,0"); + + p = matrix.map (ray.first + ray.second * 1000.0); + EXPECT_EQ (v2s_2d (p), "1,0"); + + ray = lay::camera_normal (matrix, 0.0, -1.0); + EXPECT_EQ (v2s (ray.second), "0,-0.5,-0.866025"); + + p = matrix.map (ray.first); + EXPECT_EQ (v2s_2d (p), "0,-1"); + + p = matrix.map (ray.first + ray.second); + EXPECT_EQ (v2s_2d (p), "0,-1"); + + p = matrix.map (ray.first + ray.second * 1000.0); + EXPECT_EQ (v2s_2d (p), "0,-1"); +} + +TEST(5_CameraNormal) +{ + QMatrix4x4 matrix; + QVector3D p; + + matrix.perspective (60.0f, 1.5, 0.1f, 100.0f); + matrix.rotate (22.0, 1.0, 0.0, 0.0); + matrix.rotate (-15.0, 0.0, 1.0, 0.0); + matrix.translate (QVector3D (0.0, 0.0, 4.0)); + + std::pair ray; + + ray = lay::camera_normal (matrix, 0.0, 1.0); + EXPECT_EQ (v2s (ray.second), "-0.2563,0.139173,-0.956526"); + + p = matrix.map (ray.first); + EXPECT_EQ (v2s_2d (p), "0,1"); + + p = matrix.map (ray.first + ray.second); + EXPECT_EQ (v2s_2d (p), "0,1"); + + p = matrix.map (ray.first + ray.second * 1000.0); + EXPECT_EQ (v2s_2d (p), "0,1"); +} diff --git a/src/plugins/tools/view_25d/unit_tests/unit_tests.pro b/src/plugins/tools/view_25d/unit_tests/unit_tests.pro index 22fd790b2..729ddc42e 100644 --- a/src/plugins/tools/view_25d/unit_tests/unit_tests.pro +++ b/src/plugins/tools/view_25d/unit_tests/unit_tests.pro @@ -7,6 +7,7 @@ include($$PWD/../../../../lib_ut.pri) SOURCES = \ layD25MemChunksTests.cc \ + layD25ViewUtilsTests.cc INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../lay_plugin $$PWD/../../../common DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../lay_plugin $$PWD/../../../common From d37608dac1783d9a15cbdc3d6d49173afde0835d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 12 Apr 2020 10:32:23 +0200 Subject: [PATCH 10/27] WIP. --- .../tools/view_25d/lay_plugin/layD25View.cc | 3 + .../view_25d/lay_plugin/layD25ViewUtils.cc | 61 +++++++ .../view_25d/lay_plugin/layD25ViewUtils.h | 12 ++ .../view_25d/lay_plugin/layD25ViewWidget.cc | 154 +++++++++++++----- .../view_25d/lay_plugin/layD25ViewWidget.h | 10 +- .../unit_tests/layD25ViewUtilsTests.cc | 62 +++++++ 6 files changed, 260 insertions(+), 42 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index 44f905517..fdb5230d9 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -37,6 +37,9 @@ D25View::D25View (QWidget *parent) mp_ui = new Ui::D25View (); mp_ui->setupUi (this); + // @@@ should be an event filter? + mp_ui->d25_view->setFocusPolicy (Qt::StrongFocus); + mp_ui->d25_view->setFocus (); // @@@ } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc index b194e55fa..e63a75969 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc @@ -161,4 +161,65 @@ camera_normal (const QMatrix4x4 &camera_trans, double x, double y) return (std::make_pair (p, u.normalized ())); } +void +normalize_scene_trans (const QMatrix4x4 &cam_trans, QVector3D &displacement, double &scale, double ztarget) +{ + QMatrix4x4 m; + + // Here is the theory: + // Let: + // cam = ( M t ) M = 3x3 matrix, t = 3x1 translation vector, z = scalar, p = 1x3 perspective + // ( p z ) + // and: + // scene = ( S d ) S = s*U1 (s = scale factor, U1 = 3x3 unit matrix), d = 3x1 displacement vector + // ( 0 1 ) + // then: + // cam * scene = ( M*s M*d+t ) + // ( p*s p*d+z ) (p*d = dot product) + // + // this is image invariant (only x,y results are considered) against changes of s (s->s') if + // + // 1.) (p*d+z)/s = (p*d'+z)/s' + // 2.) (M*d+t)/s = (M*d'+t)/s' for [x] and [y] + // + // Ff we seek a solution with d'[z] == b (b = ztarget), we get these equations (f:=s'/s) + // + // 2.) M[xx] * d'[x] + M[xy] * d'[y] - ((M*d)[x] + t[x]) * f = -t[x] - M[xz] * b + // M[yx] * d'[x] + M[yy] * d'[y] - ((M*d)[y] + t[y]) * f = -t[y] - M[yz] * b + // 1.) p[x] * d'[x] + p[y] * d'[y] - (p*d+z) * f = -z - p[z] * b + // + // we can solve these equations for d'[x], d'[y] and f. + // With p[x]=M[wx], p[y]=M[wy] and z=t[w], the above equation system can be written as + // + // M[ix] * d'[x] + M[iy] * d'[y] - ((M*d)[i] + t[i]) * f = -t[i] - M[iz]*b i = x,y,w + // + // and with M,t->M (4x4 matrix) and d->(d,1) (4d vector) + // + // M[ix] * d'[x] + M[iy] * d'[y] - (M*d)[i] * f = -t[i] - M[iz]*b i = x,y,w + // + + QVector4D d4 (displacement); + d4.setW (1.0); + + for (int i = 0; i < 4; ++i) { + if (i != 2) { + m (i, 0) = cam_trans (i, 0); + m (i, 1) = cam_trans (i, 1); + m (i, 3) = -QVector4D::dotProduct (cam_trans.row (i), d4); + } + } + + bool invertable = false; + m = m.inverted (&invertable); + if (! invertable) { + return; + } + + QVector4D sol = m.map (-cam_trans.column (3) - cam_trans.column (2) * ztarget); + if (sol.w () > 0.01 /*skip weird solutions*/) { + scale *= sol.w (); + displacement = QVector3D (sol.x (), sol.y (), ztarget); + } +} + } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.h index c875c771d..b4bc140ea 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.h @@ -74,6 +74,18 @@ hit_point_with_cuboid (const QVector3D &line, const QVector3D &line_dir, const Q LAY_PLUGIN_PUBLIC std::pair camera_normal (const QMatrix4x4 &camera_trans, double x, double y); +/** + * @brief Normalizes a scene transformation + * + * Scene transformations consist of a scaling and displacement. Both are + * interchangeable to some extent under the presence of a perspective + * transformation (further away makes the scene smaller). This normalization + * tries to find a displacement which has "ztarget" target value for z. Without normalization + * the scene tends to "move away" with respect to z. + */ +LAY_PLUGIN_PUBLIC void +normalize_scene_trans (const QMatrix4x4 &cam_trans, QVector3D &displacement, double &scale, double ztarget = 0.0); + } #endif diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index dadf2d297..04f965992 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -34,6 +34,7 @@ #include #include +#include #include "math.h" @@ -44,14 +45,13 @@ namespace lay D25ViewWidget::D25ViewWidget (QWidget *parent) : QOpenGLWidget (parent), - m_shapes_program (0), m_dragging (false), m_rotating (false), m_cam_azimuth (0.0), m_cam_elevation (0.0) + m_shapes_program (0), m_dragging (false), m_rotating (false), m_cam_azimuth (0.0), m_cam_elevation (0.0), m_top_view (false) { QSurfaceFormat format; format.setDepthBufferSize (24); format.setSamples (4); // more -> widget extends beyond boundary! setFormat (format); - m_cam_position = QVector3D (0.0, 0.0, 4.0); // @@@ m_scale_factor = 1.0; m_focus_dist = 0.0; } @@ -183,48 +183,87 @@ D25ViewWidget::initializeGL () } } -static QVector3D cam_direction (double azimuth, double elevation) -{ - // positive azimuth: camera looks left - // positive elevation: camera looks up - double y = sin (elevation * M_PI / 180.0); - double r = cos (elevation * M_PI / 180.0); - double x = r * sin (azimuth * M_PI / 180.0); - double z = r * cos (azimuth * M_PI / 180.0); - return QVector3D (x, y, -z); -} - void D25ViewWidget::wheelEvent (QWheelEvent *event) { double px = (event->pos ().x () - width () / 2) * 2.0 / width (); double py = -(event->pos ().y () - height () / 2) * 2.0 / height (); - double f = exp (event->angleDelta ().y () * (1.0 / (90 * 8))); - // compute vector of line of sight std::pair ray = camera_normal (m_cam_trans, px, py); // by definition the ray goes through the camera position - std::pair hp = hit_point_with_scene (m_cam_position, ray.second); + float focal_length = 2.0; + QVector3D hp = hit_point_with_scene (cam_position () + focal_length * ray.second, ray.second); - QVector3D pm = m_cam_trans.map(hp.second); - printf("@@@ mouse=%g,%g back=%g,%g\n", px, py, pm.x(), pm.y()); - printf("@@@ before: hp=%g,%g,%g d=%g,%g,%g s=%g\n", hp.second.x(), hp.second.y(), hp.second.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor); fflush(stdout); + if (false /*@@@*/ && (event->modifiers () & Qt::ShiftModifier)) { - m_displacement = hp.second * (1.0 - f) + m_displacement * f; - m_scale_factor *= f; + // "Shift" is closeup + + double f = event->angleDelta ().y () * (1.0 / (90 * 8)); + m_displacement += -f * cam_position ().length () * ray.second; + + } else { + + // No shift is zoom + + double f = exp (event->angleDelta ().y () * (1.0 / (90 * 8))); + + QVector3D initial_displacement = m_displacement; + QVector3D displacement = m_displacement; + + displacement = hp * (1.0 - f) + displacement * f; + m_scale_factor *= f; + + // normalize the scene translation so the scene does not "flee" + + QMatrix4x4 ct; + ct.rotate (-cam_elevation (), 1.0, 0.0, 0.0); + ct.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + ct.translate (-cam_position ()); + + initial_displacement = ct.map (initial_displacement); + displacement = ct.map (displacement); + + lay::normalize_scene_trans (m_cam_trans, displacement, m_scale_factor, initial_displacement.z ()); + + m_displacement = ct.inverted ().map (displacement); + + } update_cam_trans (); } -std::pair +void +D25ViewWidget::keyPressEvent (QKeyEvent *event) +{ + if (event->key () == Qt::Key_Shift) { + m_top_view = true; + update_cam_trans (); + } +} + +void +D25ViewWidget::keyReleaseEvent (QKeyEvent *event) +{ + if (event->key () == Qt::Key_Shift) { + m_top_view = false; + update_cam_trans (); + } +} + +QVector3D D25ViewWidget::hit_point_with_scene (const QVector3D &line, const QVector3D &line_dir) { QVector3D corner = QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())) * m_scale_factor + m_displacement; QVector3D dim = QVector3D (m_bbox.width (), m_zmax - m_zmin, m_bbox.height ()) * m_scale_factor; - return lay::hit_point_with_cuboid (line, line_dir, corner, dim); + std::pair hp = lay::hit_point_with_cuboid (line, line_dir, corner, dim); + if (! hp.first) { + return line; + } else { + return hp.second; + } } void @@ -238,20 +277,19 @@ D25ViewWidget::mousePressEvent (QMouseEvent *event) } m_start_pos = event->pos (); - m_start_cam_position = m_cam_position; - m_start_cam_azimuth = m_cam_azimuth; - m_start_cam_elevation = m_cam_elevation; + m_start_cam_position = cam_position (); + m_start_cam_azimuth = cam_azimuth (); + m_start_cam_elevation = cam_elevation (); m_start_displacement = m_displacement; m_focus_dist = 2.0; if (m_dragging || m_rotating) { - QVector3D cd = cam_direction (m_start_cam_azimuth, m_start_cam_elevation); - std::pair hp = hit_point_with_scene (m_cam_position, cd); - if (hp.first) { - m_focus_dist = std::max (m_focus_dist, double ((m_cam_position - hp.second).length ())); - } + QVector3D cd = cam_direction (); + QVector3D cp = cam_position (); + QVector3D hp = hit_point_with_scene (cp + m_focus_dist * cd, cd); + m_focus_dist = std::max (m_focus_dist, double ((cp - hp).length ())); } } @@ -275,9 +313,9 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) double dx = d.x () * f; double dy = -d.y () * f; - QVector3D xv (cos (m_start_cam_azimuth * M_PI / 180.0), 0.0, -sin (m_start_cam_azimuth * M_PI / 180.0)); - double re = sin (m_start_cam_elevation * M_PI / 180.0); - QVector3D yv (-re * xv.z (), cos (m_start_cam_elevation * M_PI / 180.0), re * xv.x ()); + QVector3D xv (cos (cam_azimuth () * M_PI / 180.0), 0.0, -sin (cam_azimuth () * M_PI / 180.0)); + double re = sin (cam_elevation () * M_PI / 180.0); + QVector3D yv (-re * xv.z (), cos (cam_elevation () * M_PI / 180.0), re * xv.x ()); QVector3D drag = xv * dx + yv * dy; m_displacement = m_start_displacement + drag; @@ -286,6 +324,8 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) } else if (m_rotating) { + // @@@ needs redo ... + // @@@ consider m_top_view double focus_dist = 4.0; // @@@ QPoint d = event->pos () - m_start_pos; @@ -296,30 +336,64 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) m_cam_elevation = m_start_cam_elevation + ay; m_cam_azimuth = m_start_cam_azimuth + ax; - m_cam_position = (cam_direction (m_cam_azimuth, m_cam_elevation) * -focus_dist) + cam_direction (m_start_cam_azimuth, m_start_cam_elevation) * focus_dist + m_start_cam_position; - update_cam_trans (); } } +QVector3D +D25ViewWidget::cam_direction () const +{ + double azimuth = cam_azimuth (); + double elevation = cam_elevation (); + + // positive azimuth: camera looks left + // positive elevation: camera looks up + double y = sin (elevation * M_PI / 180.0); + double r = cos (elevation * M_PI / 180.0); + double x = r * sin (azimuth * M_PI / 180.0); + double z = r * cos (azimuth * M_PI / 180.0); + return QVector3D (x, y, -z); +} + +QVector3D +D25ViewWidget::cam_position () const +{ + double focus_dist = 4.0; + return cam_direction () * -focus_dist; +} + +double +D25ViewWidget::cam_azimuth () const +{ + return m_cam_azimuth; +} + +double +D25ViewWidget::cam_elevation () const +{ + return m_top_view ? -90.0 : m_cam_elevation; +} + void D25ViewWidget::update_cam_trans () { -printf("@@@ e=%g a=%g x,y,z=%g,%g,%g d=%g,%g,%g s=%g f=%g\n", m_cam_elevation, m_cam_azimuth, m_cam_position.x(), m_cam_position.y(), m_cam_position.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor, m_focus_dist); fflush(stdout); + QVector3D cp = cam_position (); + +printf("@@@ e=%g a=%g x,y,z=%g,%g,%g d=%g,%g,%g s=%g f=%g\n", cam_elevation (), cam_azimuth (), cp.x(), cp.y(), cp.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor, m_focus_dist); fflush(stdout); QMatrix4x4 t; // finally add perspective t.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); // third: elevation - t.rotate (-m_cam_elevation, 1.0, 0.0, 0.0); + t.rotate (-cam_elevation (), 1.0, 0.0, 0.0); // second: azimuth - t.rotate (m_cam_azimuth, 0.0, 1.0, 0.0); + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); // first: translate the origin into the cam's position - t.translate (-m_cam_position); + t.translate (-cam_position ()); m_cam_trans = t; diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index 26a0653ba..68bc1a468 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -57,6 +57,8 @@ public: D25ViewWidget (QWidget *parent); ~D25ViewWidget (); + void keyPressEvent (QKeyEvent *event); + void keyReleaseEvent (QKeyEvent *event); void wheelEvent (QWheelEvent *event); void mousePressEvent (QMouseEvent *event); void mouseReleaseEvent (QMouseEvent *event); @@ -70,9 +72,9 @@ private: QOpenGLShaderProgram *m_shapes_program, *m_gridplane_program; QMatrix4x4 m_cam_trans; bool m_dragging, m_rotating; - QVector3D m_cam_position; double m_scale_factor; double m_cam_azimuth, m_cam_elevation; + bool m_top_view; QVector3D m_displacement; double m_focus_dist; QPoint m_start_pos; @@ -101,7 +103,11 @@ private: void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop); void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop); void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop); - std::pair hit_point_with_scene (const QVector3D &line, const QVector3D &line_dir); + QVector3D hit_point_with_scene(const QVector3D &line, const QVector3D &line_dir); + double cam_elevation () const; + double cam_azimuth () const; + QVector3D cam_position () const; + QVector3D cam_direction () const; }; } diff --git a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc index e5cf71c65..4d9daa5b6 100644 --- a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc +++ b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc @@ -166,3 +166,65 @@ TEST(5_CameraNormal) p = matrix.map (ray.first + ray.second * 1000.0); EXPECT_EQ (v2s_2d (p), "0,1"); } + +TEST(6_NormalizeSceneTrans) +{ + QMatrix4x4 cam; + cam.perspective (60.0f, 1.5, 0.1f, 100.0f); + cam.rotate (22.0, 1.0, 0.0, 0.0); + cam.rotate (-15.0, 0.0, 1.0, 0.0); + cam.translate (QVector3D (0.0, 0.0, 4.0)); + + double scale = 0.1; + QVector3D displacement (-0.5, 0.2, 2.0); + + QMatrix4x4 scene1; + scene1.translate (displacement); + scene1.scale (scale); + + QVector3D v1 = (cam * scene1).map (QVector3D (1.0, -1.0, 2.0)); + v1.setZ (0); + QVector3D v2 = (cam * scene1).map (QVector3D (0.0, 0.0, 5.0)); + v2.setZ (0); + QVector3D v3 = (cam * scene1).map (QVector3D (-1.0, 0.0, 1.0)); + v3.setZ (0); + + lay::normalize_scene_trans (cam, displacement, scale); + + QMatrix4x4 scene2; + scene2.translate (displacement); + scene2.scale (scale); + + EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0667"); + + QVector3D u1 = (cam * scene2).map (QVector3D (1.0, -1.0, 2.0)); + u1.setZ (0); + QVector3D u2 = (cam * scene2).map (QVector3D (0.0, 0.0, 5.0)); + u2.setZ (0); + QVector3D u3 = (cam * scene2).map (QVector3D (-1.0, 0.0, 1.0)); + u3.setZ (0); + + EXPECT_EQ ((u1 - v1).length () < 1e-4, true); + EXPECT_EQ ((u2 - v2).length () < 1e-4, true); + EXPECT_EQ ((u3 - v3).length () < 1e-4, true); + + lay::normalize_scene_trans (cam, displacement, scale, 1.0); + + QMatrix4x4 scene3; + scene3.translate (displacement); + scene3.scale (scale); + + EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0833"); + EXPECT_EQ (tl::to_string (displacement.z ()), "1"); + + QVector3D uu1 = (cam * scene2).map (QVector3D (1.0, -1.0, 2.0)); + uu1.setZ (0); + QVector3D uu2 = (cam * scene2).map (QVector3D (0.0, 0.0, 5.0)); + uu2.setZ (0); + QVector3D uu3 = (cam * scene2).map (QVector3D (-1.0, 0.0, 1.0)); + uu3.setZ (0); + + EXPECT_EQ ((uu1 - v1).length () < 1e-4, true); + EXPECT_EQ ((uu2 - v2).length () < 1e-4, true); + EXPECT_EQ ((uu3 - v3).length () < 1e-4, true); +} From 55e79ef78fbfc976ea0cb49bf84ae1fb70a09d30 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 12 Apr 2020 16:56:30 +0200 Subject: [PATCH 11/27] WIP. --- .../view_25d/lay_plugin/layD25ViewWidget.cc | 45 +++++++++---------- .../view_25d/lay_plugin/layD25ViewWidget.h | 3 +- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 04f965992..ee173e776 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -190,7 +190,7 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) double py = -(event->pos ().y () - height () / 2) * 2.0 / height (); // compute vector of line of sight - std::pair ray = camera_normal (m_cam_trans, px, py); + std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); // by definition the ray goes through the camera position float focal_length = 2.0; @@ -217,15 +217,11 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) // normalize the scene translation so the scene does not "flee" - QMatrix4x4 ct; - ct.rotate (-cam_elevation (), 1.0, 0.0, 0.0); - ct.rotate (cam_azimuth (), 0.0, 1.0, 0.0); - ct.translate (-cam_position ()); - + QMatrix4x4 ct = cam_trans (); initial_displacement = ct.map (initial_displacement); displacement = ct.map (displacement); - lay::normalize_scene_trans (m_cam_trans, displacement, m_scale_factor, initial_displacement.z ()); + lay::normalize_scene_trans (cam_perspective (), displacement, m_scale_factor, initial_displacement.z ()); m_displacement = ct.inverted ().map (displacement); @@ -375,27 +371,30 @@ D25ViewWidget::cam_elevation () const return m_top_view ? -90.0 : m_cam_elevation; } +QMatrix4x4 +D25ViewWidget::cam_perspective () const +{ + QMatrix4x4 t; + t.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); + return t; +} + +QMatrix4x4 +D25ViewWidget::cam_trans () const +{ + QMatrix4x4 t; + t.rotate (-cam_elevation (), 1.0, 0.0, 0.0); + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + t.translate (-cam_position ()); + return t; +} + void D25ViewWidget::update_cam_trans () { QVector3D cp = cam_position (); printf("@@@ e=%g a=%g x,y,z=%g,%g,%g d=%g,%g,%g s=%g f=%g\n", cam_elevation (), cam_azimuth (), cp.x(), cp.y(), cp.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor, m_focus_dist); fflush(stdout); - QMatrix4x4 t; - - // finally add perspective - t.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); - - // third: elevation - t.rotate (-cam_elevation (), 1.0, 0.0, 0.0); - - // second: azimuth - t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); - - // first: translate the origin into the cam's position - t.translate (-cam_position ()); - - m_cam_trans = t; update (); } @@ -656,7 +655,7 @@ D25ViewWidget::paintGL () // this way we can use y as z coordinate when drawing scene_trans.scale (1.0, 1.0, -1.0); - m_shapes_program->setUniformValue ("matrix", m_cam_trans * scene_trans); + m_shapes_program->setUniformValue ("matrix", cam_perspective () * cam_trans () * scene_trans); // NOTE: z axis of illum points towards the scene because we include the z inversion in the scene transformation matrix m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index 68bc1a468..c467510d8 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -70,7 +70,6 @@ private: typedef lay::mem_chunks chunks_type; QOpenGLShaderProgram *m_shapes_program, *m_gridplane_program; - QMatrix4x4 m_cam_trans; bool m_dragging, m_rotating; double m_scale_factor; double m_cam_azimuth, m_cam_elevation; @@ -108,6 +107,8 @@ private: double cam_azimuth () const; QVector3D cam_position () const; QVector3D cam_direction () const; + QMatrix4x4 cam_perspective () const; + QMatrix4x4 cam_trans () const; }; } From 75b1b4dc54499e67833a692174633a161d418fae Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 12 Apr 2020 18:38:39 +0200 Subject: [PATCH 12/27] WIP. --- .../view_25d/lay_plugin/layD25ViewUtils.cc | 48 +++++++++---------- .../view_25d/lay_plugin/layD25ViewWidget.cc | 17 +++---- .../unit_tests/layD25ViewUtilsTests.cc | 14 +++--- 3 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc index e63a75969..ba690ee99 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc @@ -164,60 +164,60 @@ camera_normal (const QMatrix4x4 &camera_trans, double x, double y) void normalize_scene_trans (const QMatrix4x4 &cam_trans, QVector3D &displacement, double &scale, double ztarget) { - QMatrix4x4 m; - // Here is the theory: // Let: // cam = ( M t ) M = 3x3 matrix, t = 3x1 translation vector, z = scalar, p = 1x3 perspective // ( p z ) // and: - // scene = ( S d ) S = s*U1 (s = scale factor, U1 = 3x3 unit matrix), d = 3x1 displacement vector - // ( 0 1 ) + // scene = ( S d*s ) S = s*U1 (s = scale factor, U1 = 3x3 unit matrix), d = 3x1 displacement vector + // ( 0 1 ) // then: - // cam * scene = ( M*s M*d+t ) - // ( p*s p*d+z ) (p*d = dot product) + // cam * scene = ( M*s M*d*s+t ) + // ( p*s p*d*s+z ) (p*d = dot product) // // this is image invariant (only x,y results are considered) against changes of s (s->s') if // - // 1.) (p*d+z)/s = (p*d'+z)/s' - // 2.) (M*d+t)/s = (M*d'+t)/s' for [x] and [y] + // 1.) (p*d*s+z)/s = (p*d'*s'+z)/s' (because x and y will be devided by this value) + // 2.) (M*d*s+t)/s = (M*d'*s'+t)/s' for [x] and [y] // - // Ff we seek a solution with d'[z] == b (b = ztarget), we get these equations (f:=s'/s) + // or // - // 2.) M[xx] * d'[x] + M[xy] * d'[y] - ((M*d)[x] + t[x]) * f = -t[x] - M[xz] * b - // M[yx] * d'[x] + M[yy] * d'[y] - ((M*d)[y] + t[y]) * f = -t[y] - M[yz] * b - // 1.) p[x] * d'[x] + p[y] * d'[y] - (p*d+z) * f = -z - p[z] * b + // 1.) p*d+z/s = p*d'+z/s' + // 2.) M*d+t/s = M*d'+t/s' + // + // If we seek a solution with d'[z] == b (b = ztarget), we get these equations (f:=1/s') + // + // 2.) M[xx] * d'[x] + M[xy] * d'[y] + t[x] * f = (M*d)[x] + t[x]/s - M[xz]*b + // M[yx] * d'[x] + M[yy] * d'[y] + t[y] * f = (M*d)[y] + t[y]/s - M[yz]*b + // 1.) p[x] * d'[x] + p[y] * d'[y] + z * f = p*d + z/s - p[z]*b // // we can solve these equations for d'[x], d'[y] and f. // With p[x]=M[wx], p[y]=M[wy] and z=t[w], the above equation system can be written as // - // M[ix] * d'[x] + M[iy] * d'[y] - ((M*d)[i] + t[i]) * f = -t[i] - M[iz]*b i = x,y,w - // - // and with M,t->M (4x4 matrix) and d->(d,1) (4d vector) - // - // M[ix] * d'[x] + M[iy] * d'[y] - (M*d)[i] * f = -t[i] - M[iz]*b i = x,y,w + // M[ix] * d'[x] + M[iy] * d'[y] + t[i] * f = (M*d)[i] - M[iz]*b + t[i]/s i = x,y,w // - QVector4D d4 (displacement); - d4.setW (1.0); + QMatrix4x4 m; for (int i = 0; i < 4; ++i) { if (i != 2) { m (i, 0) = cam_trans (i, 0); m (i, 1) = cam_trans (i, 1); - m (i, 3) = -QVector4D::dotProduct (cam_trans.row (i), d4); + m (i, 3) = cam_trans (i, 3); } } bool invertable = false; - m = m.inverted (&invertable); + QMatrix4x4 minv = m.inverted (&invertable); if (! invertable) { return; } - QVector4D sol = m.map (-cam_trans.column (3) - cam_trans.column (2) * ztarget); - if (sol.w () > 0.01 /*skip weird solutions*/) { - scale *= sol.w (); + QVector4D rhs = cam_trans.map (QVector4D (displacement.x (), displacement.y (), displacement.z () - ztarget, 1.0 / scale)); + QVector4D sol = minv.map (rhs); + double f = sol.w (); + if (f > 1e-6 /*skip weird solutions*/) { + scale = 1.0 / f; displacement = QVector3D (sol.x (), sol.y (), ztarget); } } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index ee173e776..5892e329a 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -201,7 +201,7 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) // "Shift" is closeup double f = event->angleDelta ().y () * (1.0 / (90 * 8)); - m_displacement += -f * cam_position ().length () * ray.second; + m_displacement += -(f / m_scale_factor) * cam_position ().length () * ray.second; } else { @@ -212,7 +212,7 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) QVector3D initial_displacement = m_displacement; QVector3D displacement = m_displacement; - displacement = hp * (1.0 - f) + displacement * f; + displacement += hp * (1.0 - f) / (f * m_scale_factor); m_scale_factor *= f; // normalize the scene translation so the scene does not "flee" @@ -251,7 +251,7 @@ D25ViewWidget::keyReleaseEvent (QKeyEvent *event) QVector3D D25ViewWidget::hit_point_with_scene (const QVector3D &line, const QVector3D &line_dir) { - QVector3D corner = QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())) * m_scale_factor + m_displacement; + QVector3D corner = (QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())) + m_displacement) * m_scale_factor; QVector3D dim = QVector3D (m_bbox.width (), m_zmax - m_zmin, m_bbox.height ()) * m_scale_factor; std::pair hp = lay::hit_point_with_cuboid (line, line_dir, corner, dim); @@ -314,7 +314,7 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) QVector3D yv (-re * xv.z (), cos (cam_elevation () * M_PI / 180.0), re * xv.x ()); QVector3D drag = xv * dx + yv * dy; - m_displacement = m_start_displacement + drag; + m_displacement = m_start_displacement + drag / m_scale_factor; update_cam_trans (); @@ -355,7 +355,7 @@ D25ViewWidget::cam_direction () const QVector3D D25ViewWidget::cam_position () const { - double focus_dist = 4.0; + double focus_dist = 4.0; // @@@ return cam_direction () * -focus_dist; } @@ -374,8 +374,10 @@ D25ViewWidget::cam_elevation () const QMatrix4x4 D25ViewWidget::cam_perspective () const { + double focus_dist = 4.0; // @@@ QMatrix4x4 t; t.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); + t.translate (QVector3D (0.0, 0.0, -focus_dist)); return t; } @@ -385,7 +387,6 @@ D25ViewWidget::cam_trans () const QMatrix4x4 t; t.rotate (-cam_elevation (), 1.0, 0.0, 0.0); t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); - t.translate (-cam_position ()); return t; } @@ -649,9 +650,9 @@ D25ViewWidget::paintGL () QMatrix4x4 scene_trans; - // provide the displacement and scaling - scene_trans.translate (m_displacement); + // provide the displacement and scaling (in this order!) scene_trans.scale (m_scale_factor); + scene_trans.translate (m_displacement); // this way we can use y as z coordinate when drawing scene_trans.scale (1.0, 1.0, -1.0); diff --git a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc index 4d9daa5b6..b24265b22 100644 --- a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc +++ b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc @@ -176,11 +176,11 @@ TEST(6_NormalizeSceneTrans) cam.translate (QVector3D (0.0, 0.0, 4.0)); double scale = 0.1; - QVector3D displacement (-0.5, 0.2, 2.0); + QVector3D displacement (-5.0, 2.0, 20.0); QMatrix4x4 scene1; - scene1.translate (displacement); scene1.scale (scale); + scene1.translate (displacement); QVector3D v1 = (cam * scene1).map (QVector3D (1.0, -1.0, 2.0)); v1.setZ (0); @@ -192,8 +192,8 @@ TEST(6_NormalizeSceneTrans) lay::normalize_scene_trans (cam, displacement, scale); QMatrix4x4 scene2; - scene2.translate (displacement); scene2.scale (scale); + scene2.translate (displacement); EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0667"); @@ -208,14 +208,14 @@ TEST(6_NormalizeSceneTrans) EXPECT_EQ ((u2 - v2).length () < 1e-4, true); EXPECT_EQ ((u3 - v3).length () < 1e-4, true); - lay::normalize_scene_trans (cam, displacement, scale, 1.0); + lay::normalize_scene_trans (cam, displacement, scale, 10.0); QMatrix4x4 scene3; - scene3.translate (displacement); scene3.scale (scale); + scene3.translate (displacement); - EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0833"); - EXPECT_EQ (tl::to_string (displacement.z ()), "1"); + EXPECT_EQ (tl::sprintf ("%.4f", scale), "0.0800"); + EXPECT_EQ (tl::to_string (displacement.z ()), "10"); QVector3D uu1 = (cam * scene2).map (QVector3D (1.0, -1.0, 2.0)); uu1.setZ (0); From 194a2747e68b2e54b424bf15640927e9211426c4 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sun, 12 Apr 2020 19:15:11 +0200 Subject: [PATCH 13/27] WIP: better hit point detection --- .../view_25d/lay_plugin/layD25ViewUtils.cc | 29 +++++++++++-------- .../view_25d/lay_plugin/layD25ViewWidget.cc | 13 ++------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc index ba690ee99..9d2bfc359 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc @@ -63,12 +63,20 @@ cutpoint_line_with_face (const QVector3D &line, const QVector3D &dir, const QVec } } +static bool somewhat_perpendicular (const QVector3D &a, const QVector3D &b) +{ + // returns true if a and b are perpendicular within 30 degree + return fabs (QVector3D::dotProduct (a, b) < 0.5 * a.length () * b.length ()); +} + static std::pair plane_or_face (const QVector3D &line, const QVector3D &line_dir, const QVector3D &corner, const QVector3D &u, const QVector3D &v, bool face) { if (face) { return cutpoint_line_with_face (line, line_dir, corner, u, v); - } else { + } else if (somewhat_perpendicular (u, line_dir) && somewhat_perpendicular (v, line_dir)) { return cutpoint_line_with_plane (line, line_dir, corner, QVector3D::crossProduct (u, v)); + } else { + return std::make_pair (false, QVector3D ()); } } @@ -98,17 +106,14 @@ hit_point_with_cuboid (const QVector3D &line, const QVector3D &line_dir, const Q cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (dim.x (), 0, 0), QVector3D (0, dim.y (), 0), face)); // back cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (0, 0, dim.z ()), QVector3D (dim.x (), 0, 0), QVector3D (0, dim.y (), 0), face)); - - if (face) { - // bottom - cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), face)); - // top - cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (0, dim.y (), 0), QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), face)); - // left - cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (0, 0, dim.z ()), QVector3D (0, dim.y (), 0), face)); - // right - cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), QVector3D (0, dim.y (), 0), face)); - } + // bottom + cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), face)); + // top + cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (0, dim.y (), 0), QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), face)); + // left + cutpoints.push_back (plane_or_face (line, line_dir, corner, QVector3D (0, 0, dim.z ()), QVector3D (0, dim.y (), 0), face)); + // right + cutpoints.push_back (plane_or_face (line, line_dir, corner + QVector3D (dim.x (), 0, 0), QVector3D (0, 0, dim.z ()), QVector3D (0, dim.y (), 0), face)); double min_dist = 0.0; int min_dist_index = -1; diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 5892e329a..ef5a708a9 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -340,16 +340,9 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) QVector3D D25ViewWidget::cam_direction () const { - double azimuth = cam_azimuth (); - double elevation = cam_elevation (); - - // positive azimuth: camera looks left - // positive elevation: camera looks up - double y = sin (elevation * M_PI / 180.0); - double r = cos (elevation * M_PI / 180.0); - double x = r * sin (azimuth * M_PI / 180.0); - double z = r * cos (azimuth * M_PI / 180.0); - return QVector3D (x, y, -z); + QVector3D cd = cam_trans ().map (QVector3D (0, 0, 1)); + cd.setZ (-cd.z ()); + return cd; } QVector3D From fd2749895c4be525de683a2b188153ab6cd5f5b6 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 13 Apr 2020 18:13:17 +0200 Subject: [PATCH 14/27] WIP: foreground light, enhanced navigation ... --- .../view_25d/lay_plugin/layD25ViewUtils.cc | 4 +- .../view_25d/lay_plugin/layD25ViewWidget.cc | 524 ++++++++++++------ .../view_25d/lay_plugin/layD25ViewWidget.h | 9 +- 3 files changed, 355 insertions(+), 182 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc index 9d2bfc359..b2fceddba 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc @@ -122,9 +122,7 @@ hit_point_with_cuboid (const QVector3D &line, const QVector3D &line_dir, const Q for (std::vector >::const_iterator i = cutpoints.begin (); i != cutpoints.end (); ++i) { if (i->first) { double dist = QVector3D::dotProduct (i->second - line, ld_norm); - if (dist < -epsilon) { - // ignore all cutpoints behind us - } else if (min_dist_index < 0) { + if (min_dist_index < 0) { min_dist = dist; min_dist_index = int (i - cutpoints.begin ()); } else if (dist < min_dist) { diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index ef5a708a9..0c3437017 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -45,147 +45,51 @@ namespace lay D25ViewWidget::D25ViewWidget (QWidget *parent) : QOpenGLWidget (parent), - m_shapes_program (0), m_dragging (false), m_rotating (false), m_cam_azimuth (0.0), m_cam_elevation (0.0), m_top_view (false) + m_shapes_program (0) { QSurfaceFormat format; format.setDepthBufferSize (24); format.setSamples (4); // more -> widget extends beyond boundary! + format.setStencilBufferSize (8); + // @@@? format.setVersion (3, 2); + format.setProfile (QSurfaceFormat::CoreProfile); setFormat (format); - m_scale_factor = 1.0; - m_focus_dist = 0.0; + m_zmin = m_zmax = 0.0; + mp_view = 0; } D25ViewWidget::~D25ViewWidget () { // Make sure the context is current and then explicitly // destroy all underlying OpenGL resources. - makeCurrent(); + makeCurrent (); delete m_shapes_program; - doneCurrent(); + doneCurrent (); } void -D25ViewWidget::initializeGL () +D25ViewWidget::reset () { - QOpenGLFunctions::initializeOpenGLFunctions(); + m_scale_factor = 1.0; + m_focus_dist = 0.0; + m_fov = 60.0; + m_cam_azimuth = m_cam_elevation = 0.0; + m_top_view = false; + m_dragging = m_rotating = false; - glEnable (GL_DEPTH_TEST); - glEnable (GL_BLEND); - // @@@ dark background - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // @@@ white background - // @@@ glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); - - static const char *shapes_vertex_shader_source = - "#version 320 es\n" - "#undef lowp\n" - "#undef highp\n" - "#undef mediump\n" - "layout (location = 0) in vec4 posAttr;\n" - "\n" - "void main() {\n" - " gl_Position = posAttr;\n" - "}\n"; - - static const char *shapes_geometry_shader_source = - "#version 320 es\n" - "#undef lowp\n" - "#undef highp\n" - "#undef mediump\n" - "\n" - "uniform vec4 color;\n" - "uniform vec4 ambient;\n" - "uniform vec3 illum;\n" - "out lowp vec4 vertexColor;\n" - "uniform mat4 matrix;\n" - "layout (triangles) in;\n" - "layout (triangle_strip, max_vertices = 3) out;\n" - "\n" - "void main() {\n" - " vec4 p0 = gl_in[0].gl_Position;\n" - " vec4 p1 = gl_in[1].gl_Position;\n" - " vec4 p2 = gl_in[2].gl_Position;\n" - " vec3 n = cross(p2.xyz - p0.xyz, p1.xyz - p0.xyz);\n" - " float dp = dot(normalize(n), illum);\n" - " vertexColor.rgb = color.rgb * (dp * 0.5 + 0.5) - (min(0.0, dp) * 0.5 * ambient.rgb);\n" - " vertexColor.a = 1.0;\n" - " gl_Position = matrix * p0;\n" - " EmitVertex();\n" - " gl_Position = matrix * p1;\n" - " EmitVertex();\n" - " gl_Position = matrix * p2;\n" - " EmitVertex();\n" - " EndPrimitive();\n" - "}\n"; - - static const char *shapes_fragment_shader_source = - "#version 320 es\n" - "#undef lowp\n" - "#undef highp\n" - "#undef mediump\n" - "in lowp vec4 vertexColor;\n" - "out lowp vec4 fragColor;\n" - "void main() {\n" - " fragColor = vertexColor;\n" - "}\n"; - - m_shapes_program = new QOpenGLShaderProgram (this); - if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Vertex, shapes_vertex_shader_source)) { - throw tl::Exception (std::string ("Shapes vertex shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); - } - if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Geometry, shapes_geometry_shader_source)) { - throw tl::Exception (std::string ("Shapes geometry shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); - } - if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Fragment, shapes_fragment_shader_source)) { - throw tl::Exception (std::string ("Shapes fragment shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); - } - if (! m_shapes_program->link ()) { - throw tl::Exception (std::string ("Shapes shader program linking failed failed:\n") + tl::to_string (m_shapes_program->log ())); - } - - // grid plane shader source - - static const char *gridplan_vertex_shader_source = - "#version 320 es\n" - "#undef lowp\n" - "#undef highp\n" - "#undef mediump\n" - "layout (location = 0) in vec4 posAttr;\n" - "uniform mat4 matrix;\n" - "\n" - "void main() {\n" - " gl_Position = matrix * posAttr;\n" - "}\n"; - - static const char *gridplan_fragment_shader_source = - "#version 320 es\n" - "#undef lowp\n" - "#undef highp\n" - "#undef mediump\n" - "uniform lowp vec4 color;\n" - "out lowp vec4 fragColor;\n" - "void main() {\n" - " fragColor = color;\n" - "}\n"; - - m_gridplane_program = new QOpenGLShaderProgram (this); - if (! m_gridplane_program->addShaderFromSourceCode (QOpenGLShader::Vertex, gridplan_vertex_shader_source)) { - throw tl::Exception (std::string ("Grid plane vertex shader compilation failed:\n") + tl::to_string (m_gridplane_program->log ())); - } - if (! m_gridplane_program->addShaderFromSourceCode (QOpenGLShader::Fragment, gridplan_fragment_shader_source)) { - throw tl::Exception (std::string ("Grid plane fragment shader compilation failed:\n") + tl::to_string (m_gridplane_program->log ())); - } - if (! m_gridplane_program->link ()) { - throw tl::Exception (std::string ("Grid plane shader program linking failed:\n") + tl::to_string (m_gridplane_program->log ())); - } + refresh (); } void D25ViewWidget::wheelEvent (QWheelEvent *event) { + if (event->angleDelta ().y () == 0) { + return; + } + double px = (event->pos ().x () - width () / 2) * 2.0 / width (); double py = -(event->pos ().y () - height () / 2) * 2.0 / height (); @@ -193,15 +97,14 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); // by definition the ray goes through the camera position - float focal_length = 2.0; - QVector3D hp = hit_point_with_scene (cam_position () + focal_length * ray.second, ray.second); + QVector3D hp = hit_point_with_scene (ray.second); - if (false /*@@@*/ && (event->modifiers () & Qt::ShiftModifier)) { + if (event->modifiers () & Qt::ControlModifier) { - // "Shift" is closeup + // "Ctrl" is closeup double f = event->angleDelta ().y () * (1.0 / (90 * 8)); - m_displacement += -(f / m_scale_factor) * cam_position ().length () * ray.second; + m_displacement += -((f / m_scale_factor) * cam_dist ()) * ray.second; } else { @@ -212,8 +115,8 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) QVector3D initial_displacement = m_displacement; QVector3D displacement = m_displacement; - displacement += hp * (1.0 - f) / (f * m_scale_factor); m_scale_factor *= f; + displacement += hp * (1.0 - f) / m_scale_factor; // normalize the scene translation so the scene does not "flee" @@ -227,7 +130,7 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) } - update_cam_trans (); + refresh (); } void @@ -235,7 +138,7 @@ D25ViewWidget::keyPressEvent (QKeyEvent *event) { if (event->key () == Qt::Key_Shift) { m_top_view = true; - update_cam_trans (); + refresh (); } } @@ -244,19 +147,25 @@ D25ViewWidget::keyReleaseEvent (QKeyEvent *event) { if (event->key () == Qt::Key_Shift) { m_top_view = false; - update_cam_trans (); + refresh (); } } QVector3D -D25ViewWidget::hit_point_with_scene (const QVector3D &line, const QVector3D &line_dir) +D25ViewWidget::hit_point_with_scene (const QVector3D &line_dir) { + double min_focus_dist = 0.5; + QVector3D corner = (QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())) + m_displacement) * m_scale_factor; QVector3D dim = QVector3D (m_bbox.width (), m_zmax - m_zmin, m_bbox.height ()) * m_scale_factor; + QVector3D line = cam_position (); std::pair hp = lay::hit_point_with_cuboid (line, line_dir, corner, dim); if (! hp.first) { - return line; + return line + line_dir * min_focus_dist; + } else if (QVector3D::dotProduct (line_dir, hp.second - line) < min_focus_dist) { + // limit to min focus distance (not behind) + return line + line_dir * min_focus_dist; } else { return hp.second; } @@ -279,13 +188,27 @@ D25ViewWidget::mousePressEvent (QMouseEvent *event) m_start_displacement = m_displacement; m_focus_dist = 2.0; + m_hit_point = QVector3D (); - if (m_dragging || m_rotating) { + if (m_dragging) { - QVector3D cd = cam_direction (); - QVector3D cp = cam_position (); - QVector3D hp = hit_point_with_scene (cp + m_focus_dist * cd, cd); - m_focus_dist = std::max (m_focus_dist, double ((cp - hp).length ())); + // by definition the ray goes through the camera position + QVector3D hp = hit_point_with_scene (cam_direction ()); + + m_focus_dist = std::max (m_focus_dist, double ((m_start_cam_position - hp).length ())); + + } else if (m_rotating) { + + double px = (event->pos ().x () - width () / 2) * 2.0 / width (); + double py = -(event->pos ().y () - height () / 2) * 2.0 / height (); + + // compute vector of line of sight + std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); + + // by definition the ray goes through the camera position + m_hit_point = hit_point_with_scene (ray.second); + + m_focus_dist = std::max (m_focus_dist, double ((m_start_cam_position - m_hit_point).length ())); } } @@ -299,42 +222,65 @@ D25ViewWidget::mouseReleaseEvent (QMouseEvent * /*event*/) void D25ViewWidget::mouseMoveEvent (QMouseEvent *event) { + if (! m_dragging && ! m_rotating) { + return; + } + if (m_dragging) { - // for the chosen perspective transformation: - double cal = 0.6 * m_focus_dist; - QPoint d = event->pos () - m_start_pos; - double f = cal * 2.0 / double (height ()); + double f = tan ((cam_fov () / 2) / 180.0 * M_PI) * m_focus_dist * 2.0 / double (height ()); double dx = d.x () * f; double dy = -d.y () * f; - QVector3D xv (cos (cam_azimuth () * M_PI / 180.0), 0.0, -sin (cam_azimuth () * M_PI / 180.0)); - double re = sin (cam_elevation () * M_PI / 180.0); - QVector3D yv (-re * xv.z (), cos (cam_elevation () * M_PI / 180.0), re * xv.x ()); + QVector3D xv (cos (m_start_cam_azimuth * M_PI / 180.0), 0.0, sin (m_start_cam_azimuth * M_PI / 180.0)); + double re = sin (m_start_cam_elevation * M_PI / 180.0); + QVector3D yv (-re * xv.z (), cos (m_start_cam_elevation * M_PI / 180.0), re * xv.x ()); QVector3D drag = xv * dx + yv * dy; m_displacement = m_start_displacement + drag / m_scale_factor; - update_cam_trans (); - - } else if (m_rotating) { - - // @@@ needs redo ... - // @@@ consider m_top_view - double focus_dist = 4.0; // @@@ + } else { QPoint d = event->pos () - m_start_pos; + double f = tan ((cam_fov () / 2) / 180.0 * M_PI) * m_focus_dist * 2.0 / double (height ()); + double dx = d.x () * f; + double dy = -d.y () * f; - double ax = atan (d.x () / (0.5 * height ())) * 180 / M_PI; - double ay = atan (-d.y () / (0.5 * height ())) * 180 / M_PI; + if (m_hit_point.x () * dx < 0 && (dx + 2.0 * m_hit_point.x ()) * m_hit_point.x () > 0) { - m_cam_elevation = m_start_cam_elevation + ay; - m_cam_azimuth = m_start_cam_azimuth + ax; + double da = asin (dx / m_hit_point.x () - 1.0) * 180.0 / M_PI; +// @@@ printf("@@@ hp=%g,%g,%g drag=%g,%g -> da=%g\n", m_hit_point.x(), m_hit_point.y(), m_hit_point.z(), drag.x(), drag.z(), da); fflush(stdout); + m_cam_azimuth = m_start_cam_azimuth + da; - update_cam_trans (); + } + +#if 0 + // elevation change + if (! m_top_view) { + + dp = m_hit_point + QVector3D (0.0, float (drag.y ()), 0.0); + double de = QVector3D::crossProduct (dp, m_hit_point).length () * (drag.y () > 0 ? 1.0 : -1.0) / (dp.length () * m_hit_point.length ()) * 180.0 / M_PI; + m_cam_elevation = m_start_cam_elevation + de; + + } +#endif } + + refresh (); +} + +double +D25ViewWidget::cam_fov () const +{ + return m_fov; // @@@ +} + +double +D25ViewWidget::cam_dist () const +{ + return 4.0; // @@@ } QVector3D @@ -348,8 +294,7 @@ D25ViewWidget::cam_direction () const QVector3D D25ViewWidget::cam_position () const { - double focus_dist = 4.0; // @@@ - return cam_direction () * -focus_dist; + return cam_direction () * -cam_dist (); } double @@ -367,10 +312,9 @@ D25ViewWidget::cam_elevation () const QMatrix4x4 D25ViewWidget::cam_perspective () const { - double focus_dist = 4.0; // @@@ QMatrix4x4 t; - t.perspective (60.0f, float (width ()) / float (height ()), 0.1f, 100.0f); - t.translate (QVector3D (0.0, 0.0, -focus_dist)); + t.perspective (cam_fov (), float (width ()) / float (height ()), 0.1f, 10000.0f); + t.translate (QVector3D (0.0, 0.0, -cam_dist ())); return t; } @@ -384,7 +328,7 @@ D25ViewWidget::cam_trans () const } void -D25ViewWidget::update_cam_trans () +D25ViewWidget::refresh () { QVector3D cp = cam_position (); @@ -399,12 +343,9 @@ D25ViewWidget::attach_view (LayoutView *view) if (mp_view != view) { mp_view = view; - m_layers.clear (); - m_vertex_chunks.clear (); - if (mp_view) { - prepare_view (); - } + prepare_view (); + reset (); } } @@ -412,12 +353,20 @@ D25ViewWidget::attach_view (LayoutView *view) void D25ViewWidget::prepare_view () { - double z = 0.0, dz = 0.2; // @@@ + m_layers.clear (); + m_vertex_chunks.clear (); m_bbox = db::DBox (); 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; + } + + double z = 0.0, dz = 0.2; // @@@ + for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { if (! lp->has_children () && lp->visible (true) && lp->cellview_index () >= 0 && lp->cellview_index () < int (mp_view->cellviews ())) { @@ -427,11 +376,9 @@ D25ViewWidget::prepare_view () m_vertex_chunks.push_back (chunks_type ()); LayerInfo info; - // @@@ use alpha? info.color[0] = ((color >> 16) & 0xff) / 255.0f; info.color[1] = ((color >> 8) & 0xff) / 255.0f; info.color[2] = (color & 0xff) / 255.0f; - info.color[3] = 1.0; info.vertex_chunk = &m_vertex_chunks.back (); m_layers.push_back (info); @@ -627,20 +574,178 @@ D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layo } } +static std::pair find_grid (double v) +{ + for (int p = -12; p < 12; ++p) { + double g10 = pow (10, double (p)); + if (v > 100 * g10) { + continue; + } else if (v < 10 * g10) { + return std::make_pair (g10, g10); + } else if (v < 20 * g10) { + return std::make_pair (g10, g10 * 0.1); + } else if (v < 50 * g10) { + return std::make_pair (2.0 * g10, g10); + } else { + return std::make_pair (5.0 * g10, g10); + } + } + + return std::make_pair (v, v); +} + +void +D25ViewWidget::initializeGL () +{ + QOpenGLFunctions::initializeOpenGLFunctions(); + + glEnable (GL_BLEND); + // @@@ dark background + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // @@@ white background + // @@@ glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); + + static const char *shapes_vertex_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "layout (location = 0) in vec4 posAttr;\n" + "\n" + "void main() {\n" + " gl_Position = posAttr;\n" + "}\n"; + + static const char *shapes_geometry_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "\n" + "uniform vec4 color;\n" + "uniform vec4 ambient;\n" + "uniform vec3 illum;\n" + "out lowp vec4 vertexColor;\n" + "uniform mat4 geo_matrix;\n" + "uniform mat4 cam_matrix;\n" + "layout (triangles) in;\n" + "layout (triangle_strip, max_vertices = 3) out;\n" + "\n" + "void main() {\n" + " vec4 p0 = gl_in[0].gl_Position;\n" + " vec4 p1 = gl_in[1].gl_Position;\n" + " vec4 p2 = gl_in[2].gl_Position;\n" + " vec3 n = cross(p2.xyz - p0.xyz, p1.xyz - p0.xyz);\n" + " float dp = dot(normalize(n), illum);\n" + " vertexColor = color * (dp * 0.5 + 0.5) - (min(0.0, dp) * 0.5 * ambient);\n" + " vertexColor.a = 1.0;\n" + " gl_Position = cam_matrix * geo_matrix * p0;\n" + " EmitVertex();\n" + " gl_Position = cam_matrix * geo_matrix * p1;\n" + " EmitVertex();\n" + " gl_Position = cam_matrix * geo_matrix * p2;\n" + " EmitVertex();\n" + " EndPrimitive();\n" + "}\n"; + + static const char *shapes_fragment_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "in lowp vec4 vertexColor;\n" + "out lowp vec4 fragColor;\n" + "\n" + "vec4 color_by_z(lowp vec4 c, highp float z) {\n" + " lowp vec4 mist_color = vec4(c.g * 0.4, c.g * 0.4, c.g * 0.4, 1.0);\n" + " highp float d = 0.12;\n" // d + dd/2 = 0.15 = 1/? + " highp float dd = 0.06;\n" + " highp float f = 1.0;\n" + " if (z < d - dd) {\n" + " f = 0.0;\n" + " } else if (z < d + dd) {\n" + " f = (z - (d - dd)) / (2.0 * dd);\n" + " }\n" + " return (1.0 - f) * mist_color + f * c;\n" + "};\n" + "\n" + "void main() {\n" + " fragColor = color_by_z(vertexColor, gl_FragCoord.w);\n" + "}\n"; + + m_shapes_program = new QOpenGLShaderProgram (this); + if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Vertex, shapes_vertex_shader_source)) { + throw tl::Exception (std::string ("Shapes vertex shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); + } + if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Geometry, shapes_geometry_shader_source)) { + throw tl::Exception (std::string ("Shapes geometry shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); + } + if (! m_shapes_program->addShaderFromSourceCode (QOpenGLShader::Fragment, shapes_fragment_shader_source)) { + throw tl::Exception (std::string ("Shapes fragment shader compilation failed:\n") + tl::to_string (m_shapes_program->log ())); + } + if (! m_shapes_program->link ()) { + throw tl::Exception (std::string ("Shapes shader program linking failed failed:\n") + tl::to_string (m_shapes_program->log ())); + } + + // grid plane shader source + + static const char *gridplan_vertex_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "layout (location = 0) in vec4 posAttr;\n" + "uniform mat4 matrix;\n" + "\n" + "vec4 color_by_z(vec4 face_color, highp float z) {\n" + " vec4 mist_color = vec4(1.0, 1.0, 1.0, 1.0);\n" + " highp float d = -2.309;\n" // tan(camera_fov/2)*camera_dist + " highp float dd = 0.0;\n" + " highp float f = 1.0;\n" + " if (z < d - dd) {\n" + " f = 0.0;\n" + " } else if (z < d + dd) {\n" + " f = (z - (d - dd)) / (2.0 * dd);\n" + " }\n" + " return (1.0 - f) * mist_color + f * face_color;\n" + "};\n" + "\n" + "void main() {\n" + " gl_Position = matrix * posAttr;\n" + "}\n"; + + static const char *gridplan_fragment_shader_source = + "#version 320 es\n" + "#undef lowp\n" + "#undef highp\n" + "#undef mediump\n" + "uniform lowp vec4 color;\n" + "out lowp vec4 fragColor;\n" + "void main() {\n" + " fragColor = color;\n" + "}\n"; + + m_gridplane_program = new QOpenGLShaderProgram (this); + if (! m_gridplane_program->addShaderFromSourceCode (QOpenGLShader::Vertex, gridplan_vertex_shader_source)) { + throw tl::Exception (std::string ("Grid plane vertex shader compilation failed:\n") + tl::to_string (m_gridplane_program->log ())); + } + if (! m_gridplane_program->addShaderFromSourceCode (QOpenGLShader::Fragment, gridplan_fragment_shader_source)) { + throw tl::Exception (std::string ("Grid plane fragment shader compilation failed:\n") + tl::to_string (m_gridplane_program->log ())); + } + if (! m_gridplane_program->link ()) { + throw tl::Exception (std::string ("Grid plane shader program linking failed:\n") + tl::to_string (m_gridplane_program->log ())); + } +} + void D25ViewWidget::paintGL () { - printf("@@@ width=%d,height=%d\n", width(),height()); // @@@ const qreal retinaScale = devicePixelRatio (); glViewport (0, 0, width () * retinaScale, height () * retinaScale); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // @@@ white background: glClearColor (1.0, 1.0, 1.0, 1.0); - const int positions = 0; - - m_shapes_program->bind (); - QMatrix4x4 scene_trans; // provide the displacement and scaling (in this order!) @@ -649,13 +754,19 @@ D25ViewWidget::paintGL () // this way we can use y as z coordinate when drawing scene_trans.scale (1.0, 1.0, -1.0); - m_shapes_program->setUniformValue ("matrix", cam_perspective () * cam_trans () * scene_trans); + const int positions = 0; + + m_shapes_program->bind (); + + m_shapes_program->setUniformValue ("geo_matrix", cam_trans () * scene_trans); + m_shapes_program->setUniformValue ("cam_matrix", cam_perspective ()); // NOTE: z axis of illum points towards the scene because we include the z inversion in the scene transformation matrix m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); m_shapes_program->setUniformValue ("ambient", QVector4D (0.5, 0.5, 0.5, 0.5)); + glEnable (GL_DEPTH_TEST); glEnableVertexAttribArray (positions); for (std::list::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { @@ -675,24 +786,82 @@ D25ViewWidget::paintGL () m_gridplane_program->bind (); + glEnable (GL_DEPTH_TEST); glEnableVertexAttribArray (positions); - // @@@ m_gridplane_program->setUniformValue ("matrix", m_cam_trans * m_scene_trans); - m_gridplane_program->setUniformValue ("matrix", QMatrix4x4 ()); // @@@ + m_gridplane_program->setUniformValue ("matrix", cam_perspective () * cam_trans () * scene_trans); + + std::pair gg = find_grid (std::max (m_bbox.width (), m_bbox.height ())); + double gminor = gg.second, gmajor = gg.first; + + double margin = std::max (m_bbox.width (), m_bbox.height ()) * 0.02; + double l = m_bbox.left () - margin; + double r = m_bbox.right () + margin; + double b = m_bbox.bottom () - margin; + double t = m_bbox.top () + margin; // @@@ + // major and minor grid lines + + GLfloat gridline_vertices[6000]; + size_t nmax = sizeof (gridline_vertices) / sizeof (GLfloat); + + const double epsilon = 1e-6; + + for (int major = 0; major < 2; ++major) { + + m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, major ? 0.25f : 0.15f); + + size_t index = 0; + double x, y; + double step = (major ? gmajor : gminor); + + x = ceil (l / step) * step; + for ( ; index < nmax && x < r - step * epsilon; x += step) { + if ((fabs (floor (x / gmajor + 0.5) * gmajor - x) < epsilon) == (major != 0)) { + gridline_vertices [index++] = x; + gridline_vertices [index++] = 0.0; + gridline_vertices [index++] = b; + gridline_vertices [index++] = x; + gridline_vertices [index++] = 0.0; + gridline_vertices [index++] = t; + } + } + + y = ceil (b / step) * step; + for ( ; index < nmax && y < t - step * epsilon; y += step) { + if ((fabs (floor (y / gmajor + 0.5) * gmajor - y) < epsilon) == (major != 0)) { + gridline_vertices [index++] = l; + gridline_vertices [index++] = 0.0; + gridline_vertices [index++] = y; + gridline_vertices [index++] = r; + gridline_vertices [index++] = 0.0; + gridline_vertices [index++] = y; + } + } + + glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, gridline_vertices); + + glLineWidth (2.0); + glDrawArrays (GL_LINES, 0, index / 3); + + } + + // base plane + GLfloat plane_vertices[] = { - -1.05, 0.0, -2.05, -1.05, 0.0, 0.05, 1.05, 0.0, 0.05, - -1.05, 0.0, -2.05, 1.05, 0.0, 0.05, 1.05, 0.0, -2.05 + float (l), 0.0f, float (b), float (l), 0.0f, float (t), float (r), 0.0f, float (t), + float (l), 0.0f, float (b), float (r), 0.0f, float (t), float (r), 0.0f, float (b) }; - m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.2f); + m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.1f); glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, plane_vertices); glDrawArrays (GL_TRIANGLES, 0, 6); +#if 0 #if 0 GLfloat gridline_vertices[] = { -1.0, 0.0, -2.0, -1.0, 0.0, 0.0, @@ -743,6 +912,7 @@ D25ViewWidget::paintGL () glLineWidth (2.0); glDrawArrays (GL_LINES, 0, 36); +#endif glDisableVertexAttribArray (positions); @@ -752,7 +922,7 @@ D25ViewWidget::paintGL () void D25ViewWidget::resizeGL (int /*w*/, int /*h*/) { - update_cam_trans (); + refresh (); } } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index c467510d8..e89404360 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -76,6 +76,8 @@ private: bool m_top_view; QVector3D m_displacement; double m_focus_dist; + double m_fov; + QVector3D m_hit_point; QPoint m_start_pos; QVector3D m_start_cam_position; double m_start_cam_azimuth, m_start_cam_elevation; @@ -97,18 +99,21 @@ private: void paintGL (); void resizeGL (int w, int h); - void update_cam_trans (); + void refresh (); + void reset (); void prepare_view (); void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop); void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop); void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop); - QVector3D hit_point_with_scene(const QVector3D &line, const QVector3D &line_dir); + QVector3D hit_point_with_scene(const QVector3D &line_dir); double cam_elevation () const; double cam_azimuth () const; QVector3D cam_position () const; QVector3D cam_direction () const; QMatrix4x4 cam_perspective () const; QMatrix4x4 cam_trans () const; + double cam_dist () const; + double cam_fov () const; }; } From 9c005683014149778d80a90ca2e9d7dcb3b87b9d Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 13 Apr 2020 21:34:32 +0200 Subject: [PATCH 15/27] WIP: compass, navigation, bug fixes. --- .../view_25d/lay_plugin/layD25ViewUtils.cc | 2 +- .../view_25d/lay_plugin/layD25ViewWidget.cc | 198 +++++++++++------- 2 files changed, 121 insertions(+), 79 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc index b2fceddba..23cb6c951 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc @@ -66,7 +66,7 @@ cutpoint_line_with_face (const QVector3D &line, const QVector3D &dir, const QVec static bool somewhat_perpendicular (const QVector3D &a, const QVector3D &b) { // returns true if a and b are perpendicular within 30 degree - return fabs (QVector3D::dotProduct (a, b) < 0.5 * a.length () * b.length ()); + return fabs (QVector3D::dotProduct (a, b)) < 0.5 * a.length () * b.length (); } static std::pair plane_or_face (const QVector3D &line, const QVector3D &line_dir, const QVector3D &corner, const QVector3D &u, const QVector3D &v, bool face) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 0c3437017..d8170443e 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -104,7 +104,7 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) // "Ctrl" is closeup double f = event->angleDelta ().y () * (1.0 / (90 * 8)); - m_displacement += -((f / m_scale_factor) * cam_dist ()) * ray.second; + m_displacement += -((f / m_scale_factor) * std::min (cam_dist (), double ((cam_position () - hp).length ()))) * ray.second; } else { @@ -195,7 +195,8 @@ D25ViewWidget::mousePressEvent (QMouseEvent *event) // by definition the ray goes through the camera position QVector3D hp = hit_point_with_scene (cam_direction ()); - m_focus_dist = std::max (m_focus_dist, double ((m_start_cam_position - hp).length ())); + m_focus_dist = std::max (m_focus_dist, double ((cam_position () - hp).length ())); + m_hit_point = cam_position () + cam_direction () * m_focus_dist; } else if (m_rotating) { @@ -206,9 +207,10 @@ D25ViewWidget::mousePressEvent (QMouseEvent *event) std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); // by definition the ray goes through the camera position - m_hit_point = hit_point_with_scene (ray.second); + QVector3D hp = hit_point_with_scene (ray.second); - m_focus_dist = std::max (m_focus_dist, double ((m_start_cam_position - m_hit_point).length ())); + m_focus_dist = std::max (m_focus_dist, double ((cam_position () - hp).length ())); + m_hit_point = cam_position () + ray.second * m_focus_dist; } } @@ -242,11 +244,26 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) } else { + double focus_dist = 2.0; + QPoint d = event->pos () - m_start_pos; - double f = tan ((cam_fov () / 2) / 180.0 * M_PI) * m_focus_dist * 2.0 / double (height ()); + double f = tan ((cam_fov () / 2) / 180.0 * M_PI) * focus_dist * 2.0 / double (height ()); double dx = d.x () * f; double dy = -d.y () * f; + if (! m_top_view) { + + double da = dx / (cam_dist () - focus_dist) * 180.0 / M_PI; + m_cam_azimuth = m_start_cam_azimuth + da; + + double de = dy / (cam_dist () - focus_dist) * 180.0 / M_PI; + m_cam_elevation = m_start_cam_elevation + de; + +printf("@@@ -> dy=%g de=%g focus_dist=%g\n", dy, de, focus_dist); fflush(stdout); + + } + +#if 0 if (m_hit_point.x () * dx < 0 && (dx + 2.0 * m_hit_point.x ()) * m_hit_point.x () > 0) { double da = asin (dx / m_hit_point.x () - 1.0) * 180.0 / M_PI; @@ -254,6 +271,7 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) m_cam_azimuth = m_start_cam_azimuth + da; } +#endif #if 0 // elevation change @@ -740,13 +758,16 @@ D25ViewWidget::initializeGL () void D25ViewWidget::paintGL () { + GLfloat vertices[6000]; + size_t nmax = sizeof (vertices) / sizeof (GLfloat); + const qreal retinaScale = devicePixelRatio (); glViewport (0, 0, width () * retinaScale, height () * retinaScale); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // @@@ white background: glClearColor (1.0, 1.0, 1.0, 1.0); - QMatrix4x4 scene_trans; + QMatrix4x4 scene_trans, scene_trans_wo_y; // provide the displacement and scaling (in this order!) scene_trans.scale (m_scale_factor); @@ -754,6 +775,9 @@ D25ViewWidget::paintGL () // this way we can use y as z coordinate when drawing scene_trans.scale (1.0, 1.0, -1.0); + scene_trans_wo_y = scene_trans; + scene_trans_wo_y.translate (QVector3D (0.0, -m_displacement.y (), 0.0)); + const int positions = 0; m_shapes_program->bind (); @@ -789,7 +813,83 @@ D25ViewWidget::paintGL () glEnable (GL_DEPTH_TEST); glEnableVertexAttribArray (positions); - m_gridplane_program->setUniformValue ("matrix", cam_perspective () * cam_trans () * scene_trans); + // draw pivot compass + + m_gridplane_program->setUniformValue ("matrix", cam_perspective () * cam_trans ()); + + size_t index = 0; + + double compass_rad = 0.3; + double compass_bars = 0.4; + + vertices[index++] = -compass_bars; + vertices[index++] = 0.0; + vertices[index++] = 0.0; + + vertices[index++] = compass_bars; + vertices[index++] = 0.0; + vertices[index++] = 0.0; + + vertices[index++] = 0.0; + vertices[index++] = 0.0; + vertices[index++] = -compass_bars; + + vertices[index++] = 0.0; + vertices[index++] = 0.0; + vertices[index++] = compass_bars; + + int ncircle = 64; + double x = compass_rad, z = 0.0; + double da = 1.0 / double (ncircle) * M_PI * 2.0; + + for (int i = 0; i < ncircle; ++i) { + + double a = double (i + 1) * da; + double xx = compass_rad * cos (a); + double zz = compass_rad * sin (a); + + vertices[index++] = x; + vertices[index++] = 0.0; + vertices[index++] = z; + + vertices[index++] = xx; + vertices[index++] = 0.0; + vertices[index++] = zz; + + x = xx; + z = zz; + + } + + m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.25f); + + glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, vertices); + + glLineWidth (2.0); + glDrawArrays (GL_LINES, 0, index / 3); + + index = 0; + + // arrow + vertices[index++] = -0.25 * compass_rad; + vertices[index++] = 0.0; + vertices[index++] = 0.6 * compass_rad; + + vertices[index++] = 0.0; + vertices[index++] = 0.0; + vertices[index++] = -0.8 * compass_rad; + + vertices[index++] = 0.25 * compass_rad; + vertices[index++] = 0.0; + vertices[index++] = 0.6 * compass_rad; + + glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, vertices); + + glDrawArrays (GL_TRIANGLES, 0, index / 3); + + // draw base plane + + m_gridplane_program->setUniformValue ("matrix", cam_perspective () * cam_trans () * scene_trans_wo_y); std::pair gg = find_grid (std::max (m_bbox.width (), m_bbox.height ())); double gminor = gg.second, gmajor = gg.first; @@ -804,9 +904,6 @@ D25ViewWidget::paintGL () // major and minor grid lines - GLfloat gridline_vertices[6000]; - size_t nmax = sizeof (gridline_vertices) / sizeof (GLfloat); - const double epsilon = 1e-6; for (int major = 0; major < 2; ++major) { @@ -820,36 +917,34 @@ D25ViewWidget::paintGL () x = ceil (l / step) * step; for ( ; index < nmax && x < r - step * epsilon; x += step) { if ((fabs (floor (x / gmajor + 0.5) * gmajor - x) < epsilon) == (major != 0)) { - gridline_vertices [index++] = x; - gridline_vertices [index++] = 0.0; - gridline_vertices [index++] = b; - gridline_vertices [index++] = x; - gridline_vertices [index++] = 0.0; - gridline_vertices [index++] = t; + vertices [index++] = x; + vertices [index++] = 0.0; + vertices [index++] = b; + vertices [index++] = x; + vertices [index++] = 0.0; + vertices [index++] = t; } } y = ceil (b / step) * step; for ( ; index < nmax && y < t - step * epsilon; y += step) { if ((fabs (floor (y / gmajor + 0.5) * gmajor - y) < epsilon) == (major != 0)) { - gridline_vertices [index++] = l; - gridline_vertices [index++] = 0.0; - gridline_vertices [index++] = y; - gridline_vertices [index++] = r; - gridline_vertices [index++] = 0.0; - gridline_vertices [index++] = y; + vertices [index++] = l; + vertices [index++] = 0.0; + vertices [index++] = y; + vertices [index++] = r; + vertices [index++] = 0.0; + vertices [index++] = y; } } - glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, gridline_vertices); + glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, vertices); glLineWidth (2.0); glDrawArrays (GL_LINES, 0, index / 3); } - // base plane - GLfloat plane_vertices[] = { float (l), 0.0f, float (b), float (l), 0.0f, float (t), float (r), 0.0f, float (t), float (l), 0.0f, float (b), float (r), 0.0f, float (t), float (r), 0.0f, float (b) @@ -861,59 +956,6 @@ D25ViewWidget::paintGL () glDrawArrays (GL_TRIANGLES, 0, 6); -#if 0 -#if 0 - GLfloat gridline_vertices[] = { - -1.0, 0.0, -2.0, -1.0, 0.0, 0.0, - -0.75, 0.0, -2.0, -0.75, 0.0, 0.0, - -0.5, 0.0, -2.0, -0.5, 0.0, 0.0, - -0.25, 0.0, -2.0, -0.25, 0.0, 0.0, - 0.0, 0.0, -2.0, 0.0, 0.0, 0.0, - 0.25, 0.0, -2.0, 0.25, 0.0, 0.0, - 0.5, 0.0, -2.0, 0.5, 0.0, 0.0, - 0.75, 0.0, -2.0, 0.75, 0.0, 0.0, - 1.0, 0.0, -2.0, 1.0, 0.0, 0.0, - 1.0, 0.0, -2.0, -1.0, 0.0, -2.0, - 1.0, 0.0, -1.75, -1.0, 0.0, -1.75, - 1.0, 0.0, -1.5 , -1.0, 0.0, -1.5, - 1.0, 0.0, -1.25, -1.0, 0.0, -1.25, - 1.0, 0.0, -1.0, -1.0, 0.0, -1.0, - 1.0, 0.0, -0.75, -1.0, 0.0, -0.75, - 1.0, 0.0, -0.5 , -1.0, 0.0, -0.5, - 1.0, 0.0, -0.25, -1.0, 0.0, -0.25, - 1.0, 0.0, 0.0, -1.0, 0.0, 0.0 - }; -#else - GLfloat gridline_vertices[] = { - -1.0, -1.0, 0.0, -1.0, 1.0, 0.0, - -0.75, -1.0, 0.0, -0.75, 1.0, 0.0, - -0.5, -1.0, 0.0, -0.5, 1.0, 0.0, - -0.25, -1.0, 0.0, -0.25, 1.0, 0.0, - 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, - 0.25, -1.0, 0.0, 0.25, 1.0, 0.0, - 0.5, -1.0, 0.0, 0.5, 1.0, 0.0, - 0.75, -1.0, 0.0, 0.75, 1.0, 0.0, - 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, - 1.0, -1.0, 0.0, -1.0, -1.0, 0.0, - 1.0, -0.75, 0.0, -1.0, -0.75, 0.0, - 1.0, -0.5, 0.0, -1.0, -0.5, 0.0, - 1.0, -0.25, 0.0, -1.0, -0.25, 0.0, - 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, - 1.0, 0.25, 0.0, -1.0, 0.25, 0.0, - 1.0, 0.5, 0.0, -1.0, 0.5, 0.0, - 1.0, 0.75, 0.0, -1.0, 0.75, 0.0, - 1.0, 1.0, 0.0, -1.0, 1.0, 0.0 - }; -#endif - - m_shapes_program->setUniformValue ("vertexColor", 1.0, 1.0, 1.0, 0.2f); - - glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, gridline_vertices); - - glLineWidth (2.0); - glDrawArrays (GL_LINES, 0, 36); -#endif - glDisableVertexAttribArray (positions); m_shapes_program->release (); From 2ec712b1040bf1f222b360b778d39af33cac957c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 13 Apr 2020 22:18:52 +0200 Subject: [PATCH 16/27] Implementation starts to make sense. TODO: major refactoring, a lot of utility functions like fit, ... --- .../view_25d/lay_plugin/layD25ViewWidget.cc | 78 ++++++++----------- 1 file changed, 34 insertions(+), 44 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index d8170443e..fa6edca8f 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -75,7 +75,7 @@ D25ViewWidget::reset () { m_scale_factor = 1.0; m_focus_dist = 0.0; - m_fov = 60.0; + m_fov = 90.0; m_cam_azimuth = m_cam_elevation = 0.0; m_top_view = false; m_dragging = m_rotating = false; @@ -138,6 +138,8 @@ D25ViewWidget::keyPressEvent (QKeyEvent *event) { if (event->key () == Qt::Key_Shift) { m_top_view = true; + m_dragging = false; + m_rotating = false; refresh (); } } @@ -147,6 +149,8 @@ D25ViewWidget::keyReleaseEvent (QKeyEvent *event) { if (event->key () == Qt::Key_Shift) { m_top_view = false; + m_dragging = false; + m_rotating = false; refresh (); } } @@ -195,7 +199,7 @@ D25ViewWidget::mousePressEvent (QMouseEvent *event) // by definition the ray goes through the camera position QVector3D hp = hit_point_with_scene (cam_direction ()); - m_focus_dist = std::max (m_focus_dist, double ((cam_position () - hp).length ())); + m_focus_dist = (cam_position () - hp).length (); m_hit_point = cam_position () + cam_direction () * m_focus_dist; } else if (m_rotating) { @@ -219,6 +223,7 @@ void D25ViewWidget::mouseReleaseEvent (QMouseEvent * /*event*/) { m_dragging = false; + m_rotating = false; } void @@ -244,46 +249,39 @@ D25ViewWidget::mouseMoveEvent (QMouseEvent *event) } else { - double focus_dist = 2.0; - - QPoint d = event->pos () - m_start_pos; - double f = tan ((cam_fov () / 2) / 180.0 * M_PI) * focus_dist * 2.0 / double (height ()); - double dx = d.x () * f; - double dy = -d.y () * f; - if (! m_top_view) { + // fixed focus point for rotation + double focus_dist = 2.0; + + QPoint d = event->pos () - m_start_pos; + double f = tan ((cam_fov () / 2) / 180.0 * M_PI) * focus_dist * 2.0 / double (height ()); + double dx = d.x () * f; + double dy = -d.y () * f; + double da = dx / (cam_dist () - focus_dist) * 180.0 / M_PI; m_cam_azimuth = m_start_cam_azimuth + da; double de = dy / (cam_dist () - focus_dist) * 180.0 / M_PI; m_cam_elevation = m_start_cam_elevation + de; -printf("@@@ -> dy=%g de=%g focus_dist=%g\n", dy, de, focus_dist); fflush(stdout); + } else { + + // simple change of azimuth only - with center in the middle + + QPoint m = event->pos () - m_start_pos; + QVector3D p (m_start_pos.x () - width () / 2, -m_start_pos.y () + height () / 2, 0); + QVector3D d (m.x (), -m.y (), 0); + + double cp = QVector3D::crossProduct (p, p + d).z () / p.length () / (p + d).length (); + cp = std::max (-1.0, std::min (1.0, cp)); + double da = asin (cp) * 180.0 / M_PI; + + m_cam_azimuth += da; + m_start_pos = event->pos (); } -#if 0 - if (m_hit_point.x () * dx < 0 && (dx + 2.0 * m_hit_point.x ()) * m_hit_point.x () > 0) { - - double da = asin (dx / m_hit_point.x () - 1.0) * 180.0 / M_PI; -// @@@ printf("@@@ hp=%g,%g,%g drag=%g,%g -> da=%g\n", m_hit_point.x(), m_hit_point.y(), m_hit_point.z(), drag.x(), drag.z(), da); fflush(stdout); - m_cam_azimuth = m_start_cam_azimuth + da; - - } -#endif - -#if 0 - // elevation change - if (! m_top_view) { - - dp = m_hit_point + QVector3D (0.0, float (drag.y ()), 0.0); - double de = QVector3D::crossProduct (dp, m_hit_point).length () * (drag.y () > 0 ? 1.0 : -1.0) / (dp.length () * m_hit_point.length ()) * 180.0 / M_PI; - m_cam_elevation = m_start_cam_elevation + de; - - } -#endif - } refresh (); @@ -715,19 +713,6 @@ D25ViewWidget::initializeGL () "layout (location = 0) in vec4 posAttr;\n" "uniform mat4 matrix;\n" "\n" - "vec4 color_by_z(vec4 face_color, highp float z) {\n" - " vec4 mist_color = vec4(1.0, 1.0, 1.0, 1.0);\n" - " highp float d = -2.309;\n" // tan(camera_fov/2)*camera_dist - " highp float dd = 0.0;\n" - " highp float f = 1.0;\n" - " if (z < d - dd) {\n" - " f = 0.0;\n" - " } else if (z < d + dd) {\n" - " f = (z - (d - dd)) / (2.0 * dd);\n" - " }\n" - " return (1.0 - f) * mist_color + f * face_color;\n" - "};\n" - "\n" "void main() {\n" " gl_Position = matrix * posAttr;\n" "}\n"; @@ -945,6 +930,11 @@ D25ViewWidget::paintGL () } + l = m_bbox.left (); + r = m_bbox.right (); + b = m_bbox.bottom (); + t = m_bbox.top (); + GLfloat plane_vertices[] = { float (l), 0.0f, float (b), float (l), 0.0f, float (t), float (r), 0.0f, float (t), float (l), 0.0f, float (b), float (r), 0.0f, float (t), float (r), 0.0f, float (b) From f9aa89a0b3e8462be7dd1d4fdca39ea2e289ef54 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 16 Apr 2020 23:14:22 +0200 Subject: [PATCH 17/27] WIP: bugfixes, refactoring. --- src/lay/lay/layResources.qrc | 6 + .../tools/view_25d/lay_plugin/D25View.ui | 253 ++++++- .../tools/view_25d/lay_plugin/layD25Camera.cc | 113 ++++ .../tools/view_25d/lay_plugin/layD25Camera.h | 142 ++++ .../view_25d/lay_plugin/layD25MemChunks.cc | 1 + .../view_25d/lay_plugin/layD25MemChunks.h | 44 ++ .../tools/view_25d/lay_plugin/layD25View.cc | 43 ++ .../tools/view_25d/lay_plugin/layD25View.h | 3 + .../view_25d/lay_plugin/layD25ViewUtils.cc | 2 +- .../view_25d/lay_plugin/layD25ViewWidget.cc | 635 ++++++++---------- .../view_25d/lay_plugin/layD25ViewWidget.h | 75 ++- .../tools/view_25d/lay_plugin/lay_plugin.pro | 6 +- .../view_25d/unit_tests/layD25CameraTests.cc | 102 +++ .../tools/view_25d/unit_tests/unit_tests.pro | 3 +- 14 files changed, 1050 insertions(+), 378 deletions(-) create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc create mode 100644 src/plugins/tools/view_25d/lay_plugin/layD25Camera.h create mode 100644 src/plugins/tools/view_25d/unit_tests/layD25CameraTests.cc diff --git a/src/lay/lay/layResources.qrc b/src/lay/lay/layResources.qrc index abaeec830..195eb763e 100644 --- a/src/lay/lay/layResources.qrc +++ b/src/lay/lay/layResources.qrc @@ -127,6 +127,12 @@ images/folder_12.png images/file_12.png images/empty_12.png + images/fit_front.png + images/fit_back.png + images/fit_left.png + images/fit_right.png + images/fit_top.png + images/fit_bottom.png syntax/ruby.xml diff --git a/src/plugins/tools/view_25d/lay_plugin/D25View.ui b/src/plugins/tools/view_25d/lay_plugin/D25View.ui index 3e8f0fc83..efdbd6365 100644 --- a/src/plugins/tools/view_25d/lay_plugin/D25View.ui +++ b/src/plugins/tools/view_25d/lay_plugin/D25View.ui @@ -6,8 +6,8 @@ 0 0 - 576 - 649 + 854 + 665 @@ -29,17 +29,249 @@ 9 + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + % + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + ... + + + + :/fit_left.png:/fit_left.png + + + + 24 + 24 + + + + true + + + + + + + ... + + + + :/fit_front.png:/fit_front.png + + + + 24 + 24 + + + + true + + + + + + + ... + + + + :/fit_right.png:/fit_right.png + + + + 24 + 24 + + + + true + + + + + + + ... + + + + :/fit_back.png:/fit_back.png + + + + 24 + 24 + + + + true + + + + + + + ... + + + + :/fit_top.png:/fit_top.png + + + + 24 + 24 + + + + true + + + + + + + ... + + + + :/fit_bottom.png:/fit_bottom.png + + + + 24 + 24 + + + + true + + + + + + - - - Qt::Horizontal + + + + 0 + 0 + - - QDialogButtonBox::Close + + QFrame::NoFrame + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Press and hold SHIFT for top view + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + @@ -51,10 +283,9 @@
layD25ViewWidget.h
- - buttonBox - - + + + buttonBox diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc new file mode 100644 index 000000000..3d8fb12ef --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc @@ -0,0 +1,113 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layD25Camera.h" + +#include + +#include "math.h" + +namespace lay +{ + +D25Camera::D25Camera () +{ + init (); +} + +D25Camera::~D25Camera () +{ + // .. nothing yet .. +} + +void +D25Camera::init () +{ + m_fov = 90.0; + m_cam_azimuth = m_cam_elevation = 0.0; + m_top_view = false; +} + +void +D25Camera::camera_reset () +{ + init (); + camera_changed (); +} + +double +D25Camera::cam_fov () const +{ + return m_fov; // @@@ +} + +double +D25Camera::cam_dist () const +{ + return 4.0; // @@@ +} + +QVector3D +D25Camera::cam_direction () const +{ + return cam_trans ().inverted ().map (QVector3D (0, 0, -1)); +} + +QVector3D +D25Camera::cam_position () const +{ + return cam_direction () * -cam_dist (); +} + +double +D25Camera::cam_azimuth () const +{ + return m_cam_azimuth; +} + +double +D25Camera::cam_elevation () const +{ + return m_top_view ? -90.0 : m_cam_elevation; +} + +QMatrix4x4 +D25Camera::cam_perspective () const +{ + QMatrix4x4 t; + t.perspective (cam_fov (), aspect_ratio (), 0.1f, 10000.0f); + t.translate (QVector3D (0.0, 0.0, -cam_dist ())); + return t; +} + +QMatrix4x4 +D25Camera::cam_trans () const +{ + QMatrix4x4 t; + t.rotate (-cam_elevation (), 1.0, 0.0, 0.0); + t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); + return t; +} + +} + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.h b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.h new file mode 100644 index 000000000..22dd780e4 --- /dev/null +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.h @@ -0,0 +1,142 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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_layD25Camera +#define HDR_layD25Camera + +#include "layPluginCommon.h" + +#include +#include + +namespace lay +{ + +class LAY_PLUGIN_PUBLIC D25Camera +{ +public: + D25Camera (); + virtual ~D25Camera (); + + /** + * @brief Gets the position of the camera objective in the scene coordinate system + */ + QVector3D cam_position () const; + + /** + * @brief Gets the direction the camera looks into in the scene coordinate system + */ + QVector3D cam_direction () const; + + /** + * @brief Gets the perspective part of the transformation applied transform scene coordinates into the image plane + * The full transformation for scene to image plane is cam_perspective * cam_trans. + */ + QMatrix4x4 cam_perspective () const; + + /** + * @brief Gets the azimuth/elevation part of the transformation applied transform scene coordinates into the image plane + * The full transformation for scene to image plane is cam_perspective * cam_trans. + */ + QMatrix4x4 cam_trans () const; + + /** + * @brief Gets the distance of the objective in scene coordinates + */ + double cam_dist () const; + + /** + * @brief Gets the field of view of the camera + * The field of view is the objective opening angle. + */ + double cam_fov () const; + + /** + * @brief Gets a flag indicating whether top view is enabled + * In "top view" mode, the elevation is fixed to -90 degree. + */ + bool top_view () const + { + return m_top_view; + } + + /** + * @brief Sets a flag indicating whether top view is enabled + */ + void set_top_view (bool f) + { + m_top_view = f; + camera_changed (); + } + + /** + * @brief Gets the elevation angle + * A negative angle means the camera looks down, a positive angle means it looks up. + */ + double cam_elevation () const; + + /** + * @brief Sets the elevation angle + */ + void set_cam_elevation (double e) + { + m_cam_elevation = e; + camera_changed (); + } + + /** + * @brief Gets the azimuth angle + * ... + */ + double cam_azimuth () const; + + /** + * @brief Sets the azimuth angle + */ + void set_cam_azimuth (double a) + { + m_cam_azimuth = a; + camera_changed (); + } + + /** + * @brief Resets the camera's orientation + */ + void camera_reset (); + +protected: + virtual void camera_changed () { } + virtual double aspect_ratio () const { return 1.0; } + +private: + double m_cam_azimuth, m_cam_elevation; + bool m_top_view; + QVector3D m_displacement; + double m_fov; + + void init (); +}; + +} + +#endif + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc index c80a2d5a7..dfe8fb146 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.cc @@ -21,3 +21,4 @@ */ #include "layD25MemChunks.h" + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h index 034aa5377..945d1338d 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25MemChunks.h @@ -24,6 +24,7 @@ #define HDR_layD25MemChunks #include +#include #include "tlObject.h" #include // for memcpy @@ -31,6 +32,19 @@ namespace lay { +template +struct gl_type2enum +{ + GLenum operator() () const; +}; + +template <> +struct gl_type2enum +{ + GLenum operator() () const { return GL_FLOAT; } +}; + + /** * @brief Provides a semi-contiguous array of objects * @@ -201,6 +215,25 @@ public: mp_last_chunk->m_objects [mp_last_chunk->m_len++] = element; } + /** + * @brief Adds two elements + */ + void add (const Obj &e1, const Obj &e2) + { + add (e1); + add (e2); + } + + /** + * @brief Adds three elements + */ + void add (const Obj &e1, const Obj &e2, const Obj &e3) + { + add (e1); + add (e2); + add (e3); + } + /** * @brief begin iterator */ @@ -211,6 +244,17 @@ public: */ iterator end () const { return iterator (); } + /** + * @brief Draw to the given context + */ + void draw_to (QOpenGLFunctions *ctx, GLuint location, GLenum mode) const + { + for (iterator c = begin (); c != end (); ++c) { + ctx->glVertexAttribPointer (location, 3, gl_type2enum () (), GL_FALSE, 0, c->front ()); + ctx->glDrawArrays (mode, 0, c->size () / 3); + } + } + private: chunk *mp_chunks; chunk *mp_last_chunk; diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index fdb5230d9..aa6c587a4 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -31,6 +31,8 @@ namespace lay { +const double initial_elevation = 3.0; + D25View::D25View (QWidget *parent) : QDialog (parent) { @@ -41,6 +43,13 @@ D25View::D25View (QWidget *parent) 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 ())); } D25View::~D25View () @@ -55,6 +64,10 @@ D25View::exec_dialog (lay::LayoutView *view) mp_view.reset (view); 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); + int ret = QDialog::exec (); mp_ui->d25_view->attach_view (0); @@ -62,6 +75,36 @@ D25View::exec_dialog (lay::LayoutView *view) return ret; } +void +D25View::fit_button_clicked () +{ + double azimuth = mp_ui->d25_view->cam_azimuth (); + double elevation = mp_ui->d25_view->cam_elevation (); + + if (sender () == mp_ui->fit_back) { + azimuth = -180.0; + elevation = -initial_elevation; + } else if (sender () == mp_ui->fit_front) { + azimuth = 0.0; + elevation = -initial_elevation; + } else if (sender () == mp_ui->fit_left) { + azimuth = 90.0; + elevation = -initial_elevation; + } else if (sender () == mp_ui->fit_right) { + azimuth = -90.0; + elevation = -initial_elevation; + } else if (sender () == mp_ui->fit_top) { + elevation = -90; + } else if (sender () == mp_ui->fit_bottom) { + elevation = 90; + } + + mp_ui->d25_view->set_cam_azimuth (azimuth); + mp_ui->d25_view->set_cam_elevation (elevation); + + mp_ui->d25_view->fit (); +} + void D25View::accept () { diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.h b/src/plugins/tools/view_25d/lay_plugin/layD25View.h index 78526bd36..207ca7751 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.h @@ -54,6 +54,9 @@ public: protected: void accept (); +private slots: + void fit_button_clicked (); + private: Ui::D25View *mp_ui; tl::weak_ptr mp_view; diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc index 23cb6c951..3fb6e8dca 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewUtils.cc @@ -65,7 +65,7 @@ cutpoint_line_with_face (const QVector3D &line, const QVector3D &dir, const QVec static bool somewhat_perpendicular (const QVector3D &a, const QVector3D &b) { - // returns true if a and b are perpendicular within 30 degree + // returns true if a and b are perpendicular within +/-30 degree return fabs (QVector3D::dotProduct (a, b)) < 0.5 * a.length () * b.length (); } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index fa6edca8f..1a077e786 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -43,6 +43,146 @@ namespace lay // ------------------------------------------------------------------------------ +D25InteractionMode::D25InteractionMode (D25ViewWidget *view) + : mp_view (view) +{ + // .. nothing yet .. +} + +D25InteractionMode::~D25InteractionMode () +{ + // .. nothing yet .. +} + + +// ------------------------------------------------------------------------------ + +class D25PanInteractionMode + : public D25InteractionMode +{ +public: + D25PanInteractionMode (D25ViewWidget *widget, const QPoint &pos) + : D25InteractionMode (widget), m_start_pos (pos) + { + m_start_displacement = widget->displacement (); + + double px = (pos.x () - widget->width () / 2) * 2.0 / widget->width (); + double py = -(pos.y () - widget->height () / 2) * 2.0 / widget->height (); + + // compute vector of line of sight + std::pair ray = camera_normal (view ()->cam_perspective () * view ()->cam_trans (), px, py); + + // by definition the ray goes through the camera position + QVector3D hp = widget->hit_point_with_scene (ray.second); + + m_focus_dist = (widget->cam_position () - hp).length (); + } + + virtual ~D25PanInteractionMode () + { + // .. nothing yet .. + } + + virtual void mouse_move (QMouseEvent *event) + { + QPoint d = event->pos () - m_start_pos; + double f = tan ((view ()->cam_fov () / 2) / 180.0 * M_PI) * m_focus_dist * 2.0 / double (view ()->height ()); + double dx = d.x () * f; + double dy = -d.y () * f; + + QVector3D xv (cos (view ()->cam_azimuth () * M_PI / 180.0), 0.0, sin (view ()->cam_azimuth () * M_PI / 180.0)); + double re = sin (view ()->cam_elevation () * M_PI / 180.0); + QVector3D yv (-re * xv.z (), cos (view ()->cam_elevation () * M_PI / 180.0), re * xv.x ()); + QVector3D drag = xv * dx + yv * dy; + + view ()->set_displacement (m_start_displacement + drag / view ()->scale_factor ()); + } + +private: + QPoint m_start_pos; + double m_focus_dist; + QVector3D m_start_displacement; +}; + +// ------------------------------------------------------------------------------ + +class D25Rotate2DInteractionMode + : public D25InteractionMode +{ +public: + D25Rotate2DInteractionMode (D25ViewWidget *widget, const QPoint &pos) + : D25InteractionMode (widget), m_start_pos (pos) + { + m_start_cam_azimuth = widget->cam_azimuth (); + m_start_cam_elevation = widget->cam_elevation (); + } + + virtual ~D25Rotate2DInteractionMode () + { + // .. nothing yet .. + } + + virtual void mouse_move (QMouseEvent *event) + { + // fixed focus point for rotation + double focus_dist = 2.0; + + QPoint d = event->pos () - m_start_pos; + double f = tan ((view ()->cam_fov () / 2) / 180.0 * M_PI) * focus_dist * 2.0 / double (view ()->height ()); + double dx = d.x () * f; + double dy = -d.y () * f; + + double da = dx / (view ()->cam_dist () - focus_dist) * 180.0 / M_PI; + view ()->set_cam_azimuth (m_start_cam_azimuth + da); + + double de = dy / (view ()->cam_dist () - focus_dist) * 180.0 / M_PI; + view ()->set_cam_elevation (m_start_cam_elevation + de); + } + +private: + QPoint m_start_pos; + double m_start_cam_azimuth, m_start_cam_elevation; +}; + +// ------------------------------------------------------------------------------ + +class D25RotateAzimuthInteractionMode + : public D25InteractionMode +{ +public: + D25RotateAzimuthInteractionMode (D25ViewWidget *widget, const QPoint &pos) + : D25InteractionMode (widget), m_start_pos (pos) + { + // .. nothing yet .. + } + + virtual ~D25RotateAzimuthInteractionMode () + { + // .. nothing yet .. + } + + virtual void mouse_move (QMouseEvent *event) + { + // simple change of azimuth only - with center in the middle + + QPoint m = event->pos () - m_start_pos; + QVector3D p (m_start_pos.x () - view ()->width () / 2, -m_start_pos.y () + view ()->height () / 2, 0); + QVector3D d (m.x (), -m.y (), 0); + + double cp = QVector3D::crossProduct (p, p + d).z () / p.length () / (p + d).length (); + cp = std::max (-1.0, std::min (1.0, cp)); + double da = asin (cp) * 180.0 / M_PI; + + view ()->set_cam_azimuth (view ()->cam_azimuth () + da); + m_start_pos = event->pos (); + } + +private: + QPoint m_start_pos; +}; + +// ------------------------------------------------------------------------------ + D25ViewWidget::D25ViewWidget (QWidget *parent) : QOpenGLWidget (parent), m_shapes_program (0) @@ -74,13 +214,9 @@ void D25ViewWidget::reset () { m_scale_factor = 1.0; - m_focus_dist = 0.0; - m_fov = 90.0; - m_cam_azimuth = m_cam_elevation = 0.0; - m_top_view = false; - m_dragging = m_rotating = false; + mp_mode.reset (0); - refresh (); + camera_reset (); } void @@ -93,40 +229,55 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) double px = (event->pos ().x () - width () / 2) * 2.0 / width (); double py = -(event->pos ().y () - height () / 2) * 2.0 / height (); - // compute vector of line of sight - std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); + if (top_view ()) { - // by definition the ray goes through the camera position - QVector3D hp = hit_point_with_scene (ray.second); + // Plain zoom - if (event->modifiers () & Qt::ControlModifier) { - - // "Ctrl" is closeup - - 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; - - } else { - - // No shift is zoom + QVector3D hp (px, py, 0.0); 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; + m_displacement += hp * (1.0 - f) / m_scale_factor; - // normalize the scene translation so the scene does not "flee" + } else { - QMatrix4x4 ct = cam_trans (); - initial_displacement = ct.map (initial_displacement); - displacement = ct.map (displacement); + // compute vector of line of sight + std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); - lay::normalize_scene_trans (cam_perspective (), displacement, m_scale_factor, initial_displacement.z ()); + // by definition the ray goes through the camera position + QVector3D hp = hit_point_with_scene (ray.second); - m_displacement = ct.inverted ().map (displacement); + if (event->modifiers () & Qt::ControlModifier) { + + // "Ctrl" is closeup + + 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; + + } else { + + // No shift 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); + + } } @@ -137,10 +288,8 @@ void D25ViewWidget::keyPressEvent (QKeyEvent *event) { if (event->key () == Qt::Key_Shift) { - m_top_view = true; - m_dragging = false; - m_rotating = false; - refresh (); + mp_mode.reset (0); + set_top_view (true); } } @@ -148,10 +297,8 @@ void D25ViewWidget::keyReleaseEvent (QKeyEvent *event) { if (event->key () == Qt::Key_Shift) { - m_top_view = false; - m_dragging = false; - m_rotating = false; - refresh (); + mp_mode.reset (0); + set_top_view (false); } } @@ -178,181 +325,87 @@ D25ViewWidget::hit_point_with_scene (const QVector3D &line_dir) void D25ViewWidget::mousePressEvent (QMouseEvent *event) { - m_dragging = m_rotating = false; + mp_mode.reset (0); + if (event->button () == Qt::MidButton) { - m_dragging = true; + mp_mode.reset (new D25PanInteractionMode (this, event->pos ())); } else if (event->button () == Qt::LeftButton) { - m_rotating = true; - } - - m_start_pos = event->pos (); - m_start_cam_position = cam_position (); - m_start_cam_azimuth = cam_azimuth (); - m_start_cam_elevation = cam_elevation (); - m_start_displacement = m_displacement; - - m_focus_dist = 2.0; - m_hit_point = QVector3D (); - - if (m_dragging) { - - // by definition the ray goes through the camera position - QVector3D hp = hit_point_with_scene (cam_direction ()); - - m_focus_dist = (cam_position () - hp).length (); - m_hit_point = cam_position () + cam_direction () * m_focus_dist; - - } else if (m_rotating) { - - double px = (event->pos ().x () - width () / 2) * 2.0 / width (); - double py = -(event->pos ().y () - height () / 2) * 2.0 / height (); - - // compute vector of line of sight - std::pair ray = camera_normal (cam_perspective () * cam_trans (), px, py); - - // by definition the ray goes through the camera position - QVector3D hp = hit_point_with_scene (ray.second); - - m_focus_dist = std::max (m_focus_dist, double ((cam_position () - hp).length ())); - m_hit_point = cam_position () + ray.second * m_focus_dist; - + if (! top_view ()) { + mp_mode.reset (new D25Rotate2DInteractionMode (this, event->pos ())); + } else { + mp_mode.reset (new D25RotateAzimuthInteractionMode (this, event->pos ())); + } } } void D25ViewWidget::mouseReleaseEvent (QMouseEvent * /*event*/) { - m_dragging = false; - m_rotating = false; + mp_mode.reset (0); } void D25ViewWidget::mouseMoveEvent (QMouseEvent *event) { - if (! m_dragging && ! m_rotating) { - return; + if (mp_mode.get ()) { + mp_mode->mouse_move (event); } +} - if (m_dragging) { +inline double square (double x) { return x * x; } - QPoint d = event->pos () - m_start_pos; - double f = tan ((cam_fov () / 2) / 180.0 * M_PI) * m_focus_dist * 2.0 / double (height ()); - double dx = d.x () * f; - double dy = -d.y () * f; +void +D25ViewWidget::fit () +{ + // we pick a scale factor to adjust the z dimension roughly to 1/4 of the screen height at a focus distance of 2 + double norm_height = 0.5; + double in_focus = 2.0; + m_scale_factor = (tan (cam_fov () * M_PI / 180.0 / 2.0) * 2.0) * in_focus * norm_height / std::max (0.001, (m_zmax - m_zmin)); - QVector3D xv (cos (m_start_cam_azimuth * M_PI / 180.0), 0.0, sin (m_start_cam_azimuth * M_PI / 180.0)); - double re = sin (m_start_cam_elevation * M_PI / 180.0); - QVector3D yv (-re * xv.z (), cos (m_start_cam_elevation * M_PI / 180.0), re * xv.x ()); - QVector3D drag = xv * dx + yv * dy; + QVector3D dim = QVector3D (m_bbox.width (), m_zmax - m_zmin, m_bbox.height ()) * m_scale_factor; + QVector3D bll = QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())); - m_displacement = m_start_displacement + drag / m_scale_factor; + // now we pick a displacement which moves the center to y = 0 and x, y in a way that the dimension covers the field of + // view and is centered. + // (we use the elliptic approximation which works exactly for azimuth angles which are a multiple of 90 degree) - } else { + double dh = sqrt (square (cos (cam_azimuth () * M_PI / 180.0) * dim.x ()) + square (sin (cam_azimuth () * M_PI / 180.0) * dim.z ())); + double dv = sqrt (square (cos (cam_azimuth () * M_PI / 180.0) * dim.z ()) + square (sin (cam_azimuth () * M_PI / 180.0) * dim.x ())); - if (! m_top_view) { + double d = std::max (dh, fabs (sin (cam_elevation ()) * dv)); - // fixed focus point for rotation - double focus_dist = 2.0; + QVector3D new_center (0.0, 0.0, -dv / 2.0 + std::max (0.0, -d / (2.0 * tan (cam_fov () * M_PI / 180.0 / 2.0)) + cam_dist ())); + QVector3D new_center_in_scene = cam_trans ().inverted ().map (new_center); - QPoint d = event->pos () - m_start_pos; - double f = tan ((cam_fov () / 2) / 180.0 * M_PI) * focus_dist * 2.0 / double (height ()); - double dx = d.x () * f; - double dy = -d.y () * f; + new_center_in_scene.setY (0.0); - double da = dx / (cam_dist () - focus_dist) * 180.0 / M_PI; - m_cam_azimuth = m_start_cam_azimuth + da; - - double de = dy / (cam_dist () - focus_dist) * 180.0 / M_PI; - m_cam_elevation = m_start_cam_elevation + de; - - } else { - - // simple change of azimuth only - with center in the middle - - QPoint m = event->pos () - m_start_pos; - QVector3D p (m_start_pos.x () - width () / 2, -m_start_pos.y () + height () / 2, 0); - QVector3D d (m.x (), -m.y (), 0); - - double cp = QVector3D::crossProduct (p, p + d).z () / p.length () / (p + d).length (); - cp = std::max (-1.0, std::min (1.0, cp)); - double da = asin (cp) * 180.0 / M_PI; - - m_cam_azimuth += da; - m_start_pos = event->pos (); - - } - - } + m_displacement = (new_center_in_scene - dim * 0.5) / m_scale_factor - bll; refresh (); } -double -D25ViewWidget::cam_fov () const -{ - return m_fov; // @@@ -} - -double -D25ViewWidget::cam_dist () const -{ - return 4.0; // @@@ -} - -QVector3D -D25ViewWidget::cam_direction () const -{ - QVector3D cd = cam_trans ().map (QVector3D (0, 0, 1)); - cd.setZ (-cd.z ()); - return cd; -} - -QVector3D -D25ViewWidget::cam_position () const -{ - return cam_direction () * -cam_dist (); -} - -double -D25ViewWidget::cam_azimuth () const -{ - return m_cam_azimuth; -} - -double -D25ViewWidget::cam_elevation () const -{ - return m_top_view ? -90.0 : m_cam_elevation; -} - -QMatrix4x4 -D25ViewWidget::cam_perspective () const -{ - QMatrix4x4 t; - t.perspective (cam_fov (), float (width ()) / float (height ()), 0.1f, 10000.0f); - t.translate (QVector3D (0.0, 0.0, -cam_dist ())); - return t; -} - -QMatrix4x4 -D25ViewWidget::cam_trans () const -{ - QMatrix4x4 t; - t.rotate (-cam_elevation (), 1.0, 0.0, 0.0); - t.rotate (cam_azimuth (), 0.0, 1.0, 0.0); - return t; -} - void D25ViewWidget::refresh () { QVector3D cp = cam_position (); -printf("@@@ e=%g a=%g x,y,z=%g,%g,%g d=%g,%g,%g s=%g f=%g\n", cam_elevation (), cam_azimuth (), cp.x(), cp.y(), cp.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor, m_focus_dist); fflush(stdout); +printf("@@@ e=%g a=%g x,y,z=%g,%g,%g d=%g,%g,%g s=%g\n", cam_elevation (), cam_azimuth (), cp.x(), cp.y(), cp.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor); fflush(stdout); update (); } +void +D25ViewWidget::camera_changed () +{ + refresh (); +} + +double +D25ViewWidget::aspect_ratio () const +{ + return double (width ()) / double (height ()); +} + void D25ViewWidget::attach_view (LayoutView *view) { @@ -439,61 +492,26 @@ D25ViewWidget::render_polygon (D25ViewWidget::chunks_type &chunks, const db::Pol // triangle bottom - chunks.add (pts[0].x () * dbu); - chunks.add (zstart); - chunks.add (pts[0].y () * dbu); - - chunks.add (pts[2].x () * dbu); - chunks.add (zstart); - chunks.add (pts[2].y () * dbu); - - chunks.add (pts[1].x () * dbu); - chunks.add (zstart); - chunks.add (pts[1].y () * dbu); + chunks.add (pts[0].x () * dbu, zstart, pts[0].y () * dbu); + chunks.add (pts[2].x () * dbu, zstart, pts[2].y () * dbu); + chunks.add (pts[1].x () * dbu, zstart, pts[1].y () * dbu); // triangle top - - chunks.add (pts[0].x () * dbu); - chunks.add (zstop); - chunks.add (pts[0].y () * dbu); - - chunks.add (pts[1].x () * dbu); - chunks.add (zstop); - chunks.add (pts[1].y () * dbu); - - chunks.add (pts[2].x () * dbu); - chunks.add (zstop); - chunks.add (pts[2].y () * dbu); + chunks.add (pts[0].x () * dbu, zstop, pts[0].y () * dbu); + chunks.add (pts[1].x () * dbu, zstop, pts[1].y () * dbu); + chunks.add (pts[2].x () * dbu, zstop, pts[2].y () * dbu); if (poly.hull ().size () == 4) { // triangle bottom - - chunks.add (pts[0].x () * dbu); - chunks.add (zstart); - chunks.add (pts[0].y () * dbu); - - chunks.add (pts[3].x () * dbu); - chunks.add (zstart); - chunks.add (pts[3].y () * dbu); - - chunks.add (pts[2].x () * dbu); - chunks.add (zstart); - chunks.add (pts[2].y () * dbu); + chunks.add (pts[0].x () * dbu, zstart, pts[0].y () * dbu); + chunks.add (pts[3].x () * dbu, zstart, pts[3].y () * dbu); + chunks.add (pts[2].x () * dbu, zstart, pts[2].y () * dbu); // triangle top - - chunks.add (pts[0].x () * dbu); - chunks.add (zstop); - chunks.add (pts[0].y () * dbu); - - chunks.add (pts[2].x () * dbu); - chunks.add (zstop); - chunks.add (pts[2].y () * dbu); - - chunks.add (pts[3].x () * dbu); - chunks.add (zstop); - chunks.add (pts[3].y () * dbu); + chunks.add (pts[0].x () * dbu, zstop, pts[0].y () * dbu); + chunks.add (pts[2].x () * dbu, zstop, pts[2].y () * dbu); + chunks.add (pts[3].x () * dbu, zstop, pts[3].y () * dbu); } @@ -503,29 +521,12 @@ D25ViewWidget::render_polygon (D25ViewWidget::chunks_type &chunks, const db::Pol void D25ViewWidget::render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &edge, double dbu, double zstart, double zstop) { - chunks.add (edge.p1 ().x () * dbu); - chunks.add (zstart); - chunks.add (edge.p1 ().y () * dbu); - - chunks.add (edge.p2 ().x () * dbu); - chunks.add (zstop); - chunks.add (edge.p2 ().y () * dbu); - - chunks.add (edge.p1 ().x () * dbu); - chunks.add (zstop); - chunks.add (edge.p1 ().y () * dbu); - - chunks.add (edge.p1 ().x () * dbu); - chunks.add (zstart); - chunks.add (edge.p1 ().y () * dbu); - - chunks.add (edge.p2 ().x () * dbu); - chunks.add (zstart); - chunks.add (edge.p2 ().y () * dbu); - - chunks.add (edge.p2 ().x () * dbu); - chunks.add (zstop); - chunks.add (edge.p2 ().y () * dbu); + chunks.add (edge.p1 ().x () * dbu, zstart, edge.p1 ().y () * dbu); + chunks.add (edge.p2 ().x () * dbu, zstop, edge.p2 ().y () * dbu); + chunks.add (edge.p1 ().x () * dbu, zstop, edge.p1 ().y () * dbu); + chunks.add (edge.p1 ().x () * dbu, zstart, edge.p1 ().y () * dbu); + chunks.add (edge.p2 ().x () * dbu, zstart, edge.p2 ().y () * dbu); + chunks.add (edge.p2 ().x () * dbu, zstop, edge.p2 ().y () * dbu); } void @@ -642,8 +643,7 @@ D25ViewWidget::initializeGL () "uniform vec4 ambient;\n" "uniform vec3 illum;\n" "out lowp vec4 vertexColor;\n" - "uniform mat4 geo_matrix;\n" - "uniform mat4 cam_matrix;\n" + "uniform mat4 matrix;\n" "layout (triangles) in;\n" "layout (triangle_strip, max_vertices = 3) out;\n" "\n" @@ -655,11 +655,11 @@ D25ViewWidget::initializeGL () " float dp = dot(normalize(n), illum);\n" " vertexColor = color * (dp * 0.5 + 0.5) - (min(0.0, dp) * 0.5 * ambient);\n" " vertexColor.a = 1.0;\n" - " gl_Position = cam_matrix * geo_matrix * p0;\n" + " gl_Position = matrix * p0;\n" " EmitVertex();\n" - " gl_Position = cam_matrix * geo_matrix * p1;\n" + " gl_Position = matrix * p1;\n" " EmitVertex();\n" - " gl_Position = cam_matrix * geo_matrix * p2;\n" + " gl_Position = matrix * p2;\n" " EmitVertex();\n" " EndPrimitive();\n" "}\n"; @@ -743,9 +743,6 @@ D25ViewWidget::initializeGL () void D25ViewWidget::paintGL () { - GLfloat vertices[6000]; - size_t nmax = sizeof (vertices) / sizeof (GLfloat); - const qreal retinaScale = devicePixelRatio (); glViewport (0, 0, width () * retinaScale, height () * retinaScale); @@ -767,8 +764,9 @@ D25ViewWidget::paintGL () m_shapes_program->bind (); - m_shapes_program->setUniformValue ("geo_matrix", cam_trans () * scene_trans); - m_shapes_program->setUniformValue ("cam_matrix", cam_perspective ()); + // draw the actual layout + + m_shapes_program->setUniformValue ("matrix", cam_perspective () * cam_trans () * scene_trans); // NOTE: z axis of illum points towards the scene because we include the z inversion in the scene transformation matrix m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); @@ -779,20 +777,19 @@ D25ViewWidget::paintGL () glEnableVertexAttribArray (positions); for (std::list::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) { - m_shapes_program->setUniformValue ("color", l->color [0], l->color [1], l->color [2], l->color [3]); - - for (chunks_type::iterator c = l->vertex_chunk->begin (); c != l->vertex_chunk->end (); ++c) { - glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, c->front ()); - glDrawArrays (GL_TRIANGLES, 0, c->size () / 3); - } - + l->vertex_chunk->draw_to (this, positions, GL_TRIANGLES); } glDisableVertexAttribArray (positions); m_shapes_program->release (); + // decoration + + // a vertex buffer for the decoration + lay::mem_chunks vertexes; + m_gridplane_program->bind (); glEnable (GL_DEPTH_TEST); @@ -802,26 +799,14 @@ D25ViewWidget::paintGL () m_gridplane_program->setUniformValue ("matrix", cam_perspective () * cam_trans ()); - size_t index = 0; - double compass_rad = 0.3; double compass_bars = 0.4; - vertices[index++] = -compass_bars; - vertices[index++] = 0.0; - vertices[index++] = 0.0; + vertexes.add (-compass_bars, 0.0, 0.0); + vertexes.add (compass_bars, 0.0, 0.0); - vertices[index++] = compass_bars; - vertices[index++] = 0.0; - vertices[index++] = 0.0; - - vertices[index++] = 0.0; - vertices[index++] = 0.0; - vertices[index++] = -compass_bars; - - vertices[index++] = 0.0; - vertices[index++] = 0.0; - vertices[index++] = compass_bars; + vertexes.add (0.0, 0.0, -compass_bars); + vertexes.add (0.0, 0.0, compass_bars); int ncircle = 64; double x = compass_rad, z = 0.0; @@ -833,13 +818,8 @@ D25ViewWidget::paintGL () double xx = compass_rad * cos (a); double zz = compass_rad * sin (a); - vertices[index++] = x; - vertices[index++] = 0.0; - vertices[index++] = z; - - vertices[index++] = xx; - vertices[index++] = 0.0; - vertices[index++] = zz; + vertexes.add (x, 0.0, z); + vertexes.add (xx, 0.0, zz); x = xx; z = zz; @@ -848,29 +828,18 @@ D25ViewWidget::paintGL () m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.25f); - glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, vertices); - glLineWidth (2.0); - glDrawArrays (GL_LINES, 0, index / 3); - - index = 0; + vertexes.draw_to (this, positions, GL_LINES); // arrow - vertices[index++] = -0.25 * compass_rad; - vertices[index++] = 0.0; - vertices[index++] = 0.6 * compass_rad; - vertices[index++] = 0.0; - vertices[index++] = 0.0; - vertices[index++] = -0.8 * compass_rad; + vertexes.clear (); - vertices[index++] = 0.25 * compass_rad; - vertices[index++] = 0.0; - vertices[index++] = 0.6 * compass_rad; + 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.25 * compass_rad, 0.0, 0.6 * compass_rad); - glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, vertices); - - glDrawArrays (GL_TRIANGLES, 0, index / 3); + vertexes.draw_to (this, positions, GL_TRIANGLES); // draw base plane @@ -880,71 +849,61 @@ D25ViewWidget::paintGL () double gminor = gg.second, gmajor = gg.first; double margin = std::max (m_bbox.width (), m_bbox.height ()) * 0.02; - double l = m_bbox.left () - margin; - double r = m_bbox.right () + margin; - double b = m_bbox.bottom () - margin; - double t = m_bbox.top () + margin; - // @@@ + double l = m_bbox.left (); + double r = m_bbox.right (); + double b = m_bbox.bottom (); + double t = m_bbox.top (); // major and minor grid lines + vertexes.clear (); + const double epsilon = 1e-6; for (int major = 0; major < 2; ++major) { m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, major ? 0.25f : 0.15f); - size_t index = 0; double x, y; double step = (major ? gmajor : gminor); x = ceil (l / step) * step; - for ( ; index < nmax && x < r - step * epsilon; x += step) { + for ( ; x < r - step * epsilon; x += step) { if ((fabs (floor (x / gmajor + 0.5) * gmajor - x) < epsilon) == (major != 0)) { - vertices [index++] = x; - vertices [index++] = 0.0; - vertices [index++] = b; - vertices [index++] = x; - vertices [index++] = 0.0; - vertices [index++] = t; + vertexes.add (x, 0.0, b - margin); + vertexes.add (x, 0.0, t + margin); } } y = ceil (b / step) * step; - for ( ; index < nmax && y < t - step * epsilon; y += step) { + for ( ; y < t - step * epsilon; y += step) { if ((fabs (floor (y / gmajor + 0.5) * gmajor - y) < epsilon) == (major != 0)) { - vertices [index++] = l; - vertices [index++] = 0.0; - vertices [index++] = y; - vertices [index++] = r; - vertices [index++] = 0.0; - vertices [index++] = y; + vertexes.add (l - margin, 0.0, y); + vertexes.add (r + margin, 0.0, y); } } - glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, vertices); - glLineWidth (2.0); - glDrawArrays (GL_LINES, 0, index / 3); + vertexes.draw_to (this, positions, GL_LINES); } - l = m_bbox.left (); - r = m_bbox.right (); - b = m_bbox.bottom (); - t = m_bbox.top (); + // the plane itself - GLfloat plane_vertices[] = { - float (l), 0.0f, float (b), float (l), 0.0f, float (t), float (r), 0.0f, float (t), - float (l), 0.0f, float (b), float (r), 0.0f, float (t), float (r), 0.0f, float (b) - }; + vertexes.clear (); + + vertexes.add (l, 0.0, b); + vertexes.add (l, 0.0, t); + vertexes.add (r, 0.0, t); + + vertexes.add (l, 0.0, b); + vertexes.add (r, 0.0, b); + vertexes.add (r, 0.0, t); m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.1f); - glVertexAttribPointer (positions, 3, GL_FLOAT, GL_FALSE, 0, plane_vertices); - - glDrawArrays (GL_TRIANGLES, 0, 6); + vertexes.draw_to (this, positions, GL_TRIANGLES); glDisableVertexAttribArray (positions); diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index e89404360..36f8d59b8 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -23,6 +23,11 @@ #ifndef HDR_layD25ViewWidget #define HDR_layD25ViewWidget +#include "dbPolygon.h" + +#include "layD25MemChunks.h" +#include "layD25Camera.h" + #include #include #include @@ -32,9 +37,7 @@ #include #include -#include "dbPolygon.h" - -#include "layD25MemChunks.h" +#include namespace db { @@ -46,10 +49,25 @@ namespace lay { class LayoutView; +class D25ViewWidget; + +class D25InteractionMode +{ +public: + D25InteractionMode (D25ViewWidget *widget); + virtual ~D25InteractionMode (); + + D25ViewWidget *view () { return mp_view; } + virtual void mouse_move (QMouseEvent *event) = 0; + +private: + D25ViewWidget *mp_view; +}; class D25ViewWidget : public QOpenGLWidget, - private QOpenGLFunctions + private QOpenGLFunctions, + public D25Camera { Q_OBJECT @@ -66,22 +84,40 @@ public: void attach_view (lay::LayoutView *view); + QVector3D hit_point_with_scene(const QVector3D &line_dir); + void refresh (); + void reset (); + + QVector3D displacement () const { return m_displacement; } + + void set_displacement (const QVector3D &d) + { + m_displacement = d; + refresh (); + } + + double scale_factor () const { return m_scale_factor; } + + void set_scale_factor (double f) + { + m_scale_factor = f; + refresh (); + } + +protected: + virtual void camera_changed (); + virtual double aspect_ratio () const; + +public slots: + void fit (); + private: typedef lay::mem_chunks chunks_type; + std::auto_ptr mp_mode; QOpenGLShaderProgram *m_shapes_program, *m_gridplane_program; - bool m_dragging, m_rotating; double m_scale_factor; - double m_cam_azimuth, m_cam_elevation; - bool m_top_view; QVector3D m_displacement; - double m_focus_dist; - double m_fov; - QVector3D m_hit_point; - QPoint m_start_pos; - QVector3D m_start_cam_position; - double m_start_cam_azimuth, m_start_cam_elevation; - QVector3D m_start_displacement; lay::LayoutView *mp_view; db::DBox m_bbox; double m_zmin, m_zmax; @@ -99,21 +135,10 @@ private: void paintGL (); void resizeGL (int w, int h); - void refresh (); - void reset (); void prepare_view (); void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop); void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop); void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop); - QVector3D hit_point_with_scene(const QVector3D &line_dir); - double cam_elevation () const; - double cam_azimuth () const; - QVector3D cam_position () const; - QVector3D cam_direction () const; - QMatrix4x4 cam_perspective () const; - QMatrix4x4 cam_trans () const; - double cam_dist () const; - double cam_fov () const; }; } diff --git a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro index 6afb49ac2..2ef786e9b 100644 --- a/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro +++ b/src/plugins/tools/view_25d/lay_plugin/lay_plugin.pro @@ -12,14 +12,16 @@ HEADERS = \ layD25View.h \ layD25ViewWidget.h \ layD25MemChunks.h \ - layD25ViewUtils.h + layD25ViewUtils.h \ + layD25Camera.h SOURCES = \ layD25View.cc \ layD25ViewWidget.cc \ layD25Plugin.cc \ layD25MemChunks.cc \ - layD25ViewUtils.cc + layD25ViewUtils.cc \ + layD25Camera.cc FORMS = \ D25View.ui \ diff --git a/src/plugins/tools/view_25d/unit_tests/layD25CameraTests.cc b/src/plugins/tools/view_25d/unit_tests/layD25CameraTests.cc new file mode 100644 index 000000000..2934a9a9c --- /dev/null +++ b/src/plugins/tools/view_25d/unit_tests/layD25CameraTests.cc @@ -0,0 +1,102 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 "layD25Camera.h" +#include "tlUnitTest.h" + +static std::string v2s (const QVector4D &v) +{ + return tl::to_string (v.x ()) + "," + tl::to_string (v.y ()) + "," + tl::to_string (v.z ()); +} + +static std::string v2s (const QVector3D &v) +{ + return tl::to_string (v.x ()) + "," + tl::to_string (v.y ()) + "," + tl::to_string (v.z ()); +} + +static std::string v2s_2d (const QVector3D &v) +{ + return tl::to_string (v.x ()) + "," + tl::to_string (v.y ()); +} + +TEST(1_Transformations) +{ + lay::D25Camera cam; + + cam.set_cam_azimuth (45.0); + EXPECT_EQ (cam.cam_azimuth (), 45.0); + cam.set_cam_elevation (22.0); + EXPECT_EQ (cam.cam_elevation (), 22.0); + + cam.camera_reset (); + EXPECT_EQ (cam.cam_azimuth (), 0.0); + EXPECT_EQ (cam.cam_elevation (), 0.0); + + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "1,0,0"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,1,0"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "0,0,1"); + EXPECT_EQ (v2s (cam.cam_direction ()), "0,0,-1"); + EXPECT_EQ (v2s (cam.cam_position ()), "0,0,4"); + + // looking up from the bottom, x axis stays the same (azimuth = 0) + cam.set_cam_elevation (90.0); + + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "1,0,0"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,0,-1"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "0,1,0"); + + EXPECT_EQ (v2s (cam.cam_direction ()), "0,1,0"); + EXPECT_EQ (v2s (cam.cam_position ()), "0,-4,0"); + + // looking down from the top, x axis stays the same (azimuth = 0) + cam.set_cam_elevation (-90.0); + + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "1,0,0"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,0,1"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "0,-1,0"); + + EXPECT_EQ (v2s (cam.cam_direction ()), "0,-1,0"); + EXPECT_EQ (v2s (cam.cam_position ()), "0,4,0"); + + // looking from the left, y axis stays the same (elevation = 0) + cam.set_cam_elevation (0.0); + cam.set_cam_azimuth (90.0); + + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "0,0,-1"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,1,0"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "1,0,0"); + + EXPECT_EQ (v2s (cam.cam_direction ()), "1,0,0"); + EXPECT_EQ (v2s (cam.cam_position ()), "-4,0,0"); + + // looking from the right, y axis stays the same (elevation = 0) + cam.set_cam_elevation (0.0); + cam.set_cam_azimuth (-90.0); + + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (1, 0, 0, 1))), "0,0,1"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 1, 0, 1))), "0,1,0"); + EXPECT_EQ (v2s (cam.cam_trans ().map (QVector4D (0, 0, 1, 1))), "-1,0,0"); + + EXPECT_EQ (v2s (cam.cam_direction ()), "-1,0,0"); + EXPECT_EQ (v2s (cam.cam_position ()), "4,0,0"); +} diff --git a/src/plugins/tools/view_25d/unit_tests/unit_tests.pro b/src/plugins/tools/view_25d/unit_tests/unit_tests.pro index 729ddc42e..c3e4e8e21 100644 --- a/src/plugins/tools/view_25d/unit_tests/unit_tests.pro +++ b/src/plugins/tools/view_25d/unit_tests/unit_tests.pro @@ -7,7 +7,8 @@ include($$PWD/../../../../lib_ut.pri) SOURCES = \ layD25MemChunksTests.cc \ - layD25ViewUtilsTests.cc + layD25ViewUtilsTests.cc \ + layD25CameraTests.cc INCLUDEPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../lay_plugin $$PWD/../../../common DEPENDPATH += $$LAY_INC $$TL_INC $$DB_INC $$GSI_INC $$PWD/../lay_plugin $$PWD/../../../common From f954afab7a0ba14cd456d9fc3e01fa4cedc6c660 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Thu, 16 Apr 2020 23:14:48 +0200 Subject: [PATCH 18/27] Added missing files. --- src/lay/lay/images/fit_back.png | Bin 0 -> 537 bytes src/lay/lay/images/fit_bottom.png | Bin 0 -> 530 bytes src/lay/lay/images/fit_front.png | Bin 0 -> 543 bytes src/lay/lay/images/fit_left.png | Bin 0 -> 548 bytes src/lay/lay/images/fit_right.png | Bin 0 -> 542 bytes src/lay/lay/images/fit_top.png | Bin 0 -> 526 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/lay/lay/images/fit_back.png create mode 100644 src/lay/lay/images/fit_bottom.png create mode 100644 src/lay/lay/images/fit_front.png create mode 100644 src/lay/lay/images/fit_left.png create mode 100644 src/lay/lay/images/fit_right.png create mode 100644 src/lay/lay/images/fit_top.png diff --git a/src/lay/lay/images/fit_back.png b/src/lay/lay/images/fit_back.png new file mode 100644 index 0000000000000000000000000000000000000000..cbfbbad302c9edd73247d93b027bd5eb7409c23a GIT binary patch literal 537 zcmV+!0_OdRP)1I-S>Ux4T;^ zm2RS*7JZ~rsTE3TlTw-{Br*4UOG3c+{dM2>FD%Pi`}G3LvP2k$bIQr_Fj=qHzpB-v zW*CNZjYfk20C=7kYz3D}6q&IKN|#rm&@h$RRGm$wS$jqas3x?Dcx5rfHr|0vHSi003{3 b{GC`I`<<^26aZsg00000NkvXXu0mjfE5PY~ literal 0 HcmV?d00001 diff --git a/src/lay/lay/images/fit_bottom.png b/src/lay/lay/images/fit_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..7308be3a2967f5cf857183f7bbfe733523a64786 GIT binary patch literal 530 zcmV+t0`2{YP)rcL3N<^dC$F6T$e9Zo^zI7c|YTE((I>mfPueIvt+pL&;?F8B1Uo zS}K5~n_cSa8b@%^jc(M8#X|r%vS*GH@jUNo>v}3Yb@zZ%4gjzQxA&^1ahXhJ-kv!& zc&|S0`)8pU@=A4F!IHPB_}cYX9Zj?L%&~!PXeX=GO9i*QN0_QrTCK0+p#oLa0-FmT zPooOf{Zh@;T8@i21j|0TOd<>G@3FHoCzb890V6_4D^)$QQZ*R+i{OXPF}@w0Z`1dY UX}95mZ2$lO07*qoM6N<$f^B@{xBvhE literal 0 HcmV?d00001 diff --git a/src/lay/lay/images/fit_front.png b/src/lay/lay/images/fit_front.png new file mode 100644 index 0000000000000000000000000000000000000000..5034b975b22eb7248164ad8ac0ad4a036ab6250e GIT binary patch literal 543 zcmV+)0^t3LP))22Y+k_#Y%NZ&G&)j1G0FtV6em4jTlSW4mo8TJ7$1sZiV4F|R(y@11!c=3@X_ z*nq5t@pycJd zbTfzhdqtF2nFObAqmv#iUj_J+eHOuiIlp-EF*3En=QH)$uNCRE4c`=dCdTmfB}+K~ zfRA2X-oCnhMZ?iyD>y0)db#)K!mxwnSp@@*7tN_Z$;ax@n62Q9xTeRu?$24vzwz;M z_MA9pYz1oR-8tL$c-yF8#zXGj$|c=a;B~864pG{u003azMK0=RHNOZURLRKg{){a8 h|0DRK*u>q&`2>kgj{kPc8$SR5002ovPDHLkV1hg#?8^WE literal 0 HcmV?d00001 diff --git a/src/lay/lay/images/fit_left.png b/src/lay/lay/images/fit_left.png new file mode 100644 index 0000000000000000000000000000000000000000..36dc09f5c00b813591bc670e672ea6daee6c96be GIT binary patch literal 548 zcmV+<0^9wGP)D6oweJv_%9pwHy8cK}~X3lN^Ku zO%Zr);^H9EVwe)#wS?eOLq7%~oEn1~ngVGlknS*julLmV-lo9LlRK@^XS?UQ_xZfv z?+Y-JgOHtBC=|kDUe7J!JU%xirfGfwz@{jQWk*0f9uLjU1TF%>*)3lvbDs|nRaor!0NF;fQW_L$-#`XUGzZwBXfWOOYXR6dc#W>SA zQxvMWD4~>g^7;HiEEaol1-K_mt1YOX$M*I`H@D2?aw$sbE&v=@vz`@on1_3A23E9Y z>&Q(x06@K7&*{1zO(YV2M?m>wei7^BQIe!5w*X0!UUgl+qm*u2vz`@I-lvx-M-JVV z{|IB8rIemn{hkTbhA~;KR&NFcq|@mN#+Wz)2qD>0sYC|_003Z&kFDOX6(NL(VHg>n m=QG0q+U+&~Kx3G*L+cw7j;Ky$^$sWi0000ugK~zYI?UO%90#O{tf4@V^h=$-O$0qlnQE+OqM!TaS(1wO` z_GT9c5t5S7L9dqnIJDVfP!J8#R?w(4mDOFBp7+%5UQ>{IaxbIJ&-D2Hc;C-^@5cie z;Q-ndbGcl=<#Lrcj++s`$ggQyQPZ?lMBB^Rf{3u_xjFrKR}Mr`3=X`3D2fK9)We)?1BcK) zJUSk?Z3==wzt^%XTP%ST0Odk~(n26k3xW9041k^|`VU5ek>KyR?24I8#%r3U!SWaO z0l+jr%_p3h_F_$C613ax4a>6RXf(RXa?1SPcKQ~43rn8bxuYPP&AJsuSx3ZRZ*LGa zjigj=>b~wCyXx)r&7e}LtTda=2T79dSOtYh6P|MAB-tQi33)h7oi+ g9RPs(FnfpQ3oQ|;^7mw!&;S4c07*qoM6N<$g7wJjJOBUy literal 0 HcmV?d00001 diff --git a/src/lay/lay/images/fit_top.png b/src/lay/lay/images/fit_top.png new file mode 100644 index 0000000000000000000000000000000000000000..843fd32d6970747d41b8a09f611c3fba06067130 GIT binary patch literal 526 zcmV+p0`dKcP)zQ8edGGwV2Ldoq z50Ri@rBa!VgomyO361cCxUOTlKo-*J^mR`_Hk(bvC&o|5Vw15H+27#-XzuEEv+>e+ zebZMIMY-^LA@4^rnM}}+_p_Pk{W&3l%LR%M0&~&3lUB2FAd2Grj~gtBg5|g{%$*#d z5CQw}=r|f^3WDHv&YGq7QsWgR%2JgRsh@YyePD_&X z#09WzTXGyn%VaVeJb-e!tRUh#0Brfau8LGujhLpnMk(Fn2?qesb-m0OOXYI8(Vl=> zt+vP*dz5AQffpdl@-t)X1`(J2UROniVQeDeE^l~8l+q$1c5U6YfngZ&dcA)6TR=Xa zzonF#Jpra^7OT}N{uTfLKq)QxXWuF!gqW6P6$C*j^aE(O+W-Kqe%|)2FEW~_f>NnH QmH+?%07*qoM6N<$g7yaCx&QzG literal 0 HcmV?d00001 From 7884446da166ac397e0031b569937c9c27228235 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 17 Apr 2020 00:25:21 +0200 Subject: [PATCH 19/27] Orientation cube, some refinement. --- .../tools/view_25d/lay_plugin/D25View.ui | 20 ++- .../tools/view_25d/lay_plugin/layD25Camera.h | 2 +- .../tools/view_25d/lay_plugin/layD25View.cc | 27 ++++ .../tools/view_25d/lay_plugin/layD25View.h | 2 + .../view_25d/lay_plugin/layD25ViewWidget.cc | 123 +++++++++++++++++- .../view_25d/lay_plugin/layD25ViewWidget.h | 5 +- 6 files changed, 173 insertions(+), 6 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/D25View.ui b/src/plugins/tools/view_25d/lay_plugin/D25View.ui index efdbd6365..f09a1a654 100644 --- a/src/plugins/tools/view_25d/lay_plugin/D25View.ui +++ b/src/plugins/tools/view_25d/lay_plugin/D25View.ui @@ -61,6 +61,24 @@
+ + + 0 + 0 + + + + + 150 + 16777215 + + + + -300 + + + 300 + Qt::Horizontal @@ -91,7 +109,7 @@ Qt::Horizontal - QSizePolicy::Fixed + QSizePolicy::Expanding diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.h b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.h index 22dd780e4..06680ef47 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.h @@ -105,7 +105,7 @@ public: /** * @brief Gets the azimuth angle - * ... + * A positive angle means we look from the left. A negative means we look from the right. */ double cam_azimuth () const; diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index aa6c587a4..158e19f3f 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -50,6 +50,8 @@ D25View::D25View (QWidget *parent) 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->d25_view, SIGNAL (scale_factor_changed (double)), this, SLOT (scale_factor_changed (double))); } D25View::~D25View () @@ -58,6 +60,31 @@ D25View::~D25View () mp_ui = 0; } +static QString scale_factor_to_string (double f) +{ + QString s; + s.sprintf ("x %.3g", f); + return s; +} + +void +D25View::scale_slider_changed (int value) +{ + double f = exp (log (10.0) * -0.01 * value); + mp_ui->zoom_factor->setText (scale_factor_to_string (f)); + mp_ui->d25_view->set_scale_factor (f); +} + +void +D25View::scale_factor_changed (double f) +{ + mp_ui->zoom_factor->setText (scale_factor_to_string (f)); + int v = floor (0.5 - log10 (f) * 100.0); + mp_ui->zoom_slider->blockSignals (true); + mp_ui->zoom_slider->setValue (v); + mp_ui->zoom_slider->blockSignals (false); +} + int D25View::exec_dialog (lay::LayoutView *view) { diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.h b/src/plugins/tools/view_25d/lay_plugin/layD25View.h index 207ca7751..6f776ed3c 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.h @@ -56,6 +56,8 @@ protected: private slots: void fit_button_clicked (); + void scale_factor_changed (double f); + void scale_slider_changed (int value); private: Ui::D25View *mp_ui; diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 1a077e786..48ca09105 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -240,6 +240,8 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) m_scale_factor *= f; m_displacement += hp * (1.0 - f) / m_scale_factor; + emit scale_factor_changed (m_scale_factor); + } else { // compute vector of line of sight @@ -248,16 +250,16 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) // by definition the ray goes through the camera position QVector3D hp = hit_point_with_scene (ray.second); - if (event->modifiers () & Qt::ControlModifier) { + if (! (event->modifiers () & Qt::ControlModifier)) { - // "Ctrl" is closeup + // No Ctrl is closeup 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; } else { - // No shift is zoom + // "Ctrl" is zoom double f = exp (event->angleDelta ().y () * (1.0 / (90 * 8))); @@ -277,6 +279,8 @@ D25ViewWidget::wheelEvent (QWheelEvent *event) m_displacement = ct.inverted ().map (displacement); + emit scale_factor_changed (m_scale_factor); + } } @@ -382,6 +386,8 @@ D25ViewWidget::fit () m_displacement = (new_center_in_scene - dim * 0.5) / m_scale_factor - bll; refresh (); + + emit scale_factor_changed (m_scale_factor); } void @@ -905,6 +911,117 @@ D25ViewWidget::paintGL () vertexes.draw_to (this, positions, GL_TRIANGLES); + // the orientation cube + + if (! top_view ()) { + + glDisable (GL_DEPTH_TEST); + + int cube_size = 64; + int cube_margin = 20; + + 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)); + // into_top_right_corner.translate (0.5, 0.5, 0.0); + into_top_right_corner.scale (2.0 * cube_size / double (height ()), 2.0 * cube_size / double (height ()), 1.0); + + m_gridplane_program->setUniformValue ("matrix", into_top_right_corner * cam_perspective () * cam_trans ()); + + vertexes.clear (); + + vertexes.add (-1.0, -1.0, 1.0); + vertexes.add (-1.0, -1.0, -1.0); + + vertexes.add (-1.0, 1.0, 1.0); + vertexes.add (-1.0, 1.0, -1.0); + + vertexes.add (1.0, -1.0, 1.0); + vertexes.add (1.0, -1.0, -1.0); + + vertexes.add (1.0, 1.0, 1.0); + vertexes.add (1.0, 1.0, -1.0); + + vertexes.add (-1.0, -1.0, 1.0); + vertexes.add (-1.0, 1.0, 1.0); + + vertexes.add (1.0, -1.0, 1.0); + vertexes.add (1.0, 1.0, 1.0); + + vertexes.add (-1.0, -1.0, 1.0); + vertexes.add (1.0, -1.0, 1.0); + + vertexes.add (-1.0, 1.0, 1.0); + vertexes.add (1.0, 1.0, 1.0); + + vertexes.add (-1.0, -1.0, -1.0); + vertexes.add (-1.0, 1.0, -1.0); + + vertexes.add (1.0, -1.0, -1.0); + vertexes.add (1.0, 1.0, -1.0); + + vertexes.add (-1.0, -1.0, -1.0); + vertexes.add (1.0, -1.0, -1.0); + + vertexes.add (-1.0, 1.0, -1.0); + vertexes.add (1.0, 1.0, -1.0); + + m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.2f); + + vertexes.draw_to (this, positions, GL_LINES); + + vertexes.clear (); + + // A "K" at the front + vertexes.add (-0.8, -0.8, 1.0); + vertexes.add (-0.8, 0.8, 1.0); + vertexes.add (-0.2, 0.8, 1.0); + + vertexes.add (-0.8, -0.8, 1.0); + vertexes.add (-0.2, -0.8, 1.0); + vertexes.add (-0.2, 0.8, 1.0); + + vertexes.add (0.2, 0.8, 1.0); + vertexes.add (0.8, 0.8, 1.0); + vertexes.add (0.8, 0.6, 1.0); + + vertexes.add (0.2, 0.8, 1.0); + vertexes.add (0.8, 0.6, 1.0); + vertexes.add (0.6, 0.4, 1.0); + + vertexes.add (-0.2, 0.4, 1.0); + vertexes.add (0.2, 0.8, 1.0); + vertexes.add (0.6, 0.4, 1.0); + + vertexes.add (-0.2, 0.4, 1.0); + vertexes.add (0.6, 0.4, 1.0); + vertexes.add (0.2, 0.0, 1.0); + + vertexes.add (-0.2, 0.4, 1.0); + vertexes.add (0.2, 0.0, 1.0); + vertexes.add (-0.2, -0.4, 1.0); + + vertexes.add (-0.2, -0.4, 1.0); + vertexes.add (0.6, -0.4, 1.0); + vertexes.add (0.2, -0.0, 1.0); + + vertexes.add (-0.2, -0.4, 1.0); + vertexes.add (0.2, -0.8, 1.0); + vertexes.add (0.6, -0.4, 1.0); + + vertexes.add (0.2, -0.8, 1.0); + vertexes.add (0.8, -0.6, 1.0); + vertexes.add (0.6, -0.4, 1.0); + + vertexes.add (0.2, -0.8, 1.0); + vertexes.add (0.8, -0.8, 1.0); + vertexes.add (0.8, -0.6, 1.0); + + m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.3f); + + vertexes.draw_to (this, positions, GL_TRIANGLES); + + } + glDisableVertexAttribArray (positions); m_shapes_program->release (); diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index 36f8d59b8..ea6d5c790 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -104,6 +104,9 @@ public: refresh (); } +signals: + void scale_factor_changed (double f); + protected: virtual void camera_changed (); virtual double aspect_ratio () const; @@ -112,7 +115,7 @@ public slots: void fit (); private: - typedef lay::mem_chunks chunks_type; + typedef lay::mem_chunks chunks_type; std::auto_ptr mp_mode; QOpenGLShaderProgram *m_shapes_program, *m_gridplane_program; From b2216ec37284b683951039145f6991ff2c58b107 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 17 Apr 2020 11:15:50 +0200 Subject: [PATCH 20/27] WIP: tech component + editor. --- src/db/db/db.pro | 6 +- src/db/db/dbD25TechnologyComponent.cc | 286 ++++++++++++++++++ src/db/db/dbD25TechnologyComponent.h | 152 ++++++++++ .../laybasic/D25TechnologyComponentEditor.ui | 38 +++ .../laybasic/layD25TechnologyComponent.cc | 93 ++++++ .../laybasic/layD25TechnologyComponent.h | 54 ++++ src/laybasic/laybasic/laybasic.pro | 9 +- src/laybasic/laybasic/laybasicResources.qrc | 1 + src/laybasic/laybasic/syntax/d25_text.xml | 76 +++++ .../tools/view_25d/lay_plugin/layD25Plugin.cc | 2 +- 10 files changed, 711 insertions(+), 6 deletions(-) create mode 100644 src/db/db/dbD25TechnologyComponent.cc create mode 100644 src/db/db/dbD25TechnologyComponent.h create mode 100644 src/laybasic/laybasic/D25TechnologyComponentEditor.ui create mode 100644 src/laybasic/laybasic/layD25TechnologyComponent.cc create mode 100644 src/laybasic/laybasic/layD25TechnologyComponent.h create mode 100644 src/laybasic/laybasic/syntax/d25_text.xml diff --git a/src/db/db/db.pro b/src/db/db/db.pro index ea36ff395..81ca2b2c5 100644 --- a/src/db/db/db.pro +++ b/src/db/db/db.pro @@ -184,7 +184,8 @@ SOURCES = \ dbLayoutVsSchematic.cc \ gsiDeclDbNetlistCrossReference.cc \ gsiDeclDbLayoutVsSchematic.cc \ - dbNetlistObject.cc + dbNetlistObject.cc \ + dbD25TechnologyComponent.cc HEADERS = \ dbArray.h \ @@ -331,7 +332,8 @@ HEADERS = \ dbLayoutVsSchematicReader.h \ dbLayoutVsSchematicFormatDefs.h \ dbLayoutVsSchematic.h \ - dbNetlistObject.h + dbNetlistObject.h \ + dbD25TechnologyComponent.h !equals(HAVE_QT, "0") { diff --git a/src/db/db/dbD25TechnologyComponent.cc b/src/db/db/dbD25TechnologyComponent.cc new file mode 100644 index 000000000..7e3742a5e --- /dev/null +++ b/src/db/db/dbD25TechnologyComponent.cc @@ -0,0 +1,286 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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" + "# 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', " + "# 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: zstop=1.5, zstart=0.5 # same as above\n" + "# 1: height=1.0, zstop=1.5 # same as above\n" + "# 1: 1.0 zstop=1.5 # same as above\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) +{ + int current_line = 0; + m_layers.clear (); + + try { + + std::vector lines = tl::split (src, "\n"); + for (std::vector::const_iterator l = lines.begin (); l != lines.end (); ++l) { + + ++current_line; + + tl::Extractor ex (l->c_str ()); + + if (ex.test ("#")) { + // ignore comments + } else if (ex.at_end ()) { + // ignore empty lines + } else { + + db::D25LayerInfo info; + if (! m_layers.empty ()) { + info.set_zstart (m_layers.back ().zstop ()); + info.set_zstop (m_layers.back ().zstop ()); + } + + tl::Variant z0, z1, h; + std::vector args; + + db::LayerProperties lp; + lp.read (ex); + info.set_layer (lp); + + ex.expect (":"); + + while (! ex.at_end ()) { + + double pv = 0.0; + + std::string pn; + if (ex.try_read_name (pn)) { + ex.expect ("="); + ex.read (pv); + } else { + ex.read (pv); + } + + 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.zstart () + 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 if (args.size () == 1) { + info.set_zstop ((! z0.is_nil () ? z0.to_double () : info.zstart ()) + args[0]); + } else if (args.size () == 2) { + info.set_zstart (args[0]); + info.set_zstop (args[1]); + } else { + throw tl::Exception (tl::to_string (tr ("Too many parameters (max 2)"))); + } + + m_layers.push_back (info); + + } + + } + + } catch (tl::Exception &ex) { + throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (" in line %d")), current_line)); + } + + m_src = src; +} + +// ----------------------------------------------------------------------------------- +// D25TechnologyComponent technology component registration + +class D25TechnologyComponentProvider + : public db::TechnologyComponentProvider +{ +public: + D25TechnologyComponentProvider () + : db::TechnologyComponentProvider () + { + // .. nothing yet .. + } + + virtual db::TechnologyComponent *create_component () const + { + return new D25TechnologyComponent (); + } + + virtual tl::XMLElementBase *xml_element () const + { + return new db::TechnologyComponentXMLElement (d25_component_name (), + tl::make_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") + ); + } +}; + +static tl::RegisteredClass tc_decl (new D25TechnologyComponentProvider (), 3100, d25_component_name ().c_str ()); + +} diff --git a/src/db/db/dbD25TechnologyComponent.h b/src/db/db/dbD25TechnologyComponent.h new file mode 100644 index 000000000..8d16796e0 --- /dev/null +++ b/src/db/db/dbD25TechnologyComponent.h @@ -0,0 +1,152 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#ifndef HDR_dbD25TechnologyComponent +#define HDR_dbD25TechnologyComponent + +#include "dbTechnology.h" +#include "dbLayerProperties.h" + +namespace db +{ + +class DB_PUBLIC D25LayerInfo +{ +public: + D25LayerInfo (); + ~D25LayerInfo (); + D25LayerInfo (const D25LayerInfo &other); + D25LayerInfo &operator= (const D25LayerInfo &other); + + bool operator== (const D25LayerInfo &other) const; + + const db::LayerProperties &layer () const + { + return m_layer; + } + + void set_layer_from_string (const std::string &l); + std::string layer_as_string () const; + + void set_layer (const db::LayerProperties &l); + + double zstart () const + { + return m_zstart; + } + + void set_zstart (double z0); + + double zstop () const + { + return m_zstop; + } + + void set_zstop (double z1); + +private: + db::LayerProperties m_layer; + double m_zstart, m_zstop; +}; + +class DB_PUBLIC D25TechnologyComponent + : public db::TechnologyComponent +{ +public: + D25TechnologyComponent (); + D25TechnologyComponent (const D25TechnologyComponent &d); + + typedef std::list layers_type; + 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 (); + } + + 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; + } + + db::TechnologyComponent *clone () const + { + return new D25TechnologyComponent (*this); + } + +private: + layers_type m_layers; + std::string m_src; +}; + +} + +#endif diff --git a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui new file mode 100644 index 000000000..5a8b631cd --- /dev/null +++ b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui @@ -0,0 +1,38 @@ + + + D25TechnologyComponentEditor + + + + 0 + 0 + 549 + 434 + + + + Settings + + + + + + 2.5d Vertical Stack Information + + + + + + + + Monospace + + + + + + + + + + diff --git a/src/laybasic/laybasic/layD25TechnologyComponent.cc b/src/laybasic/laybasic/layD25TechnologyComponent.cc new file mode 100644 index 000000000..4935360f1 --- /dev/null +++ b/src/laybasic/laybasic/layD25TechnologyComponent.cc @@ -0,0 +1,93 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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 +#include + +namespace lay +{ + +D25TechnologyComponentEditor::D25TechnologyComponentEditor (QWidget *parent) + : TechnologyComponentEditor (parent) +{ + setupUi (this); + + // TODO: activate_help_links (mp_ui->help_label); + + QResource res (tl::to_qstring (":/syntax/d25_text.xml")); + QByteArray data ((const char *) res.data (), int (res.size ())); + if (res.isCompressed ()) { + 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 ()); +} + +void +D25TechnologyComponentEditor::commit () +{ + db::D25TechnologyComponent *data = dynamic_cast (tech_component ()); + if (! data) { + return; + } + + std::string src = tl::to_string (src_te->toPlainText ()); + data->compile_from_source (src); +} + +void +D25TechnologyComponentEditor::setup () +{ + db::D25TechnologyComponent *data = dynamic_cast (tech_component ()); + if (! data) { + return; + } + + src_te->setPlainText (tl::to_qstring (data->src ())); +} + +class D25TechnologyComponentEditorProvider + : public lay::TechnologyEditorProvider +{ +public: + virtual lay::TechnologyComponentEditor *create_editor (QWidget *parent) const + { + return new D25TechnologyComponentEditor (parent); + } +}; + +static tl::RegisteredClass editor_decl (new D25TechnologyComponentEditorProvider (), 3100, "d25"); + +} // namespace lay + diff --git a/src/laybasic/laybasic/layD25TechnologyComponent.h b/src/laybasic/laybasic/layD25TechnologyComponent.h new file mode 100644 index 000000000..aeec28b7e --- /dev/null +++ b/src/laybasic/laybasic/layD25TechnologyComponent.h @@ -0,0 +1,54 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + + +#ifndef HDR_layD25TechnologyComponent +#define HDR_layD25TechnologyComponent + +#include "ui_D25TechnologyComponentEditor.h" +#include "layTechnology.h" +#include "layGenericSyntaxHighlighter.h" + +#include + +namespace lay { + +class D25TechnologyComponentEditor + : public lay::TechnologyComponentEditor, + public Ui::D25TechnologyComponentEditor +{ +Q_OBJECT + +public: + D25TechnologyComponentEditor (QWidget *parent); + + void commit (); + void setup (); + +private: + std::auto_ptr mp_hl_attributes, mp_hl_basic_attributes; +}; + +} + +#endif + diff --git a/src/laybasic/laybasic/laybasic.pro b/src/laybasic/laybasic/laybasic.pro index 7a7c8a92e..42c128414 100644 --- a/src/laybasic/laybasic/laybasic.pro +++ b/src/laybasic/laybasic/laybasic.pro @@ -73,7 +73,8 @@ FORMS = \ NetInfoDialog.ui \ NetExportDialog.ui \ SelectCellViewForm.ui \ - LayoutStatistics.ui + LayoutStatistics.ui \ + D25TechnologyComponentEditor.ui RESOURCES = \ laybasicResources.qrc \ @@ -183,7 +184,8 @@ SOURCES = \ layGenericSyntaxHighlighter.cc \ layDispatcher.cc \ laySelectCellViewForm.cc \ - layLayoutStatisticsForm.cc + layLayoutStatisticsForm.cc \ + layD25TechnologyComponent.cc HEADERS = \ gtf.h \ @@ -284,7 +286,8 @@ HEADERS = \ layGenericSyntaxHighlighter.h \ layDispatcher.h \ laySelectCellViewForm.h \ - layLayoutStatisticsForm.h + layLayoutStatisticsForm.h \ + layD25TechnologyComponent.h INCLUDEPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC DEPENDPATH += $$TL_INC $$GSI_INC $$DB_INC $$RDB_INC $$LYM_INC diff --git a/src/laybasic/laybasic/laybasicResources.qrc b/src/laybasic/laybasic/laybasicResources.qrc index 86e08c975..f9243ccc4 100644 --- a/src/laybasic/laybasic/laybasicResources.qrc +++ b/src/laybasic/laybasic/laybasicResources.qrc @@ -45,5 +45,6 @@ images/icon_device_bjt_24.png images/icon_device_bjt_16.png syntax/ur_text.xml + syntax/d25_text.xml diff --git a/src/laybasic/laybasic/syntax/d25_text.xml b/src/laybasic/laybasic/syntax/d25_text.xml new file mode 100644 index 000000000..c845bf7b1 --- /dev/null +++ b/src/laybasic/laybasic/syntax/d25_text.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc index 7f92fcd62..c2042a2f4 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Plugin.cc @@ -108,7 +108,7 @@ public: } }; -static tl::RegisteredClass config_decl (new lay::D25PluginDeclaration (), 3000, "lay::D25Plugin"); +static tl::RegisteredClass config_decl (new lay::D25PluginDeclaration (), 3100, "lay::D25Plugin"); } From ca2b0cd96af9d321056c46a8c716a3bdea4ad5fb Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 17 Apr 2020 16:24:56 +0200 Subject: [PATCH 21/27] Added tests for tech component, syntax highlighter fixed. --- src/db/db/dbD25TechnologyComponent.cc | 31 ++++++-- src/db/db/dbD25TechnologyComponent.h | 2 + .../dbD25TechnologyComponentTests.cc | 70 +++++++++++++++++++ src/db/unit_tests/unit_tests.pro | 3 +- src/laybasic/laybasic/syntax/d25_text.xml | 6 +- 5 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 src/db/unit_tests/dbD25TechnologyComponentTests.cc diff --git a/src/db/db/dbD25TechnologyComponent.cc b/src/db/db/dbD25TechnologyComponent.cc index 7e3742a5e..f710d829a 100644 --- a/src/db/db/dbD25TechnologyComponent.cc +++ b/src/db/db/dbD25TechnologyComponent.cc @@ -134,10 +134,11 @@ D25TechnologyComponent::D25TechnologyComponent () "# '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: zstop=1.5, zstart=0.5 # same as above\n" - "# 1: height=1.0, zstop=1.5 # same as above\n" - "# 1: 1.0 zstop=1.5 # same as above\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" ; } @@ -186,6 +187,10 @@ D25TechnologyComponent::compile_from_source (const std::string &src) while (! ex.at_end ()) { + if (ex.test ("#")) { + break; + } + double pv = 0.0; std::string pn; @@ -227,6 +232,9 @@ D25TechnologyComponent::compile_from_source (const std::string &src) 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) { info.set_zstop ((! z0.is_nil () ? z0.to_double () : info.zstart ()) + args[0]); @@ -250,6 +258,21 @@ D25TechnologyComponent::compile_from_source (const std::string &src) m_src = src; } +std::string +D25TechnologyComponent::to_string () const +{ + std::string res; + + for (const_iterator i = begin (); i != 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 diff --git a/src/db/db/dbD25TechnologyComponent.h b/src/db/db/dbD25TechnologyComponent.h index 8d16796e0..4c31363c1 100644 --- a/src/db/db/dbD25TechnologyComponent.h +++ b/src/db/db/dbD25TechnologyComponent.h @@ -137,6 +137,8 @@ public: m_src = s; } + std::string to_string () const; + db::TechnologyComponent *clone () const { return new D25TechnologyComponent (*this); diff --git a/src/db/unit_tests/dbD25TechnologyComponentTests.cc b/src/db/unit_tests/dbD25TechnologyComponentTests.cc new file mode 100644 index 000000000..3dc872953 --- /dev/null +++ b/src/db/unit_tests/dbD25TechnologyComponentTests.cc @@ -0,0 +1,70 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2020 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.compile_from_source ("1/0: 1.0 1.5 # a comment"); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); + + comp.compile_from_source ("1/0: zstart=1.0 zstop=1.5"); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); + + comp.compile_from_source ("1/0: zstart=1.0 height=0.5"); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); + + comp.compile_from_source ("1/0: zstop=1.5 height=0.5"); + 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"); + 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"); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5\nname: zstart=4, zstop=7"); + + try { + comp.compile_from_source ("blabla"); + EXPECT_EQ (false, true); + } catch (...) { } + + try { + comp.compile_from_source ("1/0: 1 2 3"); + EXPECT_EQ (false, true); + } catch (...) { } + + try { + comp.compile_from_source ("1/0: foo=1 bar=2"); + EXPECT_EQ (false, true); + } catch (...) { } + + try { + comp.compile_from_source ("1/0: 1;2"); + EXPECT_EQ (false, true); + } catch (...) { } +} diff --git a/src/db/unit_tests/unit_tests.pro b/src/db/unit_tests/unit_tests.pro index 5aa37d85e..f69577d0a 100644 --- a/src/db/unit_tests/unit_tests.pro +++ b/src/db/unit_tests/unit_tests.pro @@ -73,7 +73,8 @@ SOURCES = \ dbLayoutQueryTests.cc \ dbPolygonToolsTests.cc \ dbTechnologyTests.cc \ - dbStreamLayerTests.cc + dbStreamLayerTests.cc \ + dbD25TechnologyComponentTests.cc INCLUDEPATH += $$TL_INC $$DB_INC $$GSI_INC DEPENDPATH += $$TL_INC $$DB_INC $$GSI_INC diff --git a/src/laybasic/laybasic/syntax/d25_text.xml b/src/laybasic/laybasic/syntax/d25_text.xml index c845bf7b1..654dd7c93 100644 --- a/src/laybasic/laybasic/syntax/d25_text.xml +++ b/src/laybasic/laybasic/syntax/d25_text.xml @@ -15,7 +15,7 @@ - + @@ -46,13 +46,13 @@ - + - + From 1604c089dc9be1f894a690013447fe047769fc45 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 17 Apr 2020 19:02:13 +0200 Subject: [PATCH 22/27] Link between tech comp and 2.5d view --- .../tools/view_25d/lay_plugin/layD25View.cc | 12 +- .../view_25d/lay_plugin/layD25ViewWidget.cc | 106 +++++++++++++++--- .../view_25d/lay_plugin/layD25ViewWidget.h | 4 +- .../unit_tests/layD25ViewUtilsTests.cc | 16 ++- 4 files changed, 119 insertions(+), 19 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index 158e19f3f..f10ae46ac 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -89,7 +89,16 @@ int D25View::exec_dialog (lay::LayoutView *view) { mp_view.reset (view); - mp_ui->d25_view->attach_view (view); + bool any = mp_ui->d25_view->attach_view (view); + + if (! any) { + + mp_view.reset (0); + mp_ui->d25_view->attach_view (0); + + throw tl::Exception (tl::to_string (tr ("No z data configured for the layers in the view.\nUse \"Tools/Manage Technologies\" to set up a z stack."))); + + } mp_ui->d25_view->reset (); mp_ui->d25_view->set_cam_azimuth (0.0); @@ -98,6 +107,7 @@ D25View::exec_dialog (lay::LayoutView *view) int ret = QDialog::exec (); mp_ui->d25_view->attach_view (0); + mp_view.reset (0); return ret; } diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 48ca09105..52fbd46ca 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -26,6 +26,7 @@ #include "layLayoutView.h" #include "dbRecursiveShapeIterator.h" +#include "dbD25TechnologyComponent.h" #include "dbEdgeProcessor.h" #include "dbPolygonGenerators.h" #include "dbPolygonTools.h" @@ -412,20 +413,88 @@ D25ViewWidget::aspect_ratio () const return double (width ()) / double (height ()); } -void +bool D25ViewWidget::attach_view (LayoutView *view) { + bool any = false; + if (mp_view != view) { mp_view = view; - prepare_view (); + any = prepare_view (); reset (); } + + return any; } -void +namespace { + + class ZDataCache + { + public: + ZDataCache () { } + + const db::D25LayerInfo *operator() (lay::LayoutView *view, int cv_index, int layer_index) + { + std::map >::const_iterator c = m_cache.find (cv_index); + if (c != m_cache.end ()) { + std::map::const_iterator l = c->second.find (layer_index); + if (l != c->second.end ()) { + return l->second; + } else { + return 0; + } + } + + std::map &lcache = m_cache [cv_index]; + + const db::D25TechnologyComponent *comp = 0; + + const lay::CellView &cv = view->cellview (cv_index); + if (cv.is_valid () && cv->technology ()) { + const db::Technology *tech = cv->technology (); + comp = dynamic_cast (tech->component_by_name ("d25")); + } + + if (comp) { + + std::map zi_by_lp; + for (db::D25TechnologyComponent::const_iterator i = comp->begin (); i != comp->end (); ++i) { + zi_by_lp.insert (std::make_pair (i->layer (), i.operator-> ())); + } + + const db::Layout &ly = cv->layout (); + for (int l = 0; l < int (ly.layers ()); ++l) { + if (ly.is_valid_layer (l)) { + const db::LayerProperties &lp = ly.get_properties (l); + std::map::const_iterator z = zi_by_lp.find (lp); + if (z == zi_by_lp.end () && ! lp.name.empty ()) { + // If possible, try by name only + z = zi_by_lp.find (db::LayerProperties (lp.name)); + } + if (z != zi_by_lp.end ()) { + lcache[l] = z->second; + } + } + } + + } + + return operator() (view, cv_index, layer_index); + + } + + + private: + std::map > m_cache; + }; + +} + +bool D25ViewWidget::prepare_view () { m_layers.clear (); @@ -437,14 +506,25 @@ D25ViewWidget::prepare_view () if (! mp_view) { m_bbox = db::DBox (-1.0, -1.0, 1.0, 1.0); - return; + return false; } - double z = 0.0, dz = 0.2; // @@@ + ZDataCache zdata; + bool any = false; for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) { - if (! lp->has_children () && lp->visible (true) && lp->cellview_index () >= 0 && lp->cellview_index () < int (mp_view->cellviews ())) { + const db::D25LayerInfo *zi = 0; + if (! lp->has_children () && lp->visible (true)) { + zi = zdata (mp_view, lp->cellview_index (), lp->layer_index ()); + } + + if (zi) { + + any = true; + + double z0 = zi->zstart (); + double z1 = zi->zstop (); lay::color_t color = lp->fill_color (true); @@ -459,24 +539,24 @@ D25ViewWidget::prepare_view () m_layers.push_back (info); const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ()); - render_layout (m_vertex_chunks.back (), cv->layout (), *cv.cell (), (unsigned int) lp->layer_index (), z, z + dz); + render_layout (m_vertex_chunks.back (), cv->layout (), *cv.cell (), (unsigned int) lp->layer_index (), z0, z1); m_bbox += db::DBox (cv.cell ()->bbox ((unsigned int) lp->layer_index ())) * cv->layout ().dbu (); if (! zset) { - m_zmin = z; - m_zmax = z + dz; + m_zmin = z0; + m_zmax = z1; zset = true; } else { - m_zmin = std::min (z, m_zmin); - m_zmax = std::max (z + dz, m_zmax); + m_zmin = std::min (z0, m_zmin); + m_zmax = std::max (z1, m_zmax); } - z += dz; // @@@ - } } + + return any; } void diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h index ea6d5c790..e23b068a5 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.h @@ -82,7 +82,7 @@ public: void mouseReleaseEvent (QMouseEvent *event); void mouseMoveEvent (QMouseEvent *event); - void attach_view (lay::LayoutView *view); + bool attach_view(lay::LayoutView *view); QVector3D hit_point_with_scene(const QVector3D &line_dir); void refresh (); @@ -138,7 +138,7 @@ private: void paintGL (); void resizeGL (int w, int h); - void prepare_view (); + bool prepare_view(); void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, unsigned int layer, double zstart, double zstop); void render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop); void render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &poly, double dbu, double zstart, double zstop); diff --git a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc index b24265b22..4e428c818 100644 --- a/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc +++ b/src/plugins/tools/view_25d/unit_tests/layD25ViewUtilsTests.cc @@ -92,7 +92,8 @@ TEST(3_HitWithCuboid) EXPECT_EQ (v2s (r.second), "1,1,4"); r = lay::hit_point_with_cuboid (QVector3D (1, 1, 6), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); - EXPECT_EQ (r.first, false); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "1,1,3"); r = lay::hit_point_with_cuboid (QVector3D (5, -6, 0), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); EXPECT_EQ (r.first, true); @@ -100,10 +101,19 @@ TEST(3_HitWithCuboid) r = lay::hit_point_with_cuboid (QVector3D (5, -6, 4), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); EXPECT_EQ (r.first, true); - EXPECT_EQ (v2s (r.second), "5,-6,5"); + EXPECT_EQ (v2s (r.second), "5,-6,3"); r = lay::hit_point_with_cuboid (QVector3D (5, -6, 6), QVector3D (0, 0, 1), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); - EXPECT_EQ (r.first, false); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "5,-6,3"); + + r = lay::hit_point_with_cuboid (QVector3D (5, 0, 0), QVector3D (-1, 0, 0), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "1,0,0"); + + r = lay::hit_point_with_cuboid (QVector3D (-5, 0, 0), QVector3D (1, 0, 0), QVector3D (-1, -1, 3), QVector3D (2, 2, 2)); + EXPECT_EQ (r.first, true); + EXPECT_EQ (v2s (r.second), "-1,0,0"); } TEST(4_CameraNormal) From 747184beef4f66633a674a41368f9a467f3acb4c Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Fri, 17 Apr 2020 23:46:02 +0200 Subject: [PATCH 23/27] Using background color as configured. --- .../view_25d/lay_plugin/layD25ViewWidget.cc | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 52fbd46ca..01d5afdec 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -192,7 +192,6 @@ D25ViewWidget::D25ViewWidget (QWidget *parent) format.setDepthBufferSize (24); format.setSamples (4); // more -> widget extends beyond boundary! format.setStencilBufferSize (8); - // @@@? format.setVersion (3, 2); format.setProfile (QSurfaceFormat::CoreProfile); setFormat (format); @@ -394,10 +393,6 @@ D25ViewWidget::fit () void D25ViewWidget::refresh () { - QVector3D cp = cam_position (); - -printf("@@@ e=%g a=%g x,y,z=%g,%g,%g d=%g,%g,%g s=%g\n", cam_elevation (), cam_azimuth (), cp.x(), cp.y(), cp.z(), m_displacement.x(), m_displacement.y(), m_displacement.z(), m_scale_factor); fflush(stdout); - update (); } @@ -621,7 +616,7 @@ D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layo db::EdgeProcessor ep; std::vector poly_heap; - // @@@ hidden cells, hierarchy depth ... + // TODO: hidden cells, hierarchy depth ... db::RecursiveShapeIterator s (layout, cell, layer); s.shape_flags (db::ShapeIterator::Polygons | db::ShapeIterator::Paths | db::ShapeIterator::Boxes); for ( ; ! s.at_end (); ++s) { @@ -703,10 +698,7 @@ D25ViewWidget::initializeGL () QOpenGLFunctions::initializeOpenGLFunctions(); glEnable (GL_BLEND); - // @@@ dark background glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - // @@@ white background - // @@@ glBlendFunc (GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA); static const char *shapes_vertex_shader_source = "#version 320 es\n" @@ -757,9 +749,12 @@ D25ViewWidget::initializeGL () "#undef mediump\n" "in lowp vec4 vertexColor;\n" "out lowp vec4 fragColor;\n" + "uniform highp float mist_factor;\n" + "uniform highp float mist_add;\n" "\n" "vec4 color_by_z(lowp vec4 c, highp float z) {\n" - " lowp vec4 mist_color = vec4(c.g * 0.4, c.g * 0.4, c.g * 0.4, 1.0);\n" + " highp float mist_rgb = c.g * mist_factor + mist_add;\n" + " lowp vec4 mist_color = vec4(mist_rgb, mist_rgb, mist_rgb, 1.0);\n" " highp float d = 0.12;\n" // d + dd/2 = 0.15 = 1/? " highp float dd = 0.06;\n" " highp float f = 1.0;\n" @@ -833,7 +828,13 @@ D25ViewWidget::paintGL () glViewport (0, 0, width () * retinaScale, height () * retinaScale); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // @@@ white background: glClearColor (1.0, 1.0, 1.0, 1.0); + + QColor c = mp_view->background_color (); + float foreground_rgb = (c.green () > 128 ? 0.0f : 1.0f); + float ambient = (c.green () > 128 ? 1.0f : 0.5f); + float mist_factor = (c.green () > 128 ? 0.2f : 0.4f); + float mist_add = (c.green () > 128 ? 0.8f : 0.2f); + glClearColor (float (c.red ()) / 255.0f, float (c.green ()) / 255.0f, float (c.blue ()) / 255.0f, 1.0); QMatrix4x4 scene_trans, scene_trans_wo_y; @@ -857,7 +858,9 @@ D25ViewWidget::paintGL () // NOTE: z axis of illum points towards the scene because we include the z inversion in the scene transformation matrix m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); - m_shapes_program->setUniformValue ("ambient", QVector4D (0.5, 0.5, 0.5, 0.5)); + m_shapes_program->setUniformValue ("ambient", QVector4D (ambient, ambient, ambient, 0.5)); + m_shapes_program->setUniformValue ("mist_factor", mist_factor); + m_shapes_program->setUniformValue ("mist_add", mist_add); glEnable (GL_DEPTH_TEST); glEnableVertexAttribArray (positions); @@ -912,7 +915,7 @@ D25ViewWidget::paintGL () } - m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.25f); + m_gridplane_program->setUniformValue ("color", foreground_rgb, foreground_rgb, foreground_rgb, 0.25f); glLineWidth (2.0); vertexes.draw_to (this, positions, GL_LINES); @@ -949,7 +952,7 @@ D25ViewWidget::paintGL () for (int major = 0; major < 2; ++major) { - m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, major ? 0.25f : 0.15f); + m_gridplane_program->setUniformValue ("color", foreground_rgb, foreground_rgb, foreground_rgb, major ? 0.25f : 0.15f); double x, y; double step = (major ? gmajor : gminor); @@ -987,7 +990,7 @@ D25ViewWidget::paintGL () vertexes.add (r, 0.0, b); vertexes.add (r, 0.0, t); - m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.1f); + m_gridplane_program->setUniformValue ("color", foreground_rgb, foreground_rgb, foreground_rgb, 0.1f); vertexes.draw_to (this, positions, GL_TRIANGLES); @@ -1045,7 +1048,7 @@ D25ViewWidget::paintGL () vertexes.add (-1.0, 1.0, -1.0); vertexes.add (1.0, 1.0, -1.0); - m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.2f); + m_gridplane_program->setUniformValue ("color", foreground_rgb, foreground_rgb, foreground_rgb, 0.2f); vertexes.draw_to (this, positions, GL_LINES); @@ -1096,7 +1099,7 @@ D25ViewWidget::paintGL () vertexes.add (0.8, -0.8, 1.0); vertexes.add (0.8, -0.6, 1.0); - m_gridplane_program->setUniformValue ("color", 1.0, 1.0, 1.0, 0.3f); + m_gridplane_program->setUniformValue ("color", foreground_rgb, foreground_rgb, foreground_rgb, 0.3f); vertexes.draw_to (this, positions, GL_TRIANGLES); From 07ecaac5989fcd408bcec7dfff17f1f540150bc8 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 18 Apr 2020 00:17:17 +0200 Subject: [PATCH 24/27] Enhancements. --- src/plugins/tools/view_25d/lay_plugin/layD25View.cc | 3 +-- .../tools/view_25d/lay_plugin/layD25ViewWidget.cc | 9 ++++----- src/plugins/tools/view_25d/view_25d.pro | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index f10ae46ac..94855b6e0 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -39,10 +39,8 @@ D25View::D25View (QWidget *parent) mp_ui = new Ui::D25View (); mp_ui->setupUi (this); - // @@@ should be an event filter? 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 ())); @@ -103,6 +101,7 @@ D25View::exec_dialog (lay::LayoutView *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 (); int ret = QDialog::exec (); diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 01d5afdec..8dbe74798 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -731,7 +731,7 @@ D25ViewWidget::initializeGL () " vec4 p2 = gl_in[2].gl_Position;\n" " vec3 n = cross(p2.xyz - p0.xyz, p1.xyz - p0.xyz);\n" " float dp = dot(normalize(n), illum);\n" - " vertexColor = color * (dp * 0.5 + 0.5) - (min(0.0, dp) * 0.5 * ambient);\n" + " vertexColor = color * (dp * 0.5 + 0.5) - (min(0.0, dp) * ambient);\n" " vertexColor.a = 1.0;\n" " gl_Position = matrix * p0;\n" " EmitVertex();\n" @@ -827,14 +827,13 @@ D25ViewWidget::paintGL () const qreal retinaScale = devicePixelRatio (); glViewport (0, 0, width () * retinaScale, height () * retinaScale); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - QColor c = mp_view->background_color (); float foreground_rgb = (c.green () > 128 ? 0.0f : 1.0f); - float ambient = (c.green () > 128 ? 1.0f : 0.5f); + float ambient = (c.green () > 128 ? 0.8f : 0.25f); float mist_factor = (c.green () > 128 ? 0.2f : 0.4f); float mist_add = (c.green () > 128 ? 0.8f : 0.2f); glClearColor (float (c.red ()) / 255.0f, float (c.green ()) / 255.0f, float (c.blue ()) / 255.0f, 1.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); QMatrix4x4 scene_trans, scene_trans_wo_y; @@ -858,7 +857,7 @@ D25ViewWidget::paintGL () // NOTE: z axis of illum points towards the scene because we include the z inversion in the scene transformation matrix m_shapes_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ()); - m_shapes_program->setUniformValue ("ambient", QVector4D (ambient, ambient, ambient, 0.5)); + m_shapes_program->setUniformValue ("ambient", QVector4D (ambient, ambient, ambient, 1.0)); m_shapes_program->setUniformValue ("mist_factor", mist_factor); m_shapes_program->setUniformValue ("mist_add", mist_add); diff --git a/src/plugins/tools/view_25d/view_25d.pro b/src/plugins/tools/view_25d/view_25d.pro index 1f10c85ca..30278d0c8 100644 --- a/src/plugins/tools/view_25d/view_25d.pro +++ b/src/plugins/tools/view_25d/view_25d.pro @@ -1,6 +1,6 @@ TEMPLATE = subdirs -!equals(HAVE_QT, "0") { +equals(HAVE_QT5, "1") { SUBDIRS = lay_plugin unit_tests } From 2cdcf621d8fbb3d4df240d8e30a4541304ae7b68 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 18 Apr 2020 00:37:15 +0200 Subject: [PATCH 25/27] D25 tech component editor: line numbers shown, more syntax variants --- src/db/db/dbD25TechnologyComponent.cc | 25 ++++++++++++++++++- .../dbD25TechnologyComponentTests.cc | 3 +++ .../laybasic/D25TechnologyComponentEditor.ui | 22 +++++++++++++--- .../laybasic/layD25TechnologyComponent.cc | 9 +++++++ .../laybasic/layD25TechnologyComponent.h | 3 +++ src/laybasic/laybasic/syntax/d25_text.xml | 2 +- 6 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/db/db/dbD25TechnologyComponent.cc b/src/db/db/dbD25TechnologyComponent.cc index f710d829a..1ab0ed2ea 100644 --- a/src/db/db/dbD25TechnologyComponent.cc +++ b/src/db/db/dbD25TechnologyComponent.cc @@ -237,8 +237,31 @@ D25TechnologyComponent::compile_from_source (const std::string &src) info.set_zstop (z1.to_double ()); } } else if (args.size () == 1) { - info.set_zstop ((! z0.is_nil () ? z0.to_double () : info.zstart ()) + args[0]); + if (! h.is_nil ()) { + if (! z0.is_nil ()) { + throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstart already given"))); + } + if (! z1.is_nil ()) { + throw tl::Exception (tl::to_string (tr ("Rundundant 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"))); + } + 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"))); + } + if (! z1.is_nil ()) { + throw tl::Exception (tl::to_string (tr ("Rundundant parameters: zstop already given"))); + } + if (! h.is_nil ()) { + throw tl::Exception (tl::to_string (tr ("Rundundant parameters: height implicitly given"))); + } info.set_zstart (args[0]); info.set_zstop (args[1]); } else { diff --git a/src/db/unit_tests/dbD25TechnologyComponentTests.cc b/src/db/unit_tests/dbD25TechnologyComponentTests.cc index 3dc872953..181ccb92a 100644 --- a/src/db/unit_tests/dbD25TechnologyComponentTests.cc +++ b/src/db/unit_tests/dbD25TechnologyComponentTests.cc @@ -39,6 +39,9 @@ TEST(1) comp.compile_from_source ("1/0: zstart=1.0 height=0.5"); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); + comp.compile_from_source ("1/0: 1.0 height=0.5"); + EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); + comp.compile_from_source ("1/0: zstop=1.5 height=0.5"); EXPECT_EQ (comp.to_string (), "1/0: zstart=1, zstop=1.5"); diff --git a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui index 5a8b631cd..b1901ba63 100644 --- a/src/laybasic/laybasic/D25TechnologyComponentEditor.ui +++ b/src/laybasic/laybasic/D25TechnologyComponentEditor.ui @@ -13,15 +13,31 @@ Settings - - + + 2.5d Vertical Stack Information - + + + + + 0 + 0 + + + + Line + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + diff --git a/src/laybasic/laybasic/layD25TechnologyComponent.cc b/src/laybasic/laybasic/layD25TechnologyComponent.cc index 4935360f1..c004b4a1f 100644 --- a/src/laybasic/laybasic/layD25TechnologyComponent.cc +++ b/src/laybasic/laybasic/layD25TechnologyComponent.cc @@ -52,6 +52,15 @@ D25TechnologyComponentEditor::D25TechnologyComponentEditor (QWidget *parent) 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 diff --git a/src/laybasic/laybasic/layD25TechnologyComponent.h b/src/laybasic/laybasic/layD25TechnologyComponent.h index aeec28b7e..206838b70 100644 --- a/src/laybasic/laybasic/layD25TechnologyComponent.h +++ b/src/laybasic/laybasic/layD25TechnologyComponent.h @@ -44,6 +44,9 @@ public: void commit (); void setup (); +private slots: + void cursor_position_changed (); + private: std::auto_ptr mp_hl_attributes, mp_hl_basic_attributes; }; diff --git a/src/laybasic/laybasic/syntax/d25_text.xml b/src/laybasic/laybasic/syntax/d25_text.xml index 654dd7c93..5e0877b74 100644 --- a/src/laybasic/laybasic/syntax/d25_text.xml +++ b/src/laybasic/laybasic/syntax/d25_text.xml @@ -63,7 +63,7 @@ - + From d117e024f08f44a190fa6fe81c22d5493fdf0a99 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 18 Apr 2020 00:38:25 +0200 Subject: [PATCH 26/27] Removed TODO markers --- src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc | 4 ++-- src/plugins/tools/view_25d/lay_plugin/layD25View.cc | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc index 3d8fb12ef..f2d358c8d 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25Camera.cc @@ -58,13 +58,13 @@ D25Camera::camera_reset () double D25Camera::cam_fov () const { - return m_fov; // @@@ + return m_fov; } double D25Camera::cam_dist () const { - return 4.0; // @@@ + return 4.0; } QVector3D diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc index 94855b6e0..fd8d57bac 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25View.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25View.cc @@ -145,7 +145,6 @@ void D25View::accept () { QDialog::accept (); - // @@@ } } From 5c6d3775cb265b2e43abc52952716f8beccb15cb Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Mon, 31 Aug 2020 00:45:49 +0200 Subject: [PATCH 27/27] Fixed a compilation issue for a shader program. --- src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc index 8dbe74798..ff9fc8f2a 100644 --- a/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc +++ b/src/plugins/tools/view_25d/lay_plugin/layD25ViewWidget.cc @@ -752,7 +752,7 @@ D25ViewWidget::initializeGL () "uniform highp float mist_factor;\n" "uniform highp float mist_add;\n" "\n" - "vec4 color_by_z(lowp vec4 c, highp float z) {\n" + "lowp vec4 color_by_z(lowp vec4 c, highp float z) {\n" " highp float mist_rgb = c.g * mist_factor + mist_add;\n" " lowp vec4 mist_color = vec4(mist_rgb, mist_rgb, mist_rgb, 1.0);\n" " highp float d = 0.12;\n" // d + dd/2 = 0.15 = 1/?