Blame synfig-core/src/synfig/rendering/primitive/transformationaffine.cpp

248685
/* === S Y N F I G ========================================================= */
248685
/*!	\file synfig/rendering/primitive/affinetransformation.cpp
248685
**	\brief AffineTransformation
248685
**
248685
**	$Id$
248685
**
248685
**	\legal
da4398
**	......... ... 2015-2018 Ivan Mahonin
248685
**
248685
**	This package is free software; you can redistribute it and/or
248685
**	modify it under the terms of the GNU General Public License as
248685
**	published by the Free Software Foundation; either version 2 of
248685
**	the License, or (at your option) any later version.
248685
**
248685
**	This package is distributed in the hope that it will be useful,
248685
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
248685
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
248685
**	General Public License for more details.
248685
**	\endlegal
248685
*/
248685
/* ========================================================================= */
248685
248685
/* === H E A D E R S ======================================================= */
248685
248685
#ifdef USING_PCH
248685
#	include "pch.h"
248685
#else
248685
#ifdef HAVE_CONFIG_H
248685
#	include <config.h></config.h>
248685
#endif
248685
da4398
#include "transformationaffine.h"
248685
248685
#endif
248685
248685
using namespace synfig;
248685
using namespace rendering;
248685
248685
/* === M A C R O S ========================================================= */
248685
248685
/* === G L O B A L S ======================================================= */
248685
248685
/* === P R O C E D U R E S ================================================= */
248685
248685
/* === M E T H O D S ======================================================= */
248685
81df8d
Transformation*
81df8d
TransformationAffine::clone_vfunc() const
81df8d
	{ return new TransformationAffine(matrix); }
81df8d
81df8d
Transformation*
da4398
TransformationAffine::create_inverted_vfunc() const
da4398
	{ return new TransformationAffine(Matrix(matrix).invert()); }
da4398
da4398
Point
f44ff0
TransformationAffine::transform_vfunc(const Point &x) const
f44ff0
	{ return matrix.get_transformed(x); }
f44ff0
f44ff0
Matrix2
f44ff0
TransformationAffine::derivative_vfunc(const Point&) const
f44ff0
	{ return Matrix2(matrix.m00, matrix.m01, matrix.m10, matrix.m11); }
f44ff0
f44ff0
Vector
f44ff0
TransformationAffine::calc_optimal_resolution(const Matrix2 &matrix) {
f44ff0
	const Real max_overscale_sqr = 1.0*4.0;
f44ff0
	const Real real_precision_sqr = real_precision<real>() * real_precision<real>();</real></real>
fc7a04
	const Real real_precision_sqrsqr = real_precision_sqr * real_precision_sqr;
f44ff0
	
f44ff0
	const Real a = matrix.m00 * matrix.m00;
f44ff0
	const Real b = matrix.m01 * matrix.m01;
f44ff0
	const Real c = matrix.m10 * matrix.m10;
f44ff0
	const Real d = matrix.m11 * matrix.m11;
f44ff0
	Real e = fabs(matrix.det());
f44ff0
	if (e < real_precision_sqr)
f44ff0
		return Vector();
f44ff0
	e = 1.0/e;
f44ff0
	
f44ff0
	const Real sum = a*d + b*c;
fc7a04
	const Real ab2 = 2*a*b + real_precision_sqrsqr;
fc7a04
	const Real cd2 = 2*c*d + real_precision_sqrsqr;
fc7a04
	bool abgt = (ab2 >= sum);
fc7a04
	bool cdgt = (cd2 >= sum);
fc7a04
	if (abgt && cdgt) // when both is greater than sum select only lower of them
fc7a04
		(ab2 > cd2 ? abgt : cdgt) = false;
fc7a04
	
f44ff0
	Vector scale;
fc7a04
	if (abgt) {
f44ff0
		scale[0] = sqrt(2*b)*e;
f44ff0
		scale[1] = sqrt(2*a)*e;
f44ff0
	} else
fc7a04
	if (cdgt) {
f44ff0
		scale[0] = sqrt(2*d)*e;
f44ff0
		scale[1] = sqrt(2*c)*e;
f44ff0
	} else {
f44ff0
		const Real dif = a*d - b*c;
f44ff0
		scale[0] = sqrt(dif/(a - c))*e;
f44ff0
		scale[1] = sqrt(dif/(d - b))*e;
f44ff0
	}
f44ff0
	
fc7a04
	const Real sqr = scale[0]*scale[1]*(matrix.m00 + matrix.m10)*(matrix.m01 + matrix.m11);
fc7a04
	if (sqr > max_overscale_sqr)
fc7a04
		scale *= sqrt(max_overscale_sqr/sqr);
f44ff0
	
f44ff0
	return scale[0] <= real_precision<real>() || scale[1] <= real_precision<real>()</real></real>
f44ff0
		 ? Vector() : scale;
f44ff0
}
da4398
da4398
Transformation::Bounds
f44ff0
TransformationAffine::transform_bounds_affine(const Matrix &matrix, const Bounds &bounds)
248685
{
da4398
	if (!bounds.is_valid())
da4398
		return Bounds();
f44ff0
	
f44ff0
	const Real kx = 1/bounds.resolution[0];
f44ff0
	const Real ky = 1/bounds.resolution[1];
f44ff0
	
f44ff0
	return Bounds(
f44ff0
		   Rect( matrix.get_transformed( Vector(bounds.rect.minx, bounds.rect.miny) ) )
f44ff0
		.expand( matrix.get_transformed( Vector(bounds.rect.minx, bounds.rect.maxy) ) )
f44ff0
		.expand( matrix.get_transformed( Vector(bounds.rect.maxx, bounds.rect.miny) ) )
f44ff0
		.expand( matrix.get_transformed( Vector(bounds.rect.maxx, bounds.rect.maxy) ) ),
f44ff0
		calc_optimal_resolution(Matrix2(
f44ff0
			matrix.m00*kx, matrix.m01*kx,
f44ff0
			matrix.m10*ky, matrix.m11*ky )) );
248685
}
248685
f44ff0
Transformation::Bounds
f44ff0
TransformationAffine::transform_bounds_vfunc(const Bounds &bounds) const
f44ff0
	{ return transform_bounds_affine(matrix, bounds); }
f44ff0
81df8d
bool
81df8d
TransformationAffine::can_merge_outer_vfunc(const Transformation &other) const
81df8d
	{ return (bool)dynamic_cast<const transformationaffine*="">(&other); }</const>
81df8d
81df8d
bool
81df8d
TransformationAffine::can_merge_inner_vfunc(const Transformation &other) const
81df8d
	{ return can_merge_outer_vfunc(other); }
81df8d
81df8d
void
81df8d
TransformationAffine::merge_outer_vfunc(const Transformation &other)
81df8d
	{ matrix = dynamic_cast<const transformationaffine*="">(&other)->matrix * matrix; }</const>
81df8d
81df8d
void
81df8d
TransformationAffine::merge_inner_vfunc(const Transformation &other)
81df8d
	{ matrix *= dynamic_cast<const transformationaffine*="">(&other)->matrix; }</const>
81df8d
81df8d
248685
/* === E N T R Y P O I N T ================================================= */