diff --git a/c++/perspective/src/generator.cpp b/c++/perspective/src/generator.cpp index 4e0f23a..2e82651 100644 --- a/c++/perspective/src/generator.cpp +++ b/c++/perspective/src/generator.cpp @@ -364,7 +364,7 @@ Generator::generate(Surface &target, const Pair2 &bounds, bool checks) const { Vector2 d = bounds.distance(); d.x /= w; d.y /= h; - const Vector2 precision(fabs(d.x/2.0), fabs(d.x/2.0)); + const Vector2 precision(fabs(d.x/2.0), fabs(d.y/2.0)); const Vector2 precision_inv( 1/std::max(precision.x, real_precision), 1/std::max(precision.y, real_precision) ); @@ -438,7 +438,7 @@ Generator::generate(Surface &target, const Pair2 &bounds, bool checks) const { if (a + real_precision >= 1) { *pixel = color; } else { - const Color back_color = Color(1 - color.r, 1 - color.g, 1 - color.b, 1 - color.a); + const Color back_color = Color(color.g, color.b, color.r, color.a); if (a - real_precision <= 0) { *pixel = back_color; } else { diff --git a/c++/perspective/src/perspective.cpp b/c++/perspective/src/perspective.cpp index a2b1ecc..f1a1ee0 100644 --- a/c++/perspective/src/perspective.cpp +++ b/c++/perspective/src/perspective.cpp @@ -194,20 +194,26 @@ Perspective::make_matrix( Matrix3 -Perspective::normalize_matrix_by_w( - const Matrix3 &matrix ) +Perspective::matrix_mult( + const Matrix3 &matrix, + Real value ) { - Real k = matrix.get_col(2).length(); - if (k <= real_precision) - return matrix; - k = 1/k; Matrix3 m = matrix; for(int i = 0; i < 9; ++i) - m.a[i] *= k; + m.a[i] *= value; return m; } +Matrix3 +Perspective::normalize_matrix_by_det( + const Matrix3 &matrix ) +{ + const Real d = matrix.det(); + return fabs(d) <= real_precision ? matrix : matrix_mult(matrix, fabs(1/cbrt(d))); +} + + int Perspective::truncate_line( Vector2 *out_points, @@ -276,11 +282,23 @@ Perspective::calc_optimal_resolution( const Real sum = a*d + b*c; Vector2 scale; - if (2*a*b + real_precision_sqr >= sum) { + bool abgt = (2*a*b + real_precision_sqr >= sum); + bool cdgt = (2*c*d + real_precision_sqr >= sum); + + if (abgt && cdgt) { + if (a*b < c*d) { + scale.x = sqrt(2*b)*e; + scale.y = sqrt(2*a)*e; + } else { + scale.x = sqrt(2*d)*e; + scale.y = sqrt(2*c)*e; + } + } else + if (abgt) { scale.x = sqrt(2*b)*e; scale.y = sqrt(2*a)*e; } else - if (2*c*d + real_precision_sqr >= sum) { + if (cdgt) { scale.x = sqrt(2*d)*e; scale.y = sqrt(2*c)*e; } else { @@ -383,8 +401,8 @@ Perspective::create_layers( const Real step ) { bool is_invertible = false; - Matrix3 norm_matrix = normalize_matrix_by_w(matrix); - Matrix3 back_matrix = norm_matrix.inverted(&is_invertible); + Matrix3 norm_matrix = normalize_matrix_by_det(matrix); + Matrix3 back_matrix = normalize_matrix_by_det( norm_matrix.inverted(&is_invertible) ); if (!is_invertible) return; // matrix is collapsed @@ -407,6 +425,7 @@ Perspective::create_layers( if (fabs(C) < real_precision) return; // only when matrix was not invertible (additional check) + back_matrix = matrix_mult(back_matrix, 1/C); // calc src resolution const Vector2 resolution = calc_optimal_resolution( diff --git a/c++/perspective/src/perspective.h b/c++/perspective/src/perspective.h index d9eced0..a92dad2 100644 --- a/c++/perspective/src/perspective.h +++ b/c++/perspective/src/perspective.h @@ -30,7 +30,10 @@ public: const Vector2 &py, const Vector2 &p1 ); - static Matrix3 normalize_matrix_by_w( + static Matrix3 matrix_mult( + const Matrix3 &matrix, + Real value ); + static Matrix3 normalize_matrix_by_det( const Matrix3 &matrix ); static int truncate_line( diff --git a/c++/perspective/src/perspectivesandboxview.cpp b/c++/perspective/src/perspectivesandboxview.cpp index 4687875..93361d5 100644 --- a/c++/perspective/src/perspectivesandboxview.cpp +++ b/c++/perspective/src/perspectivesandboxview.cpp @@ -379,7 +379,7 @@ PerspectiveSandBoxView::on_draw_view(const Cairo::RefPtr &contex 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_by_w( m3.inverted() ); + Matrix3 back_matrix = Perspective::normalize_matrix_by_det( m3.inverted() ); update_background_best_perimeter(back_matrix, get_width(), get_height()); }