From b4eaab134c6e6df6673da94982e2b6c9d1fde6fd Mon Sep 17 00:00:00 2001 From: Ivan Mahonin Date: Feb 23 2020 15:16:23 +0000 Subject: perspective: map of distortion --- diff --git a/c++/perspective/src/perspectivesandboxview.cpp b/c++/perspective/src/perspectivesandboxview.cpp index 0e16576..650b403 100644 --- a/c++/perspective/src/perspectivesandboxview.cpp +++ b/c++/perspective/src/perspectivesandboxview.cpp @@ -1,6 +1,7 @@ #include +#include "perspective.h" #include "perspectivesandboxview.h" @@ -21,6 +22,73 @@ PerspectiveSandBoxView::PerspectiveSandBoxView(): points.push_back(bounds_p1); } + +static Vector2 calc_optimal_resolution( + const Vector2 &ox, + const Vector2 &oy ) +{ + const Real a = ox.x * ox.x; + const Real b = ox.y * ox.y; + const Real c = oy.x * oy.x; + const Real d = oy.y * oy.y; + Real e = fabs(ox.x*oy.y - ox.y*oy.x); + if (e < real_precision_sqr) + return Vector2(); // paranoid check, e must be non-zero when matrix is invertible + e = 1.0/e; + + const Real sum = a*d + b*c; + Vector2 scale; + if (2*a*b + real_precision_sqr >= sum) { + scale.x = sqrt(2*b)*e; + scale.y = sqrt(2*a)*e; + } else + if (2*c*d + real_precision_sqr >= sum) { + scale.x = sqrt(2*d)*e; + scale.y = sqrt(2*c)*e; + } else { + const Real dif = a*d - b*c; + scale.x = sqrt(dif/(a - c))*e; + scale.y = sqrt(dif/(d - b))*e; + } + + return scale; +} + + +void PerspectiveSandBoxView::update_background( + const Matrix3 &matrix, + int width, + int height ) +{ + DataSurface surface(width, height); + for(int r = 0; r < height; ++r) { + for(int c = 0; c < width; ++c) { + Vector3 v = matrix*Vector3(c, r, 1); + if (v.z <= real_precision) + continue; + + const Real k = 1/(v.z*v.z); + const Vector2 ox = Vector2( v.z*matrix.m00 - matrix.m02*v.x, + v.z*matrix.m10 - matrix.m12*v.x )*k; + const Vector2 oy = Vector2( v.z*matrix.m01 - matrix.m02*v.y, + v.z*matrix.m11 - matrix.m12*v.y )*k; + const Vector2 resolution = calc_optimal_resolution(ox, oy)*100; + if (resolution.x <= real_precision || resolution.y <= real_precision) + continue; + + const int lx = (int)round(log2(resolution.x)); + const int ly = (int)round(log2(resolution.y)); + Color color; + color.r = lx < 0 ? lx%2 + 1 : lx%2; + color.g = 0; + color.b = ly < 0 ? ly%2 + 1 : ly%2; + color.a = 1; + surface[r][c] = color; + } + } + background = surface.to_cairo_surface(); +} + void PerspectiveSandBoxView::draw_grid( const Cairo::RefPtr &context, @@ -209,7 +277,25 @@ PerspectiveSandBoxView::on_draw_view(const Cairo::RefPtr &contex matrix.row_y() = Vector4(b, 0, bw); matrix.row_w() = Vector4(c, 0, cw); } - + + { // update background + Matrix4 m4 = transform_to_pixels()*matrix; + Matrix3 m3( + Vector3( m4.m00, m4.m01, m4.m03 ), + Vector3( m4.m10, m4.m11, m4.m13 ), + Vector3( m4.m30, m4.m31, m4.m33 ) ); + Matrix3 back_matrix = Perspective::normalize_matrix( m3.inverted() ); + update_background(back_matrix, get_width(), get_height()); + } + + if (background) { + context->save(); + context->transform(transform_from_pixels().to_cairo()); + context->set_source(background, 0, 0); + context->paint(); + context->restore(); + } + draw_grid(context, matrix, Color(0, 1, 0, 1)); draw_subdivisions(context, matrix, bounds, Color(0, 0, 1, 1)); diff --git a/c++/perspective/src/perspectivesandboxview.h b/c++/perspective/src/perspectivesandboxview.h index 45afde1..115923b 100644 --- a/c++/perspective/src/perspectivesandboxview.h +++ b/c++/perspective/src/perspectivesandboxview.h @@ -13,8 +13,15 @@ public: persp_p1, bounds_p0, bounds_p1; + + Cairo::RefPtr background; PerspectiveSandBoxView(); + + void update_background( + const Matrix3 &matrix, + int width, + int height ); void draw_grid( const Cairo::RefPtr &context,