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