Merge pull request #901 from KLayout/25d-view-enhancements

25d view enhancements
This commit is contained in:
Matthias Köfferlein 2021-09-23 22:33:56 +02:00 committed by GitHub
commit e77ef66b2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 611 additions and 162 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

@ -143,5 +143,38 @@ end
<li> Up/down/left/right keys: move the pivot on the horizontal plane </li>
</ul>
<p>
Note: if the Shift key does not switch to top level view, click into the
scene view once.
</p>
<h2>Colors in the 2.5d View</h2>
<p>
While the 2.5d view window is open, the layout view is still active. Layer
colors are applied also to the 2.5d view. Changing the fill color will change
the 2.5d view's face color. The frame color will be applied to the wire frame.
If a hollow stipple is selected, only the wire frame is shown. If a layer is
made invisible in the layout view, the corresponding blocks will also be
made invisible in the 2.5d view.
</p>
<h2>Other controls</h2>
<p>
The left zoom slider changes the overall scale factor. The right slider only changes the z (height) axis zoom factor.
This is useful as in many cases, the real height profile will result in a rather flat arrangement. Increasing the
z zoom factor will exaggerate the vertical axis hence making height variations more pronounced.
</p>
<p>
The edit boxes next to the scale sliders allow entering the scale factors manually.
</p>
<p>
The button bar at the top right side holds the view presets. Use them to reset the window to
front view, top view etc.
</p>
</doc>

View File

@ -73,6 +73,9 @@
<height>16777215</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="minimum">
<number>-300</number>
</property>
@ -85,9 +88,28 @@
</widget>
</item>
<item>
<widget class="QLabel" name="zoom_factor">
<widget class="QLabel" name="percent_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>x</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="zoom_factor">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -98,8 +120,79 @@
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>8</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>%</string>
<string>Z</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="vzoom_slider">
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="minimum">
<number>-300</number>
</property>
<property name="maximum">
<number>300</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>x</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="vzoom_factor">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
@ -357,12 +450,25 @@
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Close</string>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
</widget>
</item>
@ -383,18 +489,18 @@
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<sender>pushButton</sender>
<signal>clicked()</signal>
<receiver>D25View</receiver>
<slot>accept()</slot>
<slot>hide()</slot>
<hints>
<hint type="sourcelabel">
<x>530</x>
<y>626</y>
<x>808</x>
<y>634</y>
</hint>
<hint type="destinationlabel">
<x>443</x>
<y>643</y>
<x>767</x>
<y>659</y>
</hint>
</hints>
</connection>

View File

@ -32,7 +32,7 @@ namespace lay
D25Camera::D25Camera ()
{
init ();
camera_init ();
}
D25Camera::~D25Camera ()
@ -41,7 +41,7 @@ D25Camera::~D25Camera ()
}
void
D25Camera::init ()
D25Camera::camera_init ()
{
m_fov = 45.0;
m_cam_azimuth = m_cam_elevation = 0.0;
@ -51,7 +51,7 @@ D25Camera::init ()
void
D25Camera::camera_reset ()
{
init ();
camera_init ();
camera_changed ();
}

View File

@ -123,6 +123,11 @@ public:
*/
void camera_reset ();
/**
* @brief Resets the camera's orientation but does not call "camera_changed"
*/
void camera_init ();
protected:
virtual void camera_changed () { }
virtual double aspect_ratio () const { return 1.0; }
@ -133,7 +138,6 @@ private:
QVector3D m_displacement;
double m_fov;
void init ();
};
}

View File

@ -57,7 +57,6 @@ struct gl_type2enum<float>
*/
template <class Obj, size_t ChunkLen = 1024>
class mem_chunks
: public QDialog
{
public:

View File

@ -32,34 +32,6 @@
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") {
mp_dialog->exec_dialog (mp_view);
}
}
private:
lay::LayoutView *mp_view;
lay::D25View *mp_dialog;
};
class D25PluginDeclaration
: public lay::PluginDeclaration
{
@ -98,7 +70,7 @@ public:
lay::Plugin *create_plugin (db::Manager *, lay::Dispatcher *root, lay::LayoutView *view) const
{
return new D25Plugin (root, view);
return new D25View (root, view);
}
};

View File

@ -34,8 +34,8 @@ namespace lay
const double initial_elevation = 15.0;
D25View::D25View (QWidget *parent)
: QDialog (parent)
D25View::D25View (lay::Dispatcher *root, lay::LayoutView *view)
: lay::Browser (root, view, "d25_view")
{
mp_ui = new Ui::D25View ();
mp_ui->setupUi (this);
@ -50,24 +50,73 @@ D25View::D25View (QWidget *parent)
connect (mp_ui->fit_top, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ()));
connect (mp_ui->fit_bottom, SIGNAL (clicked ()), this, SLOT (fit_button_clicked ()));
connect (mp_ui->zoom_slider, SIGNAL (valueChanged (int)), this, SLOT (scale_slider_changed (int)));
connect (mp_ui->vzoom_slider, SIGNAL (valueChanged (int)), this, SLOT (vscale_slider_changed (int)));
connect (mp_ui->zoom_factor, SIGNAL (editingFinished ()), this, SLOT (scale_value_edited ()));
connect (mp_ui->vzoom_factor, SIGNAL (editingFinished ()), this, SLOT (vscale_value_edited ()));
connect (mp_ui->d25_view, SIGNAL (scale_factor_changed (double)), this, SLOT (scale_factor_changed (double)));
connect (mp_ui->d25_view, SIGNAL (vscale_factor_changed (double)), this, SLOT (vscale_factor_changed (double)));
connect (mp_ui->d25_view, SIGNAL (init_failed ()), this, SLOT (init_failed ()));
mp_ui->gl_stack->setCurrentIndex (0);
lay::activate_help_links (mp_ui->doc_label);
view->cellviews_changed_event.add (this, &D25View::cellviews_changed);
view->layer_list_changed_event.add (this, &D25View::layer_properties_changed);
}
D25View::~D25View ()
{
delete mp_ui;
mp_ui = 0;
if (view ()) {
view ()->cellviews_changed_event.remove (this, &D25View::cellviews_changed);
}
}
void
D25View::cellviews_changed ()
{
deactivate ();
}
void
D25View::layer_properties_changed (int)
{
mp_ui->d25_view->refresh_view ();
}
void
D25View::menu_activated (const std::string &symbol)
{
if (symbol == "lay::d25_view") {
const lay::CellView &cv = view ()->cellview (view ()->active_cellview_index ());
if (cv.is_valid ()) {
show ();
activateWindow ();
raise ();
try {
activate ();
} catch (...) {
deactivate ();
throw;
}
}
} else {
lay::Browser::menu_activated (symbol);
}
}
static QString scale_factor_to_string (double f)
{
QString s;
s.sprintf ("x %.3g", f);
s.sprintf ("%.3g", f);
return s;
}
@ -78,6 +127,34 @@ D25View::init_failed ()
mp_ui->gl_stack->setCurrentIndex (1);
}
void
D25View::scale_value_edited ()
{
double f = mp_ui->d25_view->scale_factor ();
try {
tl::from_string (tl::to_string (mp_ui->zoom_factor->text ()), f);
f = std::min (1e6, std::max (1e-6, f));
} catch (...) {
// ignore exceptions
}
mp_ui->d25_view->set_scale_factor (f);
scale_factor_changed (f);
}
void
D25View::vscale_value_edited ()
{
double f = mp_ui->d25_view->vscale_factor ();
try {
tl::from_string (tl::to_string (mp_ui->vzoom_factor->text ()), f);
f = std::min (1e6, std::max (1e-6, f));
} catch (...) {
// ignore exceptions
}
mp_ui->d25_view->set_vscale_factor (f);
vscale_factor_changed (f);
}
void
D25View::scale_slider_changed (int value)
{
@ -96,32 +173,43 @@ D25View::scale_factor_changed (double f)
mp_ui->zoom_slider->blockSignals (false);
}
int
D25View::exec_dialog (lay::LayoutView *view)
void
D25View::vscale_slider_changed (int value)
{
mp_view.reset (view);
bool any = mp_ui->d25_view->attach_view (view);
double f = exp (log (10.0) * -0.01 * value);
mp_ui->vzoom_factor->setText (scale_factor_to_string (f));
mp_ui->d25_view->set_vscale_factor (f);
}
void
D25View::vscale_factor_changed (double f)
{
mp_ui->vzoom_factor->setText (scale_factor_to_string (f));
int v = floor (0.5 - log10 (f) * 100.0);
mp_ui->vzoom_slider->blockSignals (true);
mp_ui->vzoom_slider->setValue (v);
mp_ui->vzoom_slider->blockSignals (false);
}
void
D25View::deactivated ()
{
mp_ui->d25_view->attach_view (0);
}
void
D25View::activated ()
{
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);
mp_ui->d25_view->set_cam_elevation (-initial_elevation);
mp_ui->d25_view->fit ();
int ret = QDialog::exec ();
mp_ui->d25_view->attach_view (0);
mp_view.reset (0);
return ret;
}
void
@ -162,5 +250,11 @@ D25View::accept ()
QDialog::accept ();
}
void
D25View::reject ()
{
QDialog::reject ();
}
}

View File

@ -26,6 +26,7 @@
#include <QDialog>
#include "tlObject.h"
#include "layBrowser.h"
namespace Ui
{
@ -41,28 +42,37 @@ namespace lay
{
class D25View
: public QDialog
: public lay::Browser
{
Q_OBJECT
public:
D25View (QWidget *parent);
D25View (lay::Dispatcher *root, lay::LayoutView *view);
~D25View ();
int exec_dialog (lay::LayoutView *view);
virtual void menu_activated (const std::string &symbol);
virtual void deactivated ();
virtual void activated ();
protected:
void accept ();
void reject ();
private slots:
void fit_button_clicked ();
void scale_factor_changed (double f);
void scale_slider_changed (int value);
void scale_value_edited ();
void vscale_factor_changed (double f);
void vscale_slider_changed (int value);
void vscale_value_edited ();
void init_failed ();
private:
Ui::D25View *mp_ui;
tl::weak_ptr<lay::LayoutView> mp_view;
void cellviews_changed ();
void layer_properties_changed (int);
};
}

View File

@ -117,15 +117,11 @@ hit_point_with_cuboid (const QVector3D &line, const QVector3D &line_dir, const Q
double min_dist = 0.0;
int min_dist_index = -1;
QVector3D ld_norm = line_dir.normalized ();
for (std::vector<std::pair<bool, QVector3D> >::const_iterator i = cutpoints.begin (); i != cutpoints.end (); ++i) {
if (i->first) {
double dist = QVector3D::dotProduct (i->second - line, ld_norm);
if (min_dist_index < 0) {
min_dist = dist;
min_dist_index = int (i - cutpoints.begin ());
} else if (dist < min_dist) {
double dist = QVector3D::dotProduct (i->second - line, line_dir);
if (min_dist_index < 0 || dist < min_dist) {
min_dist = dist;
min_dist_index = int (i - cutpoints.begin ());
}

View File

@ -33,6 +33,7 @@
#include "dbClip.h"
#include "tlException.h"
#include "tlProgress.h"
#include <QWheelEvent>
#include <QMouseEvent>
@ -100,7 +101,7 @@ public:
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 ());
view ()->set_displacement (m_start_displacement + drag / view ()->scale_factors ());
}
private:
@ -190,7 +191,7 @@ private:
D25ViewWidget::D25ViewWidget (QWidget *parent)
: QOpenGLWidget (parent),
m_shapes_program (0), m_gridplane_program (0)
m_shapes_program (0), m_lines_program (0), m_gridplane_program (0)
{
QSurfaceFormat format;
format.setDepthBufferSize (24);
@ -200,6 +201,8 @@ D25ViewWidget::D25ViewWidget (QWidget *parent)
m_zmin = m_zmax = 0.0;
mp_view = 0;
reset_viewport ();
}
D25ViewWidget::~D25ViewWidget ()
@ -209,17 +212,29 @@ D25ViewWidget::~D25ViewWidget ()
makeCurrent ();
delete m_shapes_program;
delete m_lines_program;
delete m_gridplane_program;
doneCurrent ();
}
void
D25ViewWidget::reset ()
D25ViewWidget::reset_viewport ()
{
m_scale_factor = 1.0;
m_vscale_factor = 1.0;
mp_mode.reset (0);
camera_reset ();
camera_init ();
}
void
D25ViewWidget::reset ()
{
reset_viewport ();
emit scale_factor_changed (m_scale_factor);
emit vscale_factor_changed (m_vscale_factor);
refresh ();
}
void
@ -257,7 +272,7 @@ D25ViewWidget::wheelEvent (QWheelEvent *event)
t.rotate (cam_azimuth (), 0.0, 1.0, 0.0);
QVector3D cd = t.inverted ().map (QVector3D (0, 0, cam_dist ()));
m_displacement += d * cd;
m_displacement += d * cd / m_scale_factor;
} else {
@ -354,8 +369,8 @@ 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 corner = (QVector3D (m_bbox.left (), m_zmin, -(m_bbox.bottom () + m_bbox.height ())) + m_displacement) * scale_factors ();
QVector3D dim = QVector3D (m_bbox.width (), m_zmax - m_zmin, m_bbox.height ()) * scale_factors ();
QVector3D line = cam_position ();
std::pair<bool, QVector3D> hp = lay::hit_point_with_cuboid (line, line_dir, corner, dim);
@ -404,28 +419,47 @@ inline double square (double x) { return x * x; }
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));
if (m_bbox.empty ()) {
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_scale_factor = 1.0;
m_displacement = QVector3D ();
// 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 ()));
QVector3D dim = QVector3D (m_bbox.width (), (m_zmax - m_zmin) * m_vscale_factor, m_bbox.height ());
QVector3D bll = QVector3D (m_bbox.left (), m_zmin * m_vscale_factor, -(m_bbox.bottom () + m_bbox.height ()));
double d = std::max (dh, fabs (sin (cam_elevation ()) * dv));
m_scale_factor = 1e6;
double tfov = tan (cam_fov () / 360.0 * M_PI);
double tfovh = aspect_ratio () * tfov;
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);
for (unsigned int i = 0; i < 8; ++i) {
m_displacement = (new_center_in_scene - dim * 0.5) / m_scale_factor - bll;
m_displacement.setY (0.0);
QVector3D p ((i & 1) == 0 ? -0.5 * dim.x () : 0.5 * dim.x (), bll.y () + ((i & 2) == 0 ? 0.0 : dim.y ()), (i & 4) == 0 ? -0.5 * dim.z () : 0.5 * dim.z ());
p = cam_trans () * p;
double d;
d = std::abs (p.x ()) + tfovh * p.z ();
if (d > 1e-6) {
m_scale_factor = std::min (m_scale_factor, cam_dist () * tfovh / d);
}
d = std::abs (p.y ()) + tfov * p.z ();
if (d > 1e-6) {
m_scale_factor = std::min (m_scale_factor, cam_dist () * tfov / d);
}
}
// create some margin
m_scale_factor *= 0.95;
// Reset displacement to center the scene
m_displacement = -(bll + dim * 0.5);
m_displacement.setY (0.0);
}
refresh ();
@ -438,6 +472,13 @@ D25ViewWidget::refresh ()
update ();
}
void
D25ViewWidget::showEvent (QShowEvent *)
{
// NOTE: This should happen automatically, but apparently the OpenGL widget doesn't do an automatic refresh:
update ();
}
void
D25ViewWidget::camera_changed ()
{
@ -453,16 +494,10 @@ D25ViewWidget::aspect_ratio () const
bool
D25ViewWidget::attach_view (LayoutView *view)
{
bool any = false;
mp_view = view;
if (mp_view != view) {
mp_view = view;
any = prepare_view ();
reset ();
}
bool any = prepare_view ();
reset ();
return any;
}
@ -474,19 +509,19 @@ namespace {
public:
ZDataCache () { }
const db::D25LayerInfo *operator() (lay::LayoutView *view, int cv_index, int layer_index)
std::vector<db::D25LayerInfo> operator() (lay::LayoutView *view, int cv_index, int layer_index)
{
std::map<int, std::map<int, db::D25LayerInfo> >::const_iterator c = m_cache.find (cv_index);
std::map<int, std::map<int, std::vector<db::D25LayerInfo> > >::const_iterator c = m_cache.find (cv_index);
if (c != m_cache.end ()) {
std::map<int, db::D25LayerInfo>::const_iterator l = c->second.find (layer_index);
std::map<int, std::vector<db::D25LayerInfo> >::const_iterator l = c->second.find (layer_index);
if (l != c->second.end ()) {
return &l->second;
return l->second;
} else {
return 0;
return std::vector<db::D25LayerInfo> ();
}
}
std::map<int, db::D25LayerInfo> &lcache = m_cache [cv_index];
std::map<int, std::vector<db::D25LayerInfo> > &lcache = m_cache [cv_index];
const db::D25TechnologyComponent *comp = 0;
@ -498,7 +533,7 @@ namespace {
if (comp) {
std::map<db::LayerProperties, db::D25LayerInfo, db::LPLogicalLessFunc> zi_by_lp;
std::multimap<db::LayerProperties, db::D25LayerInfo, db::LPLogicalLessFunc> zi_by_lp;
db::D25TechnologyComponent::layers_type layers = comp->compile_from_source ();
for (db::D25TechnologyComponent::layers_type::const_iterator i = layers.begin (); i != layers.end (); ++i) {
@ -508,36 +543,68 @@ namespace {
const db::Layout &ly = cv->layout ();
for (int l = 0; l < int (ly.layers ()); ++l) {
if (ly.is_valid_layer (l)) {
const db::LayerProperties &lp = ly.get_properties (l);
std::map<db::LayerProperties, db::D25LayerInfo, db::LPLogicalLessFunc>::const_iterator z = zi_by_lp.find (lp);
if (z == zi_by_lp.end () && ! lp.name.empty ()) {
db::LayerProperties lp = ly.get_properties (l);
std::multimap<db::LayerProperties, db::D25LayerInfo, db::LPLogicalLessFunc>::const_iterator z = zi_by_lp.find (lp);
if ((z == zi_by_lp.end () || ! z->first.log_equal (lp)) && ! lp.name.empty ()) {
// If possible, try by name only
z = zi_by_lp.find (db::LayerProperties (lp.name));
lp = db::LayerProperties (lp.name);
z = zi_by_lp.find (lp);
}
if (z != zi_by_lp.end ()) {
lcache[l] = z->second;
while (z != zi_by_lp.end () && z->first.log_equal (lp)) {
lcache[l].push_back (z->second);
++z;
}
}
}
}
return operator() (view, cv_index, layer_index);
std::map<int, std::vector<db::D25LayerInfo> >::const_iterator l = lcache.find (layer_index);
if (l != lcache.end ()) {
return l->second;
} else {
return std::vector<db::D25LayerInfo> ();
}
}
private:
std::map<int, std::map<int, db::D25LayerInfo> > m_cache;
std::map<int, std::map<int, std::vector<db::D25LayerInfo> > > m_cache;
};
}
static void color_to_gl (color_t color, GLfloat (&gl_color) [4])
{
gl_color[0] = ((color >> 16) & 0xff) / 255.0f;
gl_color[1] = ((color >> 8) & 0xff) / 255.0f;
gl_color[2] = (color & 0xff) / 255.0f;
gl_color[3] = 1.0f;
}
void
D25ViewWidget::lp_to_info (const lay::LayerPropertiesNode &lp, LayerInfo &info)
{
color_to_gl (lp.fill_color (true), info.color);
if (lp.dither_pattern (true) == 1 /*hollow*/) {
info.color [3] = 0.0f;
}
color_to_gl (lp.frame_color (true), info.frame_color);
if (lp.frame_color (true) == lp.fill_color (true) && info.color [3] > 0.5) {
// optimize: don't draw wire frame unless required
info.frame_color [3] = 0.0f;
}
info.visible = lp.visible (true);
}
bool
D25ViewWidget::prepare_view ()
{
m_layers.clear ();
m_layer_to_info.clear ();
m_vertex_chunks.clear ();
m_line_chunks.clear ();
bool zset = false;
m_zmin = m_zmax = 0.0;
@ -550,36 +617,60 @@ D25ViewWidget::prepare_view ()
m_bbox = mp_view->viewport ().box ();
ZDataCache zdata;
// collect and confine to cell bbox
db::DBox cell_bbox;
for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) {
std::vector<db::D25LayerInfo> zinfo;
if (! lp->has_children ()) {
zinfo = zdata (mp_view, lp->cellview_index (), lp->layer_index ());
}
for (std::vector<db::D25LayerInfo>::const_iterator zi = zinfo.begin (); zi != zinfo.end (); ++zi) {
const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ());
cell_bbox += db::CplxTrans (cv->layout ().dbu ()) * cv.cell ()->bbox ((unsigned int) lp->layer_index ());
}
}
m_bbox &= cell_bbox;
if (m_bbox.empty ()) {
return false;
}
bool any = false;
tl::AbsoluteProgress progress (tl::to_string (tr ("Rendering ...")));
for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) {
const db::D25LayerInfo *zi = 0;
if (! lp->has_children () && lp->visible (true)) {
zi = zdata (mp_view, lp->cellview_index (), lp->layer_index ());
std::vector<db::D25LayerInfo> zinfo;
if (! lp->has_children ()) {
zinfo = zdata (mp_view, lp->cellview_index (), lp->layer_index ());
}
if (zi) {
for (std::vector<db::D25LayerInfo>::const_iterator zi = zinfo.begin (); zi != zinfo.end (); ++zi) {
any = true;
double z0 = zi->zstart ();
double z1 = zi->zstop ();
lay::color_t color = lp->fill_color (true);
m_vertex_chunks.push_back (chunks_type ());
m_vertex_chunks.push_back (triangle_chunks_type ());
m_line_chunks.push_back (line_chunks_type ());
LayerInfo info;
info.color[0] = ((color >> 16) & 0xff) / 255.0f;
info.color[1] = ((color >> 8) & 0xff) / 255.0f;
info.color[2] = (color & 0xff) / 255.0f;
lp_to_info (*lp, info);
info.vertex_chunk = &m_vertex_chunks.back ();
info.line_chunk = &m_line_chunks.back ();
m_layer_to_info.insert (std::make_pair (std::make_pair (lp->cellview_index (), lp->layer_index ()), m_layers.size ()));
m_layers.push_back (info);
const lay::CellView &cv = mp_view->cellview ((unsigned int) lp->cellview_index ());
render_layout (m_vertex_chunks.back (), cv->layout (), *cv.cell (), db::CplxTrans (cv->layout ().dbu ()).inverted () * m_bbox, (unsigned int) lp->layer_index (), z0, z1);
render_layout (progress, m_vertex_chunks.back (), m_line_chunks.back (), cv->layout (), *cv.cell (), db::CplxTrans (cv->layout ().dbu ()).inverted () * m_bbox, (unsigned int) lp->layer_index (), z0, z1);
if (! zset) {
m_zmin = z0;
@ -598,10 +689,36 @@ D25ViewWidget::prepare_view ()
}
void
D25ViewWidget::render_polygon (D25ViewWidget::chunks_type &chunks, const db::Polygon &poly, double dbu, double zstart, double zstop)
D25ViewWidget::refresh_view ()
{
if (! mp_view) {
return;
}
for (lay::LayerPropertiesConstIterator lp = mp_view->begin_layers (); ! lp.at_end (); ++lp) {
std::pair<size_t, size_t> key = std::make_pair (lp->cellview_index (), lp->layer_index ());
std::multimap<std::pair<size_t, size_t>, size_t>::const_iterator l = m_layer_to_info.find (key);
while (l != m_layer_to_info.end () && l->first == key) {
if (l->second < m_layers.size ()) {
lp_to_info (*lp, m_layers [l->second]);
}
++l;
}
}
refresh ();
}
void
D25ViewWidget::render_polygon (D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Polygon &poly, double dbu, double zstart, double zstop)
{
if (poly.holes () > 0) {
// NOTE: line_chunks isn't really used as of now. "render_wall" does the job.
std::vector<db::Polygon> poly_heap;
db::EdgeProcessor ep;
@ -612,7 +729,7 @@ D25ViewWidget::render_polygon (D25ViewWidget::chunks_type &chunks, const db::Pol
ep.process (out, op);
for (std::vector<db::Polygon>::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) {
render_polygon (chunks, *p, dbu, zstart, zstop);
render_polygon (chunks, line_chunks, *p, dbu, zstart, zstop);
}
} else if (poly.hull ().size () > 4) {
@ -621,7 +738,7 @@ D25ViewWidget::render_polygon (D25ViewWidget::chunks_type &chunks, const db::Pol
db::split_polygon (poly, poly_heap);
for (std::vector<db::Polygon>::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) {
render_polygon (chunks, *p, dbu, zstart, zstop);
render_polygon (chunks, line_chunks, *p, dbu, zstart, zstop);
}
} else if (poly.hull ().size () >= 3) {
@ -658,7 +775,7 @@ 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)
D25ViewWidget::render_wall (D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Edge &edge, double dbu, double zstart, double zstop)
{
chunks.add (edge.p1 ().x () * dbu, zstart, edge.p1 ().y () * dbu);
chunks.add (edge.p2 ().x () * dbu, zstop, edge.p2 ().y () * dbu);
@ -666,10 +783,17 @@ D25ViewWidget::render_wall (D25ViewWidget::chunks_type &chunks, const db::Edge &
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);
line_chunks.add (edge.p1 ().x () * dbu, zstart, edge.p1 ().y () * dbu);
line_chunks.add (edge.p2 ().x () * dbu, zstart, edge.p2 ().y () * dbu);
line_chunks.add (edge.p2 ().x () * dbu, zstart, edge.p2 ().y () * dbu);
line_chunks.add (edge.p2 ().x () * dbu, zstop, edge.p2 ().y () * dbu);
line_chunks.add (edge.p2 ().x () * dbu, zstop, edge.p2 ().y () * dbu);
line_chunks.add (edge.p1 ().x () * dbu, zstop, edge.p1 ().y () * dbu);
}
void
D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, const db::Box &clip_box, unsigned int layer, double zstart, double zstop)
D25ViewWidget::render_layout (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Layout &layout, const db::Cell &cell, const db::Box &clip_box, unsigned int layer, double zstart, double zstop)
{
std::vector<db::Polygon> poly_heap;
@ -688,10 +812,12 @@ D25ViewWidget::render_layout (D25ViewWidget::chunks_type &chunks, const db::Layo
for (std::vector<db::Polygon>::const_iterator p = poly_heap.begin (); p != poly_heap.end (); ++p) {
render_polygon (chunks, *p, layout.dbu (), zstart, zstop);
++progress;
render_polygon (chunks, line_chunks, *p, layout.dbu (), zstart, zstop);
for (db::Polygon::polygon_edge_iterator e = p->begin_edge (); ! e.at_end (); ++e) {
render_wall (chunks, *e, layout.dbu (), zstart, zstop);
render_wall (chunks, line_chunks, *e, layout.dbu (), zstart, zstop);
}
}
@ -724,6 +850,7 @@ D25ViewWidget::initializeGL ()
{
tl_assert (m_shapes_program == 0);
tl_assert (m_gridplane_program == 0);
tl_assert (m_lines_program == 0);
bool error = false;
@ -744,6 +871,8 @@ D25ViewWidget::initializeGL ()
delete m_shapes_program;
m_shapes_program = 0;
delete m_lines_program;
m_lines_program = 0;
delete m_gridplane_program;
m_gridplane_program = 0;
@ -837,6 +966,53 @@ D25ViewWidget::do_initialize_gl ()
throw tl::Exception (std::string ("Shapes shader program linking failed failed:\n") + tl::to_string (m_shapes_program->log ()));
}
static const char *lines_vertex_shader_source =
"#version 150\n"
"\n"
"in vec4 posAttr;\n"
"uniform mat4 matrix;\n"
"\n"
"void main() {\n"
" gl_Position = matrix * posAttr;\n"
"}\n";
static const char *lines_fragment_shader_source =
"#version 150\n"
"\n"
"uniform lowp vec4 color;\n"
"out lowp vec4 fragColor;\n"
"uniform highp float mist_factor;\n"
"uniform highp float mist_add;\n"
"\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/?
" 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(color, gl_FragCoord.w);\n"
"}\n";
m_lines_program = new QOpenGLShaderProgram (this);
if (! m_lines_program->addShaderFromSourceCode (QOpenGLShader::Vertex, lines_vertex_shader_source)) {
throw tl::Exception (std::string ("Lines vertex shader compilation failed:\n") + tl::to_string (m_lines_program->log ()));
}
if (! m_lines_program->addShaderFromSourceCode (QOpenGLShader::Fragment, lines_fragment_shader_source)) {
throw tl::Exception (std::string ("Lines fragment shader compilation failed:\n") + tl::to_string (m_lines_program->log ()));
}
if (! m_lines_program->link ()) {
throw tl::Exception (std::string ("Lines shader program linking failed failed:\n") + tl::to_string (m_lines_program->log ()));
}
// grid plane shader source
static const char *gridplan_vertex_shader_source =
@ -873,6 +1049,10 @@ D25ViewWidget::do_initialize_gl ()
void
D25ViewWidget::paintGL ()
{
if (! mp_view) {
return;
}
const qreal retina_scale = devicePixelRatio ();
glViewport (0, 0, width () * retina_scale, height () * retina_scale);
@ -884,7 +1064,7 @@ D25ViewWidget::paintGL ()
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);
if (! m_shapes_program || ! m_gridplane_program) {
if (! m_shapes_program || ! m_lines_program || ! m_gridplane_program) {
return;
}
@ -893,7 +1073,7 @@ D25ViewWidget::paintGL ()
QMatrix4x4 scene_trans, scene_trans_wo_y;
// provide the displacement and scaling (in this order!)
scene_trans.scale (m_scale_factor);
scene_trans.scale (m_scale_factor, m_scale_factor * m_vscale_factor, 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);
@ -917,9 +1097,11 @@ D25ViewWidget::paintGL ()
glEnable (GL_DEPTH_TEST);
glEnableVertexAttribArray (positions);
for (std::list<LayerInfo>::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]);
l->vertex_chunk->draw_to (this, positions, GL_TRIANGLES);
for (std::vector<LayerInfo>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
if (l->visible && l->color [3] > 0.5) {
m_shapes_program->setUniformValue ("color", l->color [0], l->color [1], l->color [2], l->color [3]);
l->vertex_chunk->draw_to (this, positions, GL_TRIANGLES);
}
}
glDisableVertexAttribArray (positions);
@ -927,6 +1109,35 @@ D25ViewWidget::paintGL ()
m_shapes_program->release ();
// wire lines
m_lines_program->bind ();
m_lines_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_lines_program->setUniformValue ("illum", QVector3D (-3.0, -4.0, 2.0).normalized ());
m_lines_program->setUniformValue ("ambient", QVector4D (ambient, ambient, ambient, 1.0));
m_lines_program->setUniformValue ("mist_factor", mist_factor);
m_lines_program->setUniformValue ("mist_add", mist_add);
glEnable (GL_DEPTH_TEST);
glEnableVertexAttribArray (positions);
glLineWidth (1.0);
for (std::vector<LayerInfo>::const_iterator l = m_layers.begin (); l != m_layers.end (); ++l) {
if (l->visible && l->frame_color [3] > 0.5) {
m_lines_program->setUniformValue ("color", l->frame_color [0], l->frame_color [1], l->frame_color [2], l->frame_color [3]);
l->line_chunk->draw_to (this, positions, GL_LINES);
}
}
glDisableVertexAttribArray (positions);
m_lines_program->release ();
// decoration
positions = m_gridplane_program->attributeLocation ("posAttr");

View File

@ -45,10 +45,16 @@ namespace db
class Cell;
}
namespace tl
{
class AbsoluteProgress;
}
namespace lay
{
class LayoutView;
class LayerPropertiesNode;
class D25ViewWidget;
class D25InteractionMode
@ -83,6 +89,7 @@ public:
void mouseMoveEvent (QMouseEvent *event);
bool attach_view(lay::LayoutView *view);
void refresh_view ();
QVector3D hit_point_with_scene(const QVector3D &line_dir);
void refresh ();
@ -96,6 +103,11 @@ public:
refresh ();
}
QVector3D scale_factors () const
{
return QVector3D (scale_factor (), scale_factor () * vscale_factor (), scale_factor ());
}
double scale_factor () const { return m_scale_factor; }
void set_scale_factor (double f)
@ -104,6 +116,14 @@ public:
refresh ();
}
double vscale_factor () const { return m_vscale_factor; }
void set_vscale_factor (double f)
{
m_vscale_factor = f;
refresh ();
}
const std::string &error () const
{
return m_error;
@ -111,37 +131,44 @@ public:
signals:
void scale_factor_changed (double f);
void vscale_factor_changed (double f);
void init_failed ();
protected:
virtual void camera_changed ();
virtual double aspect_ratio () const;
virtual void showEvent (QShowEvent *);
public slots:
void fit ();
private:
typedef lay::mem_chunks<GLfloat, 1024 * 18> chunks_type;
typedef lay::mem_chunks<GLfloat, 1024 * 18> triangle_chunks_type;
typedef lay::mem_chunks<GLfloat, 1024 * 6> line_chunks_type;
std::unique_ptr<D25InteractionMode> mp_mode;
QOpenGLShaderProgram *m_shapes_program, *m_gridplane_program;
QOpenGLShaderProgram *m_shapes_program, *m_lines_program, *m_gridplane_program;
std::string m_error;
double m_scale_factor;
double m_vscale_factor;
QVector3D m_displacement;
lay::LayoutView *mp_view;
db::DBox m_bbox;
double m_zmin, m_zmax;
std::list<chunks_type> m_vertex_chunks;
std::list<chunks_type> m_normals_chunks;
std::list<triangle_chunks_type> m_vertex_chunks;
std::list<line_chunks_type> m_line_chunks;
struct LayerInfo {
const chunks_type *vertex_chunk;
const chunks_type *normals_chunk;
const triangle_chunks_type *vertex_chunk;
const line_chunks_type *line_chunk;
GLfloat color [4];
GLfloat frame_color [4];
bool visible;
};
std::list<LayerInfo> m_layers;
std::vector<LayerInfo> m_layers;
std::multimap<std::pair<size_t, size_t>, size_t> m_layer_to_info;
void initializeGL ();
void paintGL ();
@ -149,9 +176,11 @@ private:
void do_initialize_gl ();
bool prepare_view();
void render_layout (D25ViewWidget::chunks_type &chunks, const db::Layout &layout, const db::Cell &cell, const db::Box &clip_box, 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);
void render_layout (tl::AbsoluteProgress &progress, D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Layout &layout, const db::Cell &cell, const db::Box &clip_box, unsigned int layer, double zstart, double zstop);
void render_polygon (D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Polygon &poly, double dbu, double zstart, double zstop);
void render_wall (D25ViewWidget::triangle_chunks_type &vertex_chunks, D25ViewWidget::line_chunks_type &line_chunks, const db::Edge &poly, double dbu, double zstart, double zstop);
void reset_viewport ();
static void lp_to_info (const lay::LayerPropertiesNode &lp, D25ViewWidget::LayerInfo &info);
};
}

View File

@ -34,11 +34,6 @@ 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;