From b5a51f15d09e9739e077e639272a4e342cca8dc9 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 11 Apr 2020 11:21:59 +0200 Subject: [PATCH] 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 }