diff --git a/Arrangement_on_surface_2/demo/earth/CMakeLists.txt b/Arrangement_on_surface_2/demo/earth/CMakeLists.txt index 93e242322f4..c6b2cea2ecc 100644 --- a/Arrangement_on_surface_2/demo/earth/CMakeLists.txt +++ b/Arrangement_on_surface_2/demo/earth/CMakeLists.txt @@ -104,6 +104,7 @@ file(GLOB source_files Message_manager.h Message_manager.cpp Timer.h Tools.h Tools.cpp + Verification.h Verification.cpp ) source_group( "Source Files" FILES ${source_files} ) diff --git a/Arrangement_on_surface_2/demo/earth/Main_widget.cpp b/Arrangement_on_surface_2/demo/earth/Main_widget.cpp index 54eb341e7d4..8ecd1770c17 100644 --- a/Arrangement_on_surface_2/demo/earth/Main_widget.cpp +++ b/Arrangement_on_surface_2/demo/earth/Main_widget.cpp @@ -25,8 +25,15 @@ #include "Shapefile.h" #include "Timer.h" #include "Tools.h" +#include "Verification.h" +namespace +{ + // used when dimming / highlighting selected countries + float s_dimming_factor = 0.4; +} + Main_widget::~Main_widget() { // Make sure the context is current when deleting the texture and the buffers. @@ -34,8 +41,6 @@ Main_widget::~Main_widget() doneCurrent(); } -float dimming_factor = 0.4; - void Main_widget::mousePressEvent(QMouseEvent* e) { // forward the event to the camera manipulators @@ -108,7 +113,7 @@ void Main_widget::mousePressEvent(QMouseEvent* e) // dim the previous country color auto& prev_country = m_country_triangles[prev_selected_country]; auto color = prev_country->get_color(); - color *= dimming_factor; + color *= s_dimming_factor; color.setW(1); prev_country->set_color(color); } @@ -118,7 +123,7 @@ void Main_widget::mousePressEvent(QMouseEvent* e) // highlight the current country color auto& curr_country = m_country_triangles[selected_country]; auto color = curr_country->get_color(); - color /= dimming_factor; + color /= s_dimming_factor; color.setW(1); curr_country->set_color(color); qDebug() << "SELECTED COUNTRY: " << selected_country; @@ -213,31 +218,6 @@ void Main_widget::keyPressEvent(QKeyEvent* event) } -void Main_widget::verify_antarctica_node_is_redundant() -{ - Kml::Node n1(178.277211542064, -84.4725179992025), - n2(180.0, -84.71338), - n3(-179.942499356179, -84.7214433735525); - - // 1) check if it is collinear with its neighboring nodes: - // all of the vectors in 3D must lie in the same plane - auto v1 = n1.get_coords_3f(); - auto v2 = n2.get_coords_3f(); - auto v3 = n3.get_coords_3f(); - auto n = QVector3D::crossProduct(v1, v3); - n.normalize(); - std::cout << "** DOT PRODUCT = " << QVector3D::dotProduct(n, v2) << std::endl; - - // 2) check if it is between its neighbors (check if r,s > 0) - auto det = [](float ax, float ay, float bx, float by) - { return ax * by - ay * bx; }; - auto D = det(v1.x(), v1.y(), v3.x(), v3.y()); - auto Dr = det(v2.x(), v2.y(), v3.x(), v3.y()); - auto Ds = det(v1.x(), v1.y(), v2.x(), v2.y()); - auto r = Dr / D; - auto s = Ds / D; - std::cout << "r = " << r << "\ns=" << s << std::endl; -} void Main_widget::init_problematic_nodes() { Kml::Nodes prob_nodes = { @@ -256,10 +236,10 @@ void Main_widget::init_problematic_nodes() void Main_widget::initializeGL() { // verify that the node (180.0, -84.71338) in Antarctica is redundant - //verify_antarctica_node_is_redundant(); + //Verification::verify_antarctica_node_is_redundant(); //init_problematic_nodes(); - m_mouse_pos = QVector3D(0, -1.1, 0); + m_mouse_pos = QVector3D(0, -1, 0); m_mouse_vertex = std::make_unique(m_mouse_pos); @@ -349,7 +329,7 @@ void Main_widget::initializeGL() auto color = QVector4D(rndm(), rndm(), rndm(), 1); auto m = std::max(color.x(), std::max(color.y(), color.z())); color /= m; - color *= dimming_factor; + color *= s_dimming_factor; color.setW(1); country_triangles->set_color(color); //country_triangles->set_color(colors[color_map[country_name]]); @@ -498,89 +478,7 @@ float Main_widget::compute_backprojected_error(float pixel_error) //find_minimum_projected_error_on_sphere(err); return err; } -void Main_widget::find_minimum_projected_error_on_sphere(float we) -{ - QRect vp(0, 0, m_vp_width, m_vp_height); - auto proj = m_camera.get_projection_matrix(); - auto view = m_camera.get_view_matrix(); - QMatrix4x4 model; - auto model_view = view * model; - float max_err = 0; - float max_theta = -1; - float max_phi = -1; - - int num_divs = 200; - const float dtheta = M_PI_2 / num_divs; - const float dphi = M_PI_2 / num_divs; - - const float r1 = 1.f; - const float r2 = r1 - we; - for (int i = 0; i <= num_divs; i++) - { - const float theta = dtheta * i; - const float cos_theta = std::cos(theta); - const float sin_theta = std::sin(theta); - - for (int j = 0; j <= num_divs; j++) - { - QVector3D p1, p2; - const float phi = dphi * j; - const float cos_phi = std::cos(phi); - const float sin_phi = std::sin(phi); - - // p1 - const float r1xz = r1 * sin_phi; - p1.setY(r1 * cos_phi); - p1.setX(r1xz * cos_theta); - p1.setZ(r1xz * sin_theta); - - // p2 - const float r2xz = r2 * sin_phi; - p2.setY(r2 * cos_phi); - p2.setX(r2xz * cos_theta); - p2.setZ(r2xz * sin_theta); - - auto wp1 = p1.project(model_view, proj, vp); - auto wp2 = p2.project(model_view, proj, vp); - - const auto pe = wp1.distanceToPoint(wp2); - if (max_err < pe) - { - max_err = pe; - max_theta = theta; - max_phi = phi; - } - } - } - - std::cout << "max err = " << max_err << std::endl; - std::cout << "max phi = " << max_phi * 180 / M_PI << std::endl; - std::cout << "max theta = " << max_theta * 180 / M_PI << std::endl; - - auto wp1 = QVector3D(0, r1, 0).project(model_view, proj, vp); - auto wp2 = QVector3D(0, r2, 0).project(model_view, proj, vp); - auto pe = wp1.distanceToPoint(wp2); - std::cout << "polar err = " << pe << std::endl; - - wp1 = QVector3D(r1, 0, 0).project(model_view, proj, vp); - wp2 = QVector3D(r2, 0, 0).project(model_view, proj, vp); - pe = wp1.distanceToPoint(wp2); - std::cout << "x-axis err = " << pe << std::endl; - - wp1 = QVector3D(0, 0, 1).project(model_view, proj, vp); - wp2 = QVector3D(we, 0, 1).project(model_view, proj, vp); - pe = wp1.distanceToPoint(wp2); - std::cout << "nearest proj err = " << pe << std::endl; - - wp1 = QVector3D(0, 0, -1).project(model_view, proj, vp); - wp2 = QVector3D(we, 0, -1).project(model_view, proj, vp); - pe = wp1.distanceToPoint(wp2); - std::cout << "farthest proj err = " << pe << std::endl; - - // project the origin on the screen (to check if it projects to the mid-vp) - //std::cout << QVector3D(0, 0, 0).project(model_view, proj, vp) << std::endl; -} void Main_widget::resizeGL(int w, int h) { diff --git a/Arrangement_on_surface_2/demo/earth/Main_widget.h b/Arrangement_on_surface_2/demo/earth/Main_widget.h index 8cef4432a4e..a4a230d3f20 100644 --- a/Arrangement_on_surface_2/demo/earth/Main_widget.h +++ b/Arrangement_on_surface_2/demo/earth/Main_widget.h @@ -63,13 +63,13 @@ protected: void init_country_selection(); + // This is called when the required approximation of the arcs is below the + // currently required one defined by the zoom level and window size. If you + // zoom-in or increase the window-size this can be called. But once a minimum + // approximation error is needed, it will stay there until futher change. + // SEE the definition of "m_current_approx_error" member variable below! float compute_backprojected_error(float pixel_error); - // Use this to find the approximate of the true minimum projected error. - // we are ot using this complicated method, but provide it for completeness. - void find_minimum_projected_error_on_sphere(float we); - - // verify that the node (180.0, -84.71338) in Antarctica is redundant - void verify_antarctica_node_is_redundant(); + // init problematic vertices: these are the vertices incident to deg-4 vertex void init_problematic_nodes(); @@ -89,6 +89,7 @@ private: // This is used to identify the Caspian Sea! std::unique_ptr m_new_faces; + // These are used to highlight the picked position by right-mouse click QVector3D m_mouse_pos; std::unique_ptr m_mouse_vertex; diff --git a/Arrangement_on_surface_2/demo/earth/Verification.cpp b/Arrangement_on_surface_2/demo/earth/Verification.cpp new file mode 100644 index 00000000000..fe7452aef6a --- /dev/null +++ b/Arrangement_on_surface_2/demo/earth/Verification.cpp @@ -0,0 +1,126 @@ +// Copyright(c) 2012, 2020 Tel - Aviv University(Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Engin Deniz Diktas + +#include "Verification.h" + +#include + +#include "Kml_reader.h" + + +void Verification::find_minimum_projected_error_on_sphere(float we, Camera& cam, + int vp_width, int vp_height) +{ + QRect vp(0, 0, vp_width, vp_height); + auto proj = cam.get_projection_matrix(); + auto view = cam.get_view_matrix(); + QMatrix4x4 model; + auto model_view = view * model; + + float max_err = 0; + float max_theta = -1; + float max_phi = -1; + + int num_divs = 200; + const float dtheta = M_PI_2 / num_divs; + const float dphi = M_PI_2 / num_divs; + + const float r1 = 1.f; + const float r2 = r1 - we; + for (int i = 0; i <= num_divs; i++) + { + const float theta = dtheta * i; + const float cos_theta = std::cos(theta); + const float sin_theta = std::sin(theta); + + for (int j = 0; j <= num_divs; j++) + { + QVector3D p1, p2; + const float phi = dphi * j; + const float cos_phi = std::cos(phi); + const float sin_phi = std::sin(phi); + + // p1 + const float r1xz = r1 * sin_phi; + p1.setY(r1 * cos_phi); + p1.setX(r1xz * cos_theta); + p1.setZ(r1xz * sin_theta); + + // p2 + const float r2xz = r2 * sin_phi; + p2.setY(r2 * cos_phi); + p2.setX(r2xz * cos_theta); + p2.setZ(r2xz * sin_theta); + + auto wp1 = p1.project(model_view, proj, vp); + auto wp2 = p2.project(model_view, proj, vp); + + const auto pe = wp1.distanceToPoint(wp2); + if (max_err < pe) + { + max_err = pe; + max_theta = theta; + max_phi = phi; + } + } + } + + std::cout << "max err = " << max_err << std::endl; + std::cout << "max phi = " << max_phi * 180 / M_PI << std::endl; + std::cout << "max theta = " << max_theta * 180 / M_PI << std::endl; + + auto wp1 = QVector3D(0, r1, 0).project(model_view, proj, vp); + auto wp2 = QVector3D(0, r2, 0).project(model_view, proj, vp); + auto pe = wp1.distanceToPoint(wp2); + std::cout << "polar err = " << pe << std::endl; + + wp1 = QVector3D(r1, 0, 0).project(model_view, proj, vp); + wp2 = QVector3D(r2, 0, 0).project(model_view, proj, vp); + pe = wp1.distanceToPoint(wp2); + std::cout << "x-axis err = " << pe << std::endl; + + wp1 = QVector3D(0, 0, 1).project(model_view, proj, vp); + wp2 = QVector3D(we, 0, 1).project(model_view, proj, vp); + pe = wp1.distanceToPoint(wp2); + std::cout << "nearest proj err = " << pe << std::endl; + + wp1 = QVector3D(0, 0, -1).project(model_view, proj, vp); + wp2 = QVector3D(we, 0, -1).project(model_view, proj, vp); + pe = wp1.distanceToPoint(wp2); + std::cout << "farthest proj err = " << pe << std::endl; + + // project the origin on the screen (to check if it projects to the mid-vp) + //std::cout << QVector3D(0, 0, 0).project(model_view, proj, vp) << std::endl; +} + +void Verification::verify_antarctica_node_is_redundant() +{ + Kml::Node n1(178.277211542064, -84.4725179992025), + n2(180.0, -84.71338), + n3(-179.942499356179, -84.7214433735525); + + // 1) check if it is collinear with its neighboring nodes: + // all of the vectors in 3D must lie in the same plane + auto v1 = n1.get_coords_3f(); + auto v2 = n2.get_coords_3f(); + auto v3 = n3.get_coords_3f(); + auto n = QVector3D::crossProduct(v1, v3); + n.normalize(); + std::cout << "** DOT PRODUCT = " << QVector3D::dotProduct(n, v2) << std::endl; + + // 2) check if it is between its neighbors (check if r,s > 0) + auto det = [](float ax, float ay, float bx, float by) + { return ax * by - ay * bx; }; + auto D = det(v1.x(), v1.y(), v3.x(), v3.y()); + auto Dr = det(v2.x(), v2.y(), v3.x(), v3.y()); + auto Ds = det(v1.x(), v1.y(), v2.x(), v2.y()); + auto r = Dr / D; + auto s = Ds / D; + std::cout << "r = " << r << "\ns=" << s << std::endl; +} \ No newline at end of file diff --git a/Arrangement_on_surface_2/demo/earth/Verification.h b/Arrangement_on_surface_2/demo/earth/Verification.h new file mode 100644 index 00000000000..93c45fd317d --- /dev/null +++ b/Arrangement_on_surface_2/demo/earth/Verification.h @@ -0,0 +1,37 @@ +// Copyright(c) 2012, 2020 Tel - Aviv University(Israel). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s): Engin Deniz Diktas + +#ifndef VERIFICATION_H +#define VERIFICATION_H + +#include +#include + +#include "Camera.h" + + +// +// This class contains code to verify or compute certain hypotheses +// +class Verification +{ +public: + + // Use this to find the approximate of the true minimum projected error. + // we are ot using this complicated method, but provide it for completeness. + static void find_minimum_projected_error_on_sphere(float we, Camera& cam, + int vp_width, int vp_height); + + // verify that the node (180.0, -84.71338) in Antarctica is redundant + static void verify_antarctica_node_is_redundant(); + +}; + + +#endif