From 370a3f5cc9e39352a081e5d5dd8c43676547a6e6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 4 Oct 2012 11:45:44 +1000 Subject: code cleanup: add own includes to cpp files or make the functions static if they are not used elsewhere. (bzr r11735) --- src/sp-item-transform.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index a8d553e9f..a27a1bc78 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -16,6 +16,7 @@ #include <2geom/transforms.h> #include "sp-item.h" +#include "sp-item-transform.h" void sp_item_rotate_rel(SPItem *item, Geom::Rotate const &rotation) { -- cgit v1.2.3 From 3b7a3bd5d820cb7c41fe99254129d6603a5e9ff2 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Tue, 17 Dec 2013 18:01:44 -0500 Subject: modify transform behaviour for scaled stroke width, Preserved Transforms (bzr r12852) --- src/sp-item-transform.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index a27a1bc78..70cb74940 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -94,7 +94,7 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) * not possible here because it will only allow for a positive width and height, and therefore cannot mirror * @return */ -Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visual, gdouble strokewidth, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1) +Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visual, gdouble strokewidth, bool transform_stroke, bool preserve, gdouble x0, gdouble y0, gdouble x1, gdouble y1) { Geom::Affine p2o = Geom::Translate (-bbox_visual.min()); Geom::Affine o2n = Geom::Translate (x0, y0); @@ -147,13 +147,13 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua ratio_y = (h1 - r0) / (h0 - r0); r1 = transform_stroke ? r0 * sqrt(h1/h0) : r0; scale_x = 1; - scale_y = (h1 - r1)/(h0 - r0); + scale_y = preserve ? h1/h0 : (h1 - r1)/(h0 - r0); } else if (fabs(h0 - r0) < 1e-6) { // We have a horizontal line at hand direct = Geom::Scale(flip_x * w1 / w0, flip_y); ratio_x = (w1 - r0) / (w0 - r0); ratio_y = 1; r1 = transform_stroke ? r0 * sqrt(w1/w0) : r0; - scale_x = (w1 - r1)/(w0 - r0); + scale_x = preserve ? w1/w0 : (w1 - r1)/(w0 - r0); scale_y = 1; } else { // We have a true 2D object at hand direct = Geom::Scale(flip_x * w1 / w0, flip_y* h1 / h0); // Scaling of the visual bounding box @@ -164,21 +164,21 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua * This is how the stroke should scale: r1^2 / A1 = r0^2 / A0 * So therefore we will need to solve this equation: * - * r1^2 * (w0-r0) * (h1-r1) = r0^2 * (w1-r1) * (h0-r0) + * r1^2 * (w0-r0) * (h0-r0) = r0^2 * (w1-r1) * (h1-r1) * * This is a quadratic equation in r1, of which the roots can be found using the ABC formula * */ gdouble A = -w0*h0 + r0*(w0 + h0); gdouble B = -(w1 + h1) * r0*r0; gdouble C = w1 * h1 * r0*r0; - if (B*B - 4*A*C > 0) { + if ((B*B - 4*A*C > 0) && !preserve) { // Of the two roots, I verified experimentally that this is the one we need r1 = fabs((-B - sqrt(B*B - 4*A*C))/(2*A)); // If w1 < 0 then the scale will be wrong if we just assume that scale_x = (w1 - r1)/(w0 - r0); // Therefore we here need the absolute values of w0, w1, h0, h1, and r0, as taken care of earlier scale_x = (w1 - r1)/(w0 - r0); scale_y = (h1 - r1)/(h0 - r0); - } else { // Can't find the roots of the quadratic equation. Likely the input parameters are invalid? + } else { // roots are complex. Or 'Preserve Transforms' was chosen. r1 = r0; scale_x = w1 / w0; scale_y = h1 / h0; @@ -190,7 +190,8 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua // Now we account for mirroring by flipping if needed scale *= Geom::Scale(flip_x * scale_x, flip_y * scale_y); // Make sure that the lower-left corner of the visual bounding box stays where it is, even though the stroke width has changed - unbudge *= Geom::Translate (-flip_x * 0.5 * (r0 * scale_x - r1), -flip_y * 0.5 * (r0 * scale_y - r1)); + if (!preserve) + unbudge *= Geom::Translate (-flip_x * 0.5 * (r0 * scale_x - r1), -flip_y * 0.5 * (r0 * scale_y - r1)); } else { // The stroke should not be scaled, or is zero if (r0 == 0 || r0 == Geom::infinity() ) { // Strokewidth is zero or infinite scale *= direct; -- cgit v1.2.3 From 08945ee8afa6e300b0a7ad8f20710db4756c2528 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Mon, 30 Dec 2013 15:23:58 -0500 Subject: modify transform behaviour for unscaled stroke width, Preserved Transforms (Bug 1262146) Fixed bugs: - https://launchpad.net/bugs/1262146 (bzr r12863) --- src/sp-item-transform.cpp | 109 ++++++++++++++++++++++++---------------------- 1 file changed, 56 insertions(+), 53 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 70cb74940..88148c789 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -84,8 +84,10 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) * the strokewidth, which is either constant or scales width the area of the object. This function takes care of the calculation * of the affine transformation: * @param bbox_visual Current visual bounding box - * @param strokewidth Strokewidth + * @param stroke_x Apparent strokewidth in horizontal direction + * @param stroke_y Apparent strokewidth in vertical direction * @param transform_stroke If true then the stroke will be scaled proportional to the square root of the area of the geometric bounding box + * @param preserve If true then the transform element will be preserved in XML, and evaluated after stroke is applied * @param x0 Coordinate of the target visual bounding box * @param y0 Coordinate of the target visual bounding box * @param x1 Coordinate of the target visual bounding box @@ -94,7 +96,7 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) * not possible here because it will only allow for a positive width and height, and therefore cannot mirror * @return */ -Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visual, gdouble strokewidth, bool transform_stroke, bool preserve, gdouble x0, gdouble y0, gdouble x1, gdouble y1) +Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visual, gdouble stroke_x, gdouble stroke_y, bool transform_stroke, bool preserve, gdouble x0, gdouble y0, gdouble x1, gdouble y1) { Geom::Affine p2o = Geom::Translate (-bbox_visual.min()); Geom::Affine o2n = Geom::Translate (x0, y0); @@ -103,13 +105,14 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua Geom::Affine unbudge = Geom::Translate (0, 0); // moves the object(s) to compensate for the drift caused by stroke width change // 1) We start with a visual bounding box (w0, h0) which we want to transfer into another visual bounding box (w1, h1) - // 2) The stroke is r0, equal for all edges + // 2) The stroke is r0, equal for all edges, if preserve transforms is false // 3) Given this visual bounding box we can calculate the geometric bounding box by subtracting half the stroke from each side; // -> The width and height of the geometric bounding box will therefore be (w0 - 2*0.5*r0) and (h0 - 2*0.5*r0) + // 4) If preserve transforms is true, then stroke_x != stroke_y, since these are the apparent stroke widths, after transforming gdouble w0 = bbox_visual.width(); // will return a value >= 0, as required further down the road gdouble h0 = bbox_visual.height(); - gdouble r0 = fabs(strokewidth); + gdouble r0 = sqrt(stroke_x*stroke_y); // r0 is redundant, used only for those cases where stroke_x = stroke_y // We also know the width and height of the new visual bounding box gdouble w1 = x1 - x0; // can have any sign @@ -124,7 +127,6 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua // Therefore we will use the absolute values from this point on w1 = fabs(w1); h1 = fabs(h1); - r0 = fabs(r0); // w0 and h0 will always be positive due to the definition of the width() and height() methods. // We will now try to calculate the affine transformation required to transform the first visual bounding box into @@ -134,72 +136,73 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua return Geom::Affine(); } - Geom::Affine direct; - gdouble ratio_x = 1; - gdouble ratio_y = 1; gdouble scale_x = 1; gdouble scale_y = 1; gdouble r1 = r0; if (fabs(w0 - r0) < 1e-6) { // We have a vertical line at hand - direct = Geom::Scale(flip_x, flip_y * h1 / h0); - ratio_x = 1; - ratio_y = (h1 - r0) / (h0 - r0); r1 = transform_stroke ? r0 * sqrt(h1/h0) : r0; scale_x = 1; scale_y = preserve ? h1/h0 : (h1 - r1)/(h0 - r0); } else if (fabs(h0 - r0) < 1e-6) { // We have a horizontal line at hand - direct = Geom::Scale(flip_x * w1 / w0, flip_y); - ratio_x = (w1 - r0) / (w0 - r0); - ratio_y = 1; r1 = transform_stroke ? r0 * sqrt(w1/w0) : r0; scale_x = preserve ? w1/w0 : (w1 - r1)/(w0 - r0); scale_y = 1; } else { // We have a true 2D object at hand - direct = Geom::Scale(flip_x * w1 / w0, flip_y* h1 / h0); // Scaling of the visual bounding box - ratio_x = (w1 - r0) / (w0 - r0); // Only valid when the stroke is kept constant, in which case r1 = r0 - ratio_y = (h1 - r0) / (h0 - r0); - /* Initial area of the geometric bounding box: A0 = (w0-r0)*(h0-r0) - * Desired area of the geometric bounding box: A1 = (w1-r1)*(h1-r1) - * This is how the stroke should scale: r1^2 / A1 = r0^2 / A0 - * So therefore we will need to solve this equation: - * - * r1^2 * (w0-r0) * (h0-r0) = r0^2 * (w1-r1) * (h1-r1) - * - * This is a quadratic equation in r1, of which the roots can be found using the ABC formula - * */ - gdouble A = -w0*h0 + r0*(w0 + h0); - gdouble B = -(w1 + h1) * r0*r0; - gdouble C = w1 * h1 * r0*r0; - if ((B*B - 4*A*C > 0) && !preserve) { - // Of the two roots, I verified experimentally that this is the one we need - r1 = fabs((-B - sqrt(B*B - 4*A*C))/(2*A)); - // If w1 < 0 then the scale will be wrong if we just assume that scale_x = (w1 - r1)/(w0 - r0); - // Therefore we here need the absolute values of w0, w1, h0, h1, and r0, as taken care of earlier - scale_x = (w1 - r1)/(w0 - r0); - scale_y = (h1 - r1)/(h0 - r0); - } else { // roots are complex. Or 'Preserve Transforms' was chosen. - r1 = r0; + if (transform_stroke && !preserve) { + /* Initial area of the geometric bounding box: A0 = (w0-r0)*(h0-r0) + * Desired area of the geometric bounding box: A1 = (w1-r1)*(h1-r1) + * This is how the stroke should scale: r1^2 / A1 = r0^2 / A0 + * So therefore we will need to solve this equation: + * + * r1^2 * (w0-r0) * (h0-r0) = r0^2 * (w1-r1) * (h1-r1) + * + * This is a quadratic equation in r1, of which the roots can be found using the ABC formula + * */ + gdouble A = -w0*h0 + r0*(w0 + h0); + gdouble B = -(w1 + h1) * r0*r0; + gdouble C = w1 * h1 * r0*r0; + if (B*B - 4*A*C < 0) { + g_message("stroke scaling error : %d, %f, %f, %f, %f, %f", preserve, r0, w0, h0, w1, h1); + } else { + r1 = fabs((-B - sqrt(B*B - 4*A*C))/(2*A)); + // If w1 < 0 then the scale will be wrong if we just assume that scale_x = (w1 - r1)/(w0 - r0); + // Therefore we here need the absolute values of w0, w1, h0, h1, and r0, as taken care of earlier + scale_x = (w1 - r1)/(w0 - r0); + scale_y = (h1 - r1)/(h0 - r0); + // Make sure that the lower-left corner of the visual bounding box stays where it is, even though the stroke width has changed + unbudge *= Geom::Translate (-flip_x * 0.5 * (r0 * scale_x - r1), -flip_y * 0.5 * (r0 * scale_y - r1)); + } + } else if (!transform_stroke && !preserve) { // scale the geometric bbox with constant stroke + scale_x = (w1 - r0) / (w0 - r0); + scale_y = (h1 - r0) / (h0 - r0); + unbudge *= Geom::Translate (-flip_x * 0.5 * r0 * (scale_x - 1), -flip_y * 0.5 * r0 * (scale_y - 1)); + } else if (!transform_stroke) { // 'Preserve Transforms' was chosen. + // geometric mean of stroke_x and stroke_y will be preserved + // new_stroke_x = stroke_x*sqrt(scale_x/scale_y) + // new_stroke_y = stroke_y*sqrt(scale_y/scale_x) + // scale_x = (w1 - new_stroke_x)/(w0 - stroke_x) + // scale_y = (h1 - new_stroke_y)/(h0 - stroke_y) + gdouble A = h1*(w0 - stroke_x); + gdouble B = (h0*stroke_x - w0*stroke_y); + gdouble C = -w1*(h0 - stroke_y); + gdouble Sx_div_Sy; // Sx_div_Sy = sqrt(scale_x/scale_y) + if (B*B - 4*A*C < 0) { + g_message("stroke scaling error : %d, %f, %f, %f, %f, %f, %f", preserve, stroke_x, stroke_y, w0, h0, w1, h1); + } else { + Sx_div_Sy = (-B + sqrt(B*B - 4*A*C))/2/A; + scale_x = (w1 - stroke_x*Sx_div_Sy)/(w0 - stroke_x); + scale_y = (h1 - stroke_y/Sx_div_Sy)/(h0 - stroke_y); + unbudge *= Geom::Translate (-flip_x * 0.5 * stroke_x * scale_x * (1.0 - sqrt(1.0/scale_x/scale_y)), -flip_y * 0.5 * stroke_y * scale_y * (1.0 - sqrt(1.0/scale_x/scale_y))); + } + } else { // 'Preserve Transforms' was chosen, and stroke is scaled scale_x = w1 / w0; scale_y = h1 / h0; } } - // If the stroke is not kept constant however, the scaling of the geometric bbox is more difficult to find - if (transform_stroke && r0 != 0 && r0 != Geom::infinity()) { // Check if there's stroke, and we need to scale it - // Now we account for mirroring by flipping if needed - scale *= Geom::Scale(flip_x * scale_x, flip_y * scale_y); - // Make sure that the lower-left corner of the visual bounding box stays where it is, even though the stroke width has changed - if (!preserve) - unbudge *= Geom::Translate (-flip_x * 0.5 * (r0 * scale_x - r1), -flip_y * 0.5 * (r0 * scale_y - r1)); - } else { // The stroke should not be scaled, or is zero - if (r0 == 0 || r0 == Geom::infinity() ) { // Strokewidth is zero or infinite - scale *= direct; - } else { // Nonscaling strokewidth - scale *= Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); // Scaling of the geometric bounding box for constant stroke width - unbudge *= Geom::Translate (flip_x * 0.5 * r0 * (1 - ratio_x), flip_y * 0.5 * r0 * (1 - ratio_y)); - } - } + // Now we account for mirroring by flipping if needed + scale *= Geom::Scale(flip_x * scale_x, flip_y * scale_y); return (p2o * scale * unbudge * o2n); } -- cgit v1.2.3 From 82ab50d13fed255eaec96d794f97e7b422af9cd0 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Tue, 31 Dec 2013 08:17:23 -0500 Subject: prevent singularity when scaling horizontal or vertical line (bzr r12864) --- src/sp-item-transform.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 88148c789..2d1dd8193 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -140,11 +140,11 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua gdouble scale_y = 1; gdouble r1 = r0; - if (fabs(w0 - r0) < 1e-6) { // We have a vertical line at hand + if ((fabs(w0 - r0) < 1e-6) || w1 == 0) { // We have a vertical line at hand r1 = transform_stroke ? r0 * sqrt(h1/h0) : r0; scale_x = 1; scale_y = preserve ? h1/h0 : (h1 - r1)/(h0 - r0); - } else if (fabs(h0 - r0) < 1e-6) { // We have a horizontal line at hand + } else if ((fabs(h0 - r0) < 1e-6) || h1 == 0) { // We have a horizontal line at hand r1 = transform_stroke ? r0 * sqrt(w1/w0) : r0; scale_x = preserve ? w1/w0 : (w1 - r1)/(w0 - r0); scale_y = 1; -- cgit v1.2.3 From e2b4cd6d88088f5be17bff214c62d85f2030eb20 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sat, 4 Jan 2014 17:37:17 -0500 Subject: modify get_scale_transform_for_variable_stroke() to be consistent with get_scale_transform_for_uniform_stroke() (Bug 1262146) Fixed bugs: - https://launchpad.net/bugs/1262146 (bzr r12881) --- src/sp-item-transform.cpp | 172 ++++++++++++++++++++++++---------------------- 1 file changed, 89 insertions(+), 83 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 2d1dd8193..250713beb 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -226,6 +226,7 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua * @param bbox_visual Current visual bounding box * @param bbox_geometric Current geometric bounding box (allows for calculating the strokewidth of each edge) * @param transform_stroke If true then the stroke will be scaled proportional to the square root of the area of the geometric bounding box + * @param preserve If true then the transform element will be preserved in XML, and evaluated after stroke is applied * @param x0 Coordinate of the target visual bounding box * @param y0 Coordinate of the target visual bounding box * @param x1 Coordinate of the target visual bounding box @@ -234,7 +235,7 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua * not possible here because it will only allow for a positive width and height, and therefore cannot mirror * @return */ -Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visual, Geom::Rect const &bbox_geom, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1) +Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visual, Geom::Rect const &bbox_geom, bool transform_stroke, bool preserve, gdouble x0, gdouble y0, gdouble x1, gdouble y1) { Geom::Affine p2o = Geom::Translate (-bbox_visual.min()); Geom::Affine o2n = Geom::Translate (x0, y0); @@ -272,79 +273,10 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu return Geom::Affine(); } - Geom::Affine direct; - gdouble ratio_x = 1; - gdouble ratio_y = 1; - gdouble scale_x = 1; - gdouble scale_y = 1; - gdouble r1h = r0h; - gdouble r1w = r0w; - - if (fabs(w0 - r0w) < 1e-6) { // We have a vertical line at hand - direct = Geom::Scale(flip_x, flip_y * h1 / h0); - ratio_x = 1; - ratio_y = (h1 - r0h) / (h0 - r0h); - r1h = transform_stroke ? r0h * sqrt(h1/h0) : r0h; - scale_x = 1; - scale_y = (h1 - r1h)/(h0 - r0h); - } else if (fabs(h0 - r0h) < 1e-6) { // We have a horizontal line at hand - direct = Geom::Scale(flip_x * w1 / w0, flip_y); - ratio_x = (w1 - r0w) / (w0 - r0w); - ratio_y = 1; - r1w = transform_stroke ? r0w * sqrt(w1/w0) : r0w; - scale_x = (w1 - r1w)/(w0 - r0w); - scale_y = 1; - } else { // We have a true 2D object at hand - direct = Geom::Scale(flip_x * w1 / w0, flip_y* h1 / h0); // Scaling of the visual bounding box - ratio_x = (w1 - r0w) / (w0 - r0w); // Only valid when the stroke is kept constant, in which case r1 = r0 - ratio_y = (h1 - r0h) / (h0 - r0h); - /* Initial area of the geometric bounding box: A0 = (w0-r0w)*(h0-r0h) - * Desired area of the geometric bounding box: A1 = (w1-r1w)*(h1-r1h) - * This is how the stroke should scale: r1w^2 = A1/A0 * r0w^2, AND - * r1h^2 = A1/A0 * r0h^2 - * Now we have to solve this set of two equations and find r1w and r1h; this too complicated to do by hand, - * so I used wxMaxima for that (http://wxmaxima.sourceforge.net/). These lines can be copied into Maxima - * - * A1: (w1-r1w)*(h1-r1h); - * s: A1/A0; - * expr1a: r1w^2 = s*r0w^2; - * expr1b: r1h^2 = s*r0h^2; - * sol: solve([expr1a, expr1b], [r1h, r1w]); - * sol[1][1]; sol[2][1]; sol[3][1]; sol[4][1]; - * sol[1][2]; sol[2][2]; sol[3][2]; sol[4][2]; - * - * PS1: The last two lines are only needed for readability of the output, and can be omitted if desired - * PS2: A0 is known beforehand and assumed to be constant, instead of using A0 = (w0-r0w)*(h0-r0h). This reduces the - * length of the results significantly - * PS3: You'll get 8 solutions, 4 for each of the strokewidths r1w and r1h. Some experiments quickly showed which of the solutions - * lead to meaningful strokewidths - * */ - gdouble r0h2 = r0h*r0h; - gdouble r0h3 = r0h2*r0h; - gdouble r0w2 = r0w*r0w; - gdouble w12 = w1*w1; - gdouble h12 = h1*h1; - gdouble A0 = bbox_geom.area(); - gdouble A02 = A0*A0; - - gdouble operant = 4*h1*w1*A0+r0h2*w12-2*h1*r0h*r0w*w1+h12*r0w2; - if (operant >= 0) { - // Of the eight roots, I verified experimentally that these are the two we need - r1h = fabs((r0h*sqrt(operant)-r0h2*w1-h1*r0h*r0w)/(2*A0-2*r0h*r0w)); - r1w = fabs(-((h1*r0w*A0+r0h2*r0w*w1)*sqrt(operant)+(-3*h1*r0h*r0w*w1-h12*r0w2)*A0-r0h3*r0w*w12+h1*r0h2*r0w2*w1)/((r0h*A0-r0h2*r0w)*sqrt(operant)-2*h1*A02+(3*h1*r0h*r0w-r0h2*w1)*A0+r0h3*r0w*w1-h1*r0h2*r0w2)); - // If w1 < 0 then the scale will be wrong if we just assume that scale_x = (w1 - r1)/(w0 - r0); - // Therefore we here need the absolute values of w0, w1, h0, h1, and r0, as taken care of earlier - scale_x = (w1 - r1w)/(w0 - r0w); - scale_y = (h1 - r1h)/(h0 - r0h); - } else { // Can't find the roots of the quadratic equation. Likely the input parameters are invalid? - scale_x = w1 / w0; - scale_y = h1 / h0; - } - } - // Check whether the stroke is negative; i.e. the geometric bounding box is larger than the visual bounding box, which // occurs for example for clipped objects (see launchpad bug #811819) if (r0w < 0 || r0h < 0) { + Geom::Affine direct = Geom::Scale(flip_x * w1 / w0, flip_y* h1 / h0); // Scaling of the visual bounding box // How should we handle the stroke width scaling of clipped object? I don't know if we can/should handle this, // so for now we simply return the direct scaling return (p2o * direct * o2n); @@ -356,21 +288,95 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu gdouble stroke_ratio_w = fabs(r0w) < 1e-6 ? 1 : (bbox_geom[Geom::X].min() - bbox_visual[Geom::X].min())/r0w; gdouble stroke_ratio_h = fabs(r0h) < 1e-6 ? 1 : (bbox_geom[Geom::Y].min() - bbox_visual[Geom::Y].min())/r0h; - // If the stroke is not kept constant however, the scaling of the geometric bbox is more difficult to find - if (transform_stroke && r0w != 0 && r0w != Geom::infinity() && r0h != 0 && r0h != Geom::infinity()) { // Check if there's stroke, and we need to scale it - // Now we account for mirroring by flipping if needed - scale *= Geom::Scale(flip_x * scale_x, flip_y * scale_y); - // Make sure that the lower-left corner of the visual bounding box stays where it is, even though the stroke width has changed - unbudge *= Geom::Translate (-flip_x * stroke_ratio_w * (r0w * scale_x - r1w), -flip_y * stroke_ratio_h * (r0h * scale_y - r1h)); - } else { // The stroke should not be scaled, or is zero (or infinite) - if (r0w == 0 || r0w == Geom::infinity() || r0h == 0 || r0h == Geom::infinity()) { // can't calculate, because apparently strokewidth is zero or infinite - scale *= direct; - } else { - scale *= Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); // Scaling of the geometric bounding box for constant stroke width - unbudge *= Geom::Translate (flip_x * stroke_ratio_w * r0w * (1 - ratio_x), flip_y * stroke_ratio_h * r0h * (1 - ratio_y)); + gdouble scale_x = 1; + gdouble scale_y = 1; + gdouble r1h = r0h; + gdouble r1w = r0w; + + if ((fabs(w0 - r0w) < 1e-6) || w1 == 0) { // We have a vertical line at hand + r1h = transform_stroke ? r0h * sqrt(h1/h0) : r0h; + scale_x = 1; + scale_y = preserve ? h1/h0 : (h1 - r1h)/(h0 - r0h); + } else if ((fabs(h0 - r0h) < 1e-6) || h1 == 0) { // We have a horizontal line at hand + r1w = transform_stroke ? r0w * sqrt(w1/w0) : r0w; + scale_x = preserve ? w1/w0 : (w1 - r1w)/(w0 - r0w); + scale_y = 1; + } else { // We have a true 2D object at hand + if (transform_stroke && !preserve) { + /* Initial area of the geometric bounding box: A0 = (w0-r0w)*(h0-r0h) + * Desired area of the geometric bounding box: A1 = (w1-r1w)*(h1-r1h) + * This is how the stroke should scale: r1w^2 = A1/A0 * r0w^2, AND + * r1h^2 = A1/A0 * r0h^2 + * Now we have to solve this set of two equations and find r1w and r1h; this too complicated to do by hand, + * so I used wxMaxima for that (http://wxmaxima.sourceforge.net/). These lines can be copied into Maxima + * + * A1: (w1-r1w)*(h1-r1h); + * s: A1/A0; + * expr1a: r1w^2 = s*r0w^2; + * expr1b: r1h^2 = s*r0h^2; + * sol: solve([expr1a, expr1b], [r1h, r1w]); + * sol[1][1]; sol[2][1]; sol[3][1]; sol[4][1]; + * sol[1][2]; sol[2][2]; sol[3][2]; sol[4][2]; + * + * PS1: The last two lines are only needed for readability of the output, and can be omitted if desired + * PS2: A0 is known beforehand and assumed to be constant, instead of using A0 = (w0-r0w)*(h0-r0h). This reduces the + * length of the results significantly + * PS3: You'll get 8 solutions, 4 for each of the strokewidths r1w and r1h. Some experiments quickly showed which of the solutions + * lead to meaningful strokewidths + * */ + gdouble r0h2 = r0h*r0h; + gdouble r0h3 = r0h2*r0h; + gdouble r0w2 = r0w*r0w; + gdouble w12 = w1*w1; + gdouble h12 = h1*h1; + gdouble A0 = bbox_geom.area(); + gdouble A02 = A0*A0; + + gdouble operant = 4*h1*w1*A0+r0h2*w12-2*h1*r0h*r0w*w1+h12*r0w2; + if (operant < 0) { + g_message("variable stroke scaling error : %d, %d, %f, %f, %f, %f, %f, %f", transform_stroke, preserve, r0w, r0h, w0, h0, w1, h1); + } else { + // Of the eight roots, I verified experimentally that these are the two we need + r1h = fabs((r0h*sqrt(operant)-r0h2*w1-h1*r0h*r0w)/(2*A0-2*r0h*r0w)); + r1w = fabs(-((h1*r0w*A0+r0h2*r0w*w1)*sqrt(operant)+(-3*h1*r0h*r0w*w1-h12*r0w2)*A0-r0h3*r0w*w12+h1*r0h2*r0w2*w1)/((r0h*A0-r0h2*r0w)*sqrt(operant)-2*h1*A02+(3*h1*r0h*r0w-r0h2*w1)*A0+r0h3*r0w*w1-h1*r0h2*r0w2)); + // If w1 < 0 then the scale will be wrong if we just assume that scale_x = (w1 - r1)/(w0 - r0); + // Therefore we here need the absolute values of w0, w1, h0, h1, and r0, as taken care of earlier + scale_x = (w1 - r1w)/(w0 - r0w); + scale_y = (h1 - r1h)/(h0 - r0h); + // Make sure that the lower-left corner of the visual bounding box stays where it is, even though the stroke width has changed + unbudge *= Geom::Translate (-flip_x * stroke_ratio_w * (r0w * scale_x - r1w), -flip_y * stroke_ratio_h * (r0h * scale_y - r1h)); + } + } else if (!transform_stroke && !preserve) { // scale the geometric bbox with constant stroke + scale_x = (w1 - r0w) / (w0 - r0w); + scale_y = (h1 - r0h) / (h0 - r0h); + unbudge *= Geom::Translate (-flip_x * stroke_ratio_w * r0w * (scale_x - 1), -flip_y * stroke_ratio_h * r0h * (scale_y - 1)); + } else if (!transform_stroke) { // 'Preserve Transforms' was chosen. + // geometric mean of r0w and r0h will be preserved + // new_r0w = r0w*sqrt(scale_x/scale_y) + // new_r0h = r0h*sqrt(scale_y/scale_x) + // scale_x = (w1 - new_r0w)/(w0 - r0w) + // scale_y = (h1 - new_r0h)/(h0 - r0h) + gdouble A = h1*(w0 - r0w); + gdouble B = (h0*r0w - w0*r0h); + gdouble C = -w1*(h0 - r0h); + gdouble Sx_div_Sy; // Sx_div_Sy = sqrt(scale_x/scale_y) + if (B*B - 4*A*C < 0) { + g_message("variable stroke scaling error : %d, %d, %f, %f, %f, %f, %f, %f", transform_stroke, preserve, r0w, r0h, w0, h0, w1, h1); + } else { + Sx_div_Sy = (-B + sqrt(B*B - 4*A*C))/2/A; + scale_x = (w1 - r0w*Sx_div_Sy)/(w0 - r0w); + scale_y = (h1 - r0h/Sx_div_Sy)/(h0 - r0h); + unbudge *= Geom::Translate (-flip_x * stroke_ratio_w * r0w * scale_x * (1.0 - sqrt(1.0/scale_x/scale_y)), -flip_y * stroke_ratio_h * r0h * scale_y * (1.0 - sqrt(1.0/scale_x/scale_y))); + } + } else { // 'Preserve Transforms' was chosen, and stroke is scaled + scale_x = w1 / w0; + scale_y = h1 / h0; } } + // Now we account for mirroring by flipping if needed + scale *= Geom::Scale(flip_x * scale_x, flip_y * scale_y); + return (p2o * scale * unbudge * o2n); } -- cgit v1.2.3 From 497bc9a5b7d4501902052ec5df39197f73082c38 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Fri, 17 Jan 2014 14:06:02 -0500 Subject: avoid singularity when scaling horizontal or vertical line. (Bug 1262146) Fixed bugs: - https://launchpad.net/bugs/1262146 (bzr r12951) --- src/sp-item-transform.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 250713beb..9dbe412d7 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -132,7 +132,7 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua // We will now try to calculate the affine transformation required to transform the first visual bounding box into // the second one, while accounting for strokewidth - if ((fabs(w0 - r0) < 1e-6) && (fabs(h0 - r0) < 1e-6)) { + if ((fabs(w0 - stroke_x) < 1e-6) && (fabs(h0 - stroke_y) < 1e-6)) { return Geom::Affine(); } @@ -140,11 +140,11 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua gdouble scale_y = 1; gdouble r1 = r0; - if ((fabs(w0 - r0) < 1e-6) || w1 == 0) { // We have a vertical line at hand + if ((fabs(w0 - stroke_x) < 1e-6) || w1 == 0) { // We have a vertical line at hand r1 = transform_stroke ? r0 * sqrt(h1/h0) : r0; scale_x = 1; scale_y = preserve ? h1/h0 : (h1 - r1)/(h0 - r0); - } else if ((fabs(h0 - r0) < 1e-6) || h1 == 0) { // We have a horizontal line at hand + } else if ((fabs(h0 - stroke_y) < 1e-6) || h1 == 0) { // We have a horizontal line at hand r1 = transform_stroke ? r0 * sqrt(w1/w0) : r0; scale_x = preserve ? w1/w0 : (w1 - r1)/(w0 - r0); scale_y = 1; -- cgit v1.2.3 From e5feb4b17ce16b17ee7ff19188072c25c736bf90 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sun, 19 Jan 2014 07:43:14 -0500 Subject: fix scaling crash caused by negative stroke (Bug 1270464) Fixed bugs: - https://launchpad.net/bugs/1270464 (bzr r12956) --- src/sp-item-transform.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 9dbe412d7..854fb9cd7 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -110,6 +110,9 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua // -> The width and height of the geometric bounding box will therefore be (w0 - 2*0.5*r0) and (h0 - 2*0.5*r0) // 4) If preserve transforms is true, then stroke_x != stroke_y, since these are the apparent stroke widths, after transforming + if ((stroke_x == Geom::infinity()) || (fabs(stroke_x) < 1e-6)) stroke_x = 0; + if ((stroke_y == Geom::infinity()) || (fabs(stroke_y) < 1e-6)) stroke_y = 0; + gdouble w0 = bbox_visual.width(); // will return a value >= 0, as required further down the road gdouble h0 = bbox_visual.height(); gdouble r0 = sqrt(stroke_x*stroke_y); // r0 is redundant, used only for those cases where stroke_x = stroke_y -- cgit v1.2.3 From 0e330f5f1fc975666d7a934e3d2efe594ac0b876 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Mon, 20 Jan 2014 17:06:21 -0500 Subject: 1. make scaling of stroke of horizontal line the same as nearly horizontal line. 2. remove vertical offset when using Transform dialog to attempt to vertically scale horizontal line. (bzr r12964) --- src/sp-item-transform.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 854fb9cd7..7fa591fee 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -144,13 +144,11 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua gdouble r1 = r0; if ((fabs(w0 - stroke_x) < 1e-6) || w1 == 0) { // We have a vertical line at hand - r1 = transform_stroke ? r0 * sqrt(h1/h0) : r0; - scale_x = 1; - scale_y = preserve ? h1/h0 : (h1 - r1)/(h0 - r0); + scale_y = h1/h0; + scale_x = transform_stroke ? 1 : scale_y; } else if ((fabs(h0 - stroke_y) < 1e-6) || h1 == 0) { // We have a horizontal line at hand - r1 = transform_stroke ? r0 * sqrt(w1/w0) : r0; - scale_x = preserve ? w1/w0 : (w1 - r1)/(w0 - r0); - scale_y = 1; + scale_x = w1/w0; + scale_y = transform_stroke ? 1 : scale_x; } else { // We have a true 2D object at hand if (transform_stroke && !preserve) { /* Initial area of the geometric bounding box: A0 = (w0-r0)*(h0-r0) @@ -297,13 +295,13 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu gdouble r1w = r0w; if ((fabs(w0 - r0w) < 1e-6) || w1 == 0) { // We have a vertical line at hand - r1h = transform_stroke ? r0h * sqrt(h1/h0) : r0h; - scale_x = 1; - scale_y = preserve ? h1/h0 : (h1 - r1h)/(h0 - r0h); + scale_y = h1/h0; + scale_x = transform_stroke ? 1 : scale_y; + unbudge *= Geom::Translate (flip_x * 0.5 * (w1 - w0), 0); // compensate for the fact that this operation cannot be performed } else if ((fabs(h0 - r0h) < 1e-6) || h1 == 0) { // We have a horizontal line at hand - r1w = transform_stroke ? r0w * sqrt(w1/w0) : r0w; - scale_x = preserve ? w1/w0 : (w1 - r1w)/(w0 - r0w); - scale_y = 1; + scale_x = w1/w0; + scale_y = transform_stroke ? 1 : scale_x; + unbudge *= Geom::Translate (0, flip_y * 0.5 * (h1 - h0)); // compensate for the fact that this operation cannot be performed } else { // We have a true 2D object at hand if (transform_stroke && !preserve) { /* Initial area of the geometric bounding box: A0 = (w0-r0w)*(h0-r0h) -- cgit v1.2.3 From a666cb5212b82f743913c5e45c11ac759077ec43 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Fri, 31 Jan 2014 16:54:37 -0500 Subject: simplify equations in get_scale_transform_for_variable_stroke() for the case of 'scaled stroke'/'optimized transforms' (bzr r12990) --- src/sp-item-transform.cpp | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 7fa591fee..05390c910 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -246,7 +246,7 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu // 1) We start with a visual bounding box (w0, h0) which we want to transfer into another visual bounding box (w1, h1) // 2) We will also know the geometric bounding box, which can be used to calculate the strokewidth. The strokewidth will however - // be different for each of the four sides (left/right/top/bottom: r0l, r0r, r0t, r0b) + // be different for each of the four sides (left/right/top/bottom: r0l, r0r, r0t, r0b) gdouble w0 = bbox_visual.width(); // will return a value >= 0, as required further down the road gdouble h0 = bbox_visual.height(); @@ -258,8 +258,10 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu // We will now try to calculate the affine transformation required to transform the first visual bounding box into // the second one, while accounting for strokewidth - gdouble r0w = w0 - bbox_geom.width(); // r0w is the average strokewidth of the left and right edges, i.e. 0.5*(r0l + r0r) + gdouble r0w = w0 - bbox_geom.width(); // r0w is the average strokewidth of the left and right edges, i.e. 0.5*(r0l + r0r) gdouble r0h = h0 - bbox_geom.height(); // r0h is the average strokewidth of the top and bottom edges, i.e. 0.5*(r0t + r0b) + if ((r0w == Geom::infinity()) || (fabs(r0w) < 1e-6)) r0w = 0; + if ((r0h == Geom::infinity()) || (fabs(r0h) < 1e-6)) r0h = 0; int flip_x = (w1 > 0) ? 1 : -1; int flip_y = (h1 > 0) ? 1 : -1; @@ -308,38 +310,21 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu * Desired area of the geometric bounding box: A1 = (w1-r1w)*(h1-r1h) * This is how the stroke should scale: r1w^2 = A1/A0 * r0w^2, AND * r1h^2 = A1/A0 * r0h^2 - * Now we have to solve this set of two equations and find r1w and r1h; this too complicated to do by hand, - * so I used wxMaxima for that (http://wxmaxima.sourceforge.net/). These lines can be copied into Maxima - * - * A1: (w1-r1w)*(h1-r1h); - * s: A1/A0; - * expr1a: r1w^2 = s*r0w^2; - * expr1b: r1h^2 = s*r0h^2; - * sol: solve([expr1a, expr1b], [r1h, r1w]); - * sol[1][1]; sol[2][1]; sol[3][1]; sol[4][1]; - * sol[1][2]; sol[2][2]; sol[3][2]; sol[4][2]; - * - * PS1: The last two lines are only needed for readability of the output, and can be omitted if desired - * PS2: A0 is known beforehand and assumed to be constant, instead of using A0 = (w0-r0w)*(h0-r0h). This reduces the - * length of the results significantly - * PS3: You'll get 8 solutions, 4 for each of the strokewidths r1w and r1h. Some experiments quickly showed which of the solutions - * lead to meaningful strokewidths + * These can be re-expressed as : r1w/r0w = r1h/r0h + * and : r1w*r1w*(w0 - r0w)*(h0 - r0h) = r0w*r0w*(w1 - r1w)*(h1 - r1h) + * This leads to a quadratic equation in r1w, solved as follows: * */ - gdouble r0h2 = r0h*r0h; - gdouble r0h3 = r0h2*r0h; - gdouble r0w2 = r0w*r0w; - gdouble w12 = w1*w1; - gdouble h12 = h1*h1; - gdouble A0 = bbox_geom.area(); - gdouble A02 = A0*A0; - - gdouble operant = 4*h1*w1*A0+r0h2*w12-2*h1*r0h*r0w*w1+h12*r0w2; - if (operant < 0) { + + gdouble A = w0*h0 - r0h*w0 - r0w*h0; + gdouble B = r0h*w1 + r0w*h1; + gdouble C = -w1*h1; + + if (B*B - 4*A*C < 0) { g_message("variable stroke scaling error : %d, %d, %f, %f, %f, %f, %f, %f", transform_stroke, preserve, r0w, r0h, w0, h0, w1, h1); } else { - // Of the eight roots, I verified experimentally that these are the two we need - r1h = fabs((r0h*sqrt(operant)-r0h2*w1-h1*r0h*r0w)/(2*A0-2*r0h*r0w)); - r1w = fabs(-((h1*r0w*A0+r0h2*r0w*w1)*sqrt(operant)+(-3*h1*r0h*r0w*w1-h12*r0w2)*A0-r0h3*r0w*w12+h1*r0h2*r0w2*w1)/((r0h*A0-r0h2*r0w)*sqrt(operant)-2*h1*A02+(3*h1*r0h*r0w-r0h2*w1)*A0+r0h3*r0w*w1-h1*r0h2*r0w2)); + gdouble det = (-B + sqrt(B*B - 4*A*C))/(2*A); + r1w = r0w*det; + r1h = r0h*det; // If w1 < 0 then the scale will be wrong if we just assume that scale_x = (w1 - r1)/(w0 - r0); // Therefore we here need the absolute values of w0, w1, h0, h1, and r0, as taken care of earlier scale_x = (w1 - r1w)/(w0 - r0w); -- cgit v1.2.3 From 4212daecf6d6315290ae74f7a3c1c0fda87fc738 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sat, 1 Feb 2014 15:38:03 -0500 Subject: remove vertical offset when stretching a horizontal line (Bug 1275077) Fixed bugs: - https://launchpad.net/bugs/1275077 (bzr r12993) --- src/sp-item-transform.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 05390c910..1ab8edd51 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -146,9 +146,13 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua if ((fabs(w0 - stroke_x) < 1e-6) || w1 == 0) { // We have a vertical line at hand scale_y = h1/h0; scale_x = transform_stroke ? 1 : scale_y; + unbudge *= Geom::Translate (-flip_x * 0.5 * (scale_x - 1.0) * w0, 0); + unbudge *= Geom::Translate ( flip_x * 0.5 * (w1 - w0), 0); // compensate for the fact that this operation cannot be performed } else if ((fabs(h0 - stroke_y) < 1e-6) || h1 == 0) { // We have a horizontal line at hand scale_x = w1/w0; scale_y = transform_stroke ? 1 : scale_x; + unbudge *= Geom::Translate (0, -flip_y * 0.5 * (scale_y - 1.0) * h0); + unbudge *= Geom::Translate (0, flip_y * 0.5 * (h1 - h0)); // compensate for the fact that this operation cannot be performed } else { // We have a true 2D object at hand if (transform_stroke && !preserve) { /* Initial area of the geometric bounding box: A0 = (w0-r0)*(h0-r0) @@ -299,11 +303,13 @@ Geom::Affine get_scale_transform_for_variable_stroke(Geom::Rect const &bbox_visu if ((fabs(w0 - r0w) < 1e-6) || w1 == 0) { // We have a vertical line at hand scale_y = h1/h0; scale_x = transform_stroke ? 1 : scale_y; - unbudge *= Geom::Translate (flip_x * 0.5 * (w1 - w0), 0); // compensate for the fact that this operation cannot be performed + unbudge *= Geom::Translate (-flip_x * 0.5 * (scale_x - 1.0) * w0, 0); + unbudge *= Geom::Translate ( flip_x * 0.5 * (w1 - w0), 0); // compensate for the fact that this operation cannot be performed } else if ((fabs(h0 - r0h) < 1e-6) || h1 == 0) { // We have a horizontal line at hand scale_x = w1/w0; scale_y = transform_stroke ? 1 : scale_x; - unbudge *= Geom::Translate (0, flip_y * 0.5 * (h1 - h0)); // compensate for the fact that this operation cannot be performed + unbudge *= Geom::Translate (0, -flip_y * 0.5 * (scale_y - 1.0) * h0); + unbudge *= Geom::Translate (0, flip_y * 0.5 * (h1 - h0)); // compensate for the fact that this operation cannot be performed } else { // We have a true 2D object at hand if (transform_stroke && !preserve) { /* Initial area of the geometric bounding box: A0 = (w0-r0w)*(h0-r0h) -- cgit v1.2.3 From afd38535535847679968b3e7a9afc382781b2875 Mon Sep 17 00:00:00 2001 From: Alvin Penner Date: Sun, 2 Mar 2014 17:10:15 -0500 Subject: fix scaling crash for clipped objects (Bug 1286647) Fixed bugs: - https://launchpad.net/bugs/1286647 (bzr r13096) --- src/sp-item-transform.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 1ab8edd51..086da56ff 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -115,7 +115,6 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua gdouble w0 = bbox_visual.width(); // will return a value >= 0, as required further down the road gdouble h0 = bbox_visual.height(); - gdouble r0 = sqrt(stroke_x*stroke_y); // r0 is redundant, used only for those cases where stroke_x = stroke_y // We also know the width and height of the new visual bounding box gdouble w1 = x1 - x0; // can have any sign @@ -132,6 +131,16 @@ Geom::Affine get_scale_transform_for_uniform_stroke(Geom::Rect const &bbox_visua h1 = fabs(h1); // w0 and h0 will always be positive due to the definition of the width() and height() methods. + // Check whether the stroke is negative; i.e. the geometric bounding box is larger than the visual bounding box, which + // occurs for example for clipped objects (see launchpad bug #811819) + if (stroke_x < 0 || stroke_y < 0) { + Geom::Affine direct = Geom::Scale(flip_x * w1 / w0, flip_y* h1 / h0); // Scaling of the visual bounding box + // How should we handle the stroke width scaling of clipped object? I don't know if we can/should handle this, + // so for now we simply return the direct scaling + return (p2o * direct * o2n); + } + gdouble r0 = sqrt(stroke_x*stroke_y); // r0 is redundant, used only for those cases where stroke_x = stroke_y + // We will now try to calculate the affine transformation required to transform the first visual bounding box into // the second one, while accounting for strokewidth -- cgit v1.2.3