From 77dc5f1acd4a6b66b2d6fc5c81f7e5c61ef95785 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Thu, 5 Aug 2010 02:49:51 +0200 Subject: Wholesale cruft removal part 4; fix crash when rendering guides (bzr r9508.1.48) --- 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 23c0bdf33..aefd6603a 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -123,7 +123,7 @@ get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewid Geom::Matrix direct_constant_r = Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); - if (transform_stroke && r0 != 0 && r0 != NR_HUGE) { // there's stroke, and we need to scale it + if (transform_stroke && r0 != 0 && r0 != Geom::infinity()) { // there's stroke, and we need to scale it // These coefficients are obtained from the assumption that scaling applies to the // non-stroked "shape proper" and that stroke scale is scaled by the expansion of that // matrix. We're trying to solve this equation: @@ -148,7 +148,7 @@ get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewid scale *= direct; } } else { - if (r0 == 0 || r0 == NR_HUGE) { // no stroke to scale + if (r0 == 0 || r0 == Geom::infinity()) { // no stroke to scale scale *= direct; } else {// nonscaling strokewidth scale *= direct_constant_r; @@ -175,7 +175,7 @@ get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Matrix const &abs } Geom::Rect new_visual_bbox = new_geom_bbox; - if (initial_strokewidth > 0 && initial_strokewidth < NR_HUGE) { + if (initial_strokewidth > 0 && initial_strokewidth < Geom::infinity()) { if (transform_stroke) { // scale stroke by: sqrt (((w1-r0)/(w0-r0))*((h1-r0)/(h0-r0))) (for visual bboxes, see get_scale_transform_with_stroke) // equals scaling by: sqrt ((w1/w0)*(h1/h0)) for geometrical bboxes -- cgit v1.2.3 From dd5da66df059871c546f4d09b9d2eb92e71b74b7 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Sun, 10 Jul 2011 21:40:56 +0200 Subject: Selector's toolbar: changing the dimensions of the visual bounding box of selection of multiple objects having different stroke widths has been fixed (bug #212768, #190557, ...) Fixed bugs: - https://launchpad.net/bugs/212768 - https://launchpad.net/bugs/190557 (bzr r10437.1.5) --- src/sp-item-transform.cpp | 273 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 231 insertions(+), 42 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index ae55a5c50..45d965e44 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -7,8 +7,9 @@ * bulia byak * Johan Engelen * Abhishek Sharma + * Diederik van Lierop * - * Copyright (C) 1999-2008 authors + * Copyright (C) 1999-2011 authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -67,46 +68,76 @@ sp_item_skew_rel (SPItem *item, double skewX, double skewY) void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) { - item->set_i2d_affine(item->i2d_affine() * tr); + item->set_i2d_affine(item->i2d_affine() * tr); - item->doWriteTransform(item->getRepr(), item->transform); + item->doWriteTransform(item->getRepr(), item->transform); } -/* -** Returns the matrix you need to apply to an object with given visual bbox and strokewidth to -scale/move it to the new visual bbox x0/y0/x1/y1. Takes into account the "scale stroke" -preference value passed to it. Has to solve a quadratic equation to make sure -the goal is met exactly and the stroke scaling is obeyed. +/** + * \brief Calculate the affine transformation required to transform one visual bounding box into another, accounting for a uniform strokewidth + * + * PS: This function will only return accurate results for the visual bounding box of a selection of one of more objects, all having + * the same strokewidth. If the stroke width varies from object to object in this selection, then the function + * get_scale_transform_with_unequal_stroke() should be called instead + * + * When scaling or stretching an object using the selector, e.g. by dragging the handles or by entering a value, we will + * need to calculate the affine transformation for the old dimensions to the new dimensions. When using a geometric bounding + * box this is very straightforward, but when using a visual bounding box this become more tricky as we need to account for + * 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 transform_stroke If true then the stroke will be scaled proportional to the square root of the area of the geometric bounding box + * \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 + * \param y1 Coordinate of the target visual bounding box + * PS: we have to pass each coordinate individually, to find out if we are mirroring the object; Using a Geom::Rect() instead is + not possible here because it will only allow for a positive width and height, and therefore cannot mirror + * \return */ Geom::Affine -get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewidth, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1) +get_scale_transform_with_uniform_stroke (Geom::Rect const &bbox_visual, gdouble strokewidth, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1) { - Geom::Rect bbox (bbox_param); - - Geom::Affine p2o = Geom::Translate (-bbox.min()); + Geom::Affine p2o = Geom::Translate (-bbox_visual.min()); Geom::Affine o2n = Geom::Translate (x0, y0); - Geom::Affine scale = Geom::Scale (1, 1); // scale component - Geom::Affine unbudge = Geom::Translate (0, 0); // move component to compensate for the drift caused by stroke width change + Geom::Affine scale = Geom::Scale (1, 1); + 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 + // 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) - gdouble w0 = bbox[Geom::X].extent(); // will return a value >= 0, as required further down the road - gdouble h0 = bbox[Geom::Y].extent(); + 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); + + // We also know the width and height of the new visual bounding box gdouble w1 = x1 - x0; // can have any sign gdouble h1 = y1 - y0; - gdouble r0 = strokewidth; + // The new visual bounding box will have a stroke r1 + + // 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 (bbox.hasZeroArea()) { - Geom::Affine move = Geom::Translate(x0 - bbox.min()[Geom::X], y0 - bbox.min()[Geom::Y]); - return (move); // cannot scale from empty boxes at all, so only translate + if (bbox_visual.hasZeroArea()) { // Obviously we cannot scale from empty visual bounding boxes at all, so we will only translate in such a case + Geom::Affine move = Geom::Translate(x0 - bbox_visual.min()[Geom::X], y0 - bbox_visual.min()[Geom::Y]); + return (move); } - Geom::Affine direct = Geom::Scale(w1 / w0, h1 / h0); + Geom::Affine direct = Geom::Scale(w1 / w0, h1 / h0); // Scaling of the visual bounding box + // Although the area of the visual bounding box is not zero, we can still have a geometric + // bounding box with one or both sides having zero length. We can't handle this and will therefore + // simply return the scaling of the visual bounding box, without accounting for any stroke scaling if (fabs(w0 - r0) < 1e-6 || fabs(h0 - r0) < 1e-6 || (!transform_stroke && (fabs(w1 - r0) < 1e-6 || fabs(h1 - r0) < 1e-6))) { - return (p2o * direct * o2n); // can't solve the equation: one of the dimensions is equal to stroke width, so return the straightforward scaler + return (p2o * direct * o2n); } + // Here starts the calculation you've been waiting for; first do some preparation int flip_x = (w1 > 0) ? 1 : -1; int flip_y = (h1 > 0) ? 1 : -1; @@ -115,43 +146,201 @@ get_scale_transform_with_stroke (Geom::Rect const &bbox_param, gdouble strokewid w1 = fabs(w1); h1 = fabs(h1); r0 = fabs(r0); - // w0 and h0 will always be positive due to the definition extent() + // w0 and h0 will always be positive due to the definition of the width() and height() methods. - gdouble ratio_x = (w1 - r0) / (w0 - r0); + gdouble ratio_x = (w1 - r0) / (w0 - r0); // Only valid when the stroke is kept constant, in which case r1 = r0 gdouble ratio_y = (h1 - r0) / (h0 - r0); - + + // Calculating the scaling of the geometric bounding box if the stroke is kept constant Geom::Affine direct_constant_r = Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); - if (transform_stroke && r0 != 0 && r0 != Geom::infinity()) { // there's stroke, and we need to scale it - // These coefficients are obtained from the assumption that scaling applies to the - // non-stroked "shape proper" and that stroke scale is scaled by the expansion of that - // matrix. We're trying to solve this equation: - // r1 = r0 * sqrt (((w1-r0)/(w0-r0))*((h1-r0)/(h0-r0))) - // The operant of the sqrt() must be positive, which is ensured by the fabs() a few lines above + // 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 + /* 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) * (h1-r1) = r0^2 * (w1-r1) * (h0-r0) + * + * 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) { + // Of the two roots, I verified experimentally that this is the one we need gdouble r1 = fabs((-B - sqrt(B*B - 4*A*C))/(2*A)); - //gdouble r2 = (-B + sqrt (B*B - 4*A*C))/(2*A); - //std::cout << "r0" << r0 << " r1" << r1 << " r2" << r2 << "\n"; - // - // If w1 < 0 then the scale will be wrong if we just do - // gdouble scale_x = (w1 - r1)/(w0 - r0); - // Here we also need the absolute values of w0, w1, h0, h1, and r1 + // 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 gdouble scale_x = (w1 - r1)/(w0 - r0); gdouble scale_y = (h1 - r1)/(h0 - r0); + // 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)); - } else { + } else { // Can't find the roots of the quadratic equation. Likely the input parameters are invalid? scale *= direct; } - } else { - if (r0 == 0 || r0 == Geom::infinity()) { // no stroke to scale - scale *= direct; - } else {// nonscaling strokewidth + } else { // The stroke should not be scaled, or is zero + if (!transform_stroke) { // Nonscaling strokewidth scale *= direct_constant_r; unbudge *= Geom::Translate (flip_x * 0.5 * r0 * (1 - ratio_x), flip_y * 0.5 * r0 * (1 - ratio_y)); + } else { // Strokewidth is zero or infinite + scale *= direct; + } + } + + return (p2o * scale * unbudge * o2n); +} + +/** + * \brief Calculate the affine transformation required to transform one visual bounding box into another, accounting for a VARIABLE strokewidth + * + * Note: Please try to understand get_scale_transform_with_uniform_stroke() first, and read all it's comments carefully. This function + * (get_scale_transform_with_unequal_stroke) is a bit different because it will allow for a strokewidth that's different for each + * side of the visual bounding box. Such a situation will arise when transforming the visual bounding box of a selection of objects, + * each having a different stroke width. In fact this function is a generalized version of get_scale_transform_with_uniform_stroke(), but + * will not (yet) replace it because it has not been tested as carefully, and because the old function is can serve as an introduction to + * understand the new one. + * + * When scaling or stretching an object using the selector, e.g. by dragging the handles or by entering a value, we will + * need to calculate the affine transformation for the old dimensions to the new dimensions. When using a geometric bounding + * box this is very straightforward, but when using a visual bounding box this become more tricky as we need to account for + * 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 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 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 + * \param y1 Coordinate of the target visual bounding box + PS: we have to pass each coordinate individually, to find out if we are mirroring the object; Using a Geom::Rect() instead is + not possible here because it will only allow for a positive width and height, and therefore cannot mirror + * \return +*/ + +Geom::Affine +get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Rect const &bbox_geom, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1) +{ + Geom::Affine p2o = Geom::Translate (-bbox_visual.min()); + Geom::Affine o2n = Geom::Translate (x0, y0); + + Geom::Affine scale = Geom::Scale (1, 1); + 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) 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) + + gdouble w0 = bbox_visual.width(); // will return a value >= 0, as required further down the road + gdouble h0 = bbox_visual.height(); + + // We also know the width and height of the new visual bounding box + gdouble w1 = x1 - x0; // can have any sign + gdouble h1 = y1 - y0; + // The new visual bounding box will have strokes r1l, r1r, r1t, and r1b + + // 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 r0h = h0 - bbox_geom.height(); // r0h is the average strokewidth of the top and bottom edges, i.e. 0.5*(r0t + r0b) + + // Check whether the stroke is not negative; should not be possible, but just in case: + g_assert(r0w >= 0); + g_assert(r0h >= 0); + + if (bbox_visual.hasZeroArea()) { // Obviously we cannot scale from empty visual bounding boxes at all, so we will only translate in such a case + Geom::Affine move = Geom::Translate(x0 - bbox_visual.min()[Geom::X], y0 - bbox_visual.min()[Geom::Y]); + return (move); + } + + Geom::Affine direct = Geom::Scale(w1 / w0, h1 / h0); + + // Although the area of the visual bounding box is not zero, we can still have a geometric + // bounding box with one or both sides having zero length. We can't handle this and will therefore + // simply return the scaling of the visual bounding box, without accounting for any stroke scaling + if (fabs(w0 - r0w) < 1e-6 || fabs(h0 - r0h) < 1e-6 || (!transform_stroke && (fabs(w1 - r0w) < 1e-6 || fabs(h1 - r0h) < 1e-6))) { + return (p2o * direct * o2n); + } + + // Here starts the calculation you've been waiting for; first do some preparation + int flip_x = (w1 > 0) ? 1 : -1; + int flip_y = (h1 > 0) ? 1 : -1; + + // w1 and h1 will be negative when mirroring, but if so then e.g. w1-r0 won't make sense + // Therefore we will use the absolute values from this point on + w1 = fabs(w1); + h1 = fabs(h1); + // w0 and h0 will always be positive due to the definition of the width() and height() methods. + + gdouble ratio_x = (w1 - r0w) / (w0 - r0w); // Only valid when the stroke is kept constant, in which case r1 = r0 + gdouble ratio_y = (h1 - r0h) / (h0 - r0h); + + // Calculating the scaling of the geometric bounding box if the stroke is kept constant + Geom::Affine direct_constant_r = Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); + + // The calculation of the new strokewidth will only use the average stroke for each of the dimensions; To find the new stroke for each + // of the edges individually though, we will use the boundary condition that the ratio of the left/right strokewidth will not change due to the + // scaling. The same holds for the ratio of the top/bottom strokewidth. + 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 + /* 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 + gdouble r1h= fabs((r0h*sqrt(operant)-r0h2*w1-h1*r0h*r0w)/(2*A0-2*r0h*r0w)); + gdouble 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 + gdouble scale_x = (w1 - r1w)/(w0 - r0w); + gdouble scale_y = (h1 - r1h)/(h0 - r0h); + // 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 { // Can't find the roots of the quadratic equation. Likely the input parameters are invalid? + scale *= direct; + } + } else { // The stroke should not be scaled, or is zero (or infinite) + if (!transform_stroke) { + scale *= direct_constant_r; + unbudge *= Geom::Translate (flip_x * stroke_ratio_w * r0w * (1 - ratio_x), flip_y * stroke_ratio_h * r0h * (1 - ratio_y)); + } else { // can't calculate, because apparently strokewidth is zero or infinite + scale *= direct; } } -- cgit v1.2.3 From 6ffe6f384a2d322451cb21e720effdae7aa904f0 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Mon, 11 Jul 2011 20:44:59 +0200 Subject: Fix crash caused by my previous commit; as reported by ~suv in bug lp:212768 Fixed bugs: - https://launchpad.net/bugs/212768 (bzr r10443) --- src/sp-item-transform.cpp | 13 ++++++------- 1 file changed, 6 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 45d965e44..eb4b81a61 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -183,11 +183,11 @@ get_scale_transform_with_uniform_stroke (Geom::Rect const &bbox_visual, gdouble scale *= direct; } } else { // The stroke should not be scaled, or is zero - if (!transform_stroke) { // Nonscaling strokewidth + if (r0 == 0 || r0 == Geom::infinity() ) { // Strokewidth is zero or infinite + scale *= direct; + } else { // Nonscaling strokewidth scale *= direct_constant_r; unbudge *= Geom::Translate (flip_x * 0.5 * r0 * (1 - ratio_x), flip_y * 0.5 * r0 * (1 - ratio_y)); - } else { // Strokewidth is zero or infinite - scale *= direct; } } @@ -336,11 +336,11 @@ get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Re scale *= direct; } } else { // The stroke should not be scaled, or is zero (or infinite) - if (!transform_stroke) { + 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 *= direct_constant_r; unbudge *= Geom::Translate (flip_x * stroke_ratio_w * r0w * (1 - ratio_x), flip_y * stroke_ratio_h * r0h * (1 - ratio_y)); - } else { // can't calculate, because apparently strokewidth is zero or infinite - scale *= direct; } } @@ -350,7 +350,6 @@ get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Re Geom::Rect get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Affine const &abs_affine, gdouble const initial_strokewidth, bool const transform_stroke) { - g_assert(initial_geom_bbox); // Find the new geometric bounding box; Do this by transforming each corner of -- cgit v1.2.3 From 2b6e0b43dbcb38e1098a5308d36ba5e75c08d5a1 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Sun, 17 Jul 2011 14:05:05 +0200 Subject: Fix crash that occurred when scaling a clipped object, as reported in lp:811819 Fixed bugs: - https://launchpad.net/bugs/811819 (bzr r10464) --- src/sp-item-transform.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index eb4b81a61..0fbce27f9 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -248,10 +248,6 @@ get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Re 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) - // Check whether the stroke is not negative; should not be possible, but just in case: - g_assert(r0w >= 0); - g_assert(r0h >= 0); - if (bbox_visual.hasZeroArea()) { // Obviously we cannot scale from empty visual bounding boxes at all, so we will only translate in such a case Geom::Affine move = Geom::Translate(x0 - bbox_visual.min()[Geom::X], y0 - bbox_visual.min()[Geom::Y]); return (move); @@ -266,6 +262,14 @@ get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Re return (p2o * direct * o2n); } + // 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 || r0w < 0) { + // 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); + } + // Here starts the calculation you've been waiting for; first do some preparation int flip_x = (w1 > 0) ? 1 : -1; int flip_y = (h1 > 0) ? 1 : -1; -- cgit v1.2.3 From eed6e9c2c229b10911a23976c47da79fc70a5b87 Mon Sep 17 00:00:00 2001 From: "Johan B. C. Engelen" Date: Sun, 17 Jul 2011 21:47:09 +0200 Subject: - rename SPItem::i2d_affine to i2dt_affine, to clarify that it is item-to-desktop, not item-to-document. This should make it easier to spot bugs. - tag some instances where the document-to-desktop transform has been hardcoded (bzr r10466) --- src/sp-item-transform.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 0fbce27f9..9f166e718 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -25,7 +25,7 @@ sp_item_rotate_rel(SPItem *item, Geom::Rotate const &rotation) Geom::Affine affine = Geom::Affine(s).inverse() * Geom::Affine(rotation) * Geom::Affine(s); // Rotate item. - item->set_i2d_affine(item->i2d_affine() * (Geom::Affine)affine); + item->set_i2d_affine(item->i2dt_affine() * (Geom::Affine)affine); // Use each item's own transform writer, consistent with sp_selection_apply_affine() item->doWriteTransform(item->getRepr(), item->transform); @@ -42,7 +42,7 @@ sp_item_scale_rel (SPItem *item, Geom::Scale const &scale) Geom::OptRect bbox = item->getBboxDesktop(); if (bbox) { Geom::Translate const s(bbox->midpoint()); // use getCenter? - item->set_i2d_affine(item->i2d_affine() * s.inverse() * scale * s); + item->set_i2d_affine(item->i2dt_affine() * s.inverse() * scale * s); item->doWriteTransform(item->getRepr(), item->transform); } } @@ -56,7 +56,7 @@ sp_item_skew_rel (SPItem *item, double skewX, double skewY) Geom::Affine const skew(1, skewY, skewX, 1, 0, 0); Geom::Affine affine = Geom::Affine(s).inverse() * skew * Geom::Affine(s); - item->set_i2d_affine(item->i2d_affine() * affine); + item->set_i2d_affine(item->i2dt_affine() * affine); item->doWriteTransform(item->getRepr(), item->transform); // Restore the center position (it's changed because the bbox center changed) @@ -68,7 +68,7 @@ sp_item_skew_rel (SPItem *item, double skewX, double skewY) void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) { - item->set_i2d_affine(item->i2d_affine() * tr); + item->set_i2d_affine(item->i2dt_affine() * tr); item->doWriteTransform(item->getRepr(), item->transform); } -- cgit v1.2.3 From 72cc39b9f0b340548f395c7f61ca9662b34aea09 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 27 Aug 2011 11:04:37 +0200 Subject: Refactor SPItem bounding box methods: remove NRRect usage and make code using them more obvious. Fix filter region computation. (bzr r10582.1.1) --- src/sp-item-transform.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 9f166e718..749a32d52 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -39,7 +39,7 @@ sp_item_rotate_rel(SPItem *item, Geom::Rotate const &rotation) void sp_item_scale_rel (SPItem *item, Geom::Scale const &scale) { - Geom::OptRect bbox = item->getBboxDesktop(); + Geom::OptRect bbox = item->desktopVisualBounds(); if (bbox) { Geom::Translate const s(bbox->midpoint()); // use getCenter? item->set_i2d_affine(item->i2dt_affine() * s.inverse() * scale * s); -- cgit v1.2.3 From 74e17c3b2817c35a4a327250436da0a72b30bd96 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Sat, 3 Sep 2011 22:26:01 +0200 Subject: Allow changing dimensions of vertical/horizontal lines using the numeric input boxes on the selector toolbar Fixed bugs: - https://launchpad.net/bugs/825840 (bzr r10614) --- src/sp-item-transform.cpp | 183 ++++++++++++++++++++++++++-------------------- 1 file changed, 104 insertions(+), 79 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index 749a32d52..311604153 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -76,7 +76,7 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) /** * \brief Calculate the affine transformation required to transform one visual bounding box into another, accounting for a uniform strokewidth * - * PS: This function will only return accurate results for the visual bounding box of a selection of one of more objects, all having + * PS: This function will only return accurate results for the visual bounding box of a selection of one or more objects, all having * the same strokewidth. If the stroke width varies from object to object in this selection, then the function * get_scale_transform_with_unequal_stroke() should be called instead * @@ -120,23 +120,6 @@ get_scale_transform_with_uniform_stroke (Geom::Rect const &bbox_visual, gdouble gdouble h1 = y1 - y0; // The new visual bounding box will have a stroke r1 - // 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 (bbox_visual.hasZeroArea()) { // Obviously we cannot scale from empty visual bounding boxes at all, so we will only translate in such a case - Geom::Affine move = Geom::Translate(x0 - bbox_visual.min()[Geom::X], y0 - bbox_visual.min()[Geom::Y]); - return (move); - } - - Geom::Affine direct = Geom::Scale(w1 / w0, h1 / h0); // Scaling of the visual bounding box - - // Although the area of the visual bounding box is not zero, we can still have a geometric - // bounding box with one or both sides having zero length. We can't handle this and will therefore - // simply return the scaling of the visual bounding box, without accounting for any stroke scaling - if (fabs(w0 - r0) < 1e-6 || fabs(h0 - r0) < 1e-6 || (!transform_stroke && (fabs(w1 - r0) < 1e-6 || fabs(h1 - r0) < 1e-6))) { - return (p2o * direct * o2n); - } - // Here starts the calculation you've been waiting for; first do some preparation int flip_x = (w1 > 0) ? 1 : -1; int flip_y = (h1 > 0) ? 1 : -1; @@ -148,14 +131,38 @@ get_scale_transform_with_uniform_stroke (Geom::Rect const &bbox_visual, gdouble r0 = fabs(r0); // w0 and h0 will always be positive due to the definition of the width() and height() methods. - gdouble ratio_x = (w1 - r0) / (w0 - r0); // Only valid when the stroke is kept constant, in which case r1 = r0 - gdouble ratio_y = (h1 - r0) / (h0 - r0); + // 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 - // Calculating the scaling of the geometric bounding box if the stroke is kept constant - Geom::Affine direct_constant_r = Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); + if ((fabs(w0 - r0) < 1e-6) && (fabs(h0 - r0) < 1e-6)) { + return Geom::Affine(); + } - // 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 + 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 = (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_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 @@ -170,23 +177,29 @@ get_scale_transform_with_uniform_stroke (Geom::Rect const &bbox_visual, gdouble gdouble C = w1 * h1 * r0*r0; if (B*B - 4*A*C > 0) { // Of the two roots, I verified experimentally that this is the one we need - gdouble r1 = fabs((-B - sqrt(B*B - 4*A*C))/(2*A)); + 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 - gdouble scale_x = (w1 - r1)/(w0 - r0); - gdouble scale_y = (h1 - r1)/(h0 - r0); - // 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)); + 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? - scale *= direct; + r1 = r0; + 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 + 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 *= direct_constant_r; + 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)); } } @@ -248,29 +261,6 @@ get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Re 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 (bbox_visual.hasZeroArea()) { // Obviously we cannot scale from empty visual bounding boxes at all, so we will only translate in such a case - Geom::Affine move = Geom::Translate(x0 - bbox_visual.min()[Geom::X], y0 - bbox_visual.min()[Geom::Y]); - return (move); - } - - Geom::Affine direct = Geom::Scale(w1 / w0, h1 / h0); - - // Although the area of the visual bounding box is not zero, we can still have a geometric - // bounding box with one or both sides having zero length. We can't handle this and will therefore - // simply return the scaling of the visual bounding box, without accounting for any stroke scaling - if (fabs(w0 - r0w) < 1e-6 || fabs(h0 - r0h) < 1e-6 || (!transform_stroke && (fabs(w1 - r0w) < 1e-6 || fabs(h1 - r0h) < 1e-6))) { - return (p2o * direct * o2n); - } - - // 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 || r0w < 0) { - // 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); - } - - // Here starts the calculation you've been waiting for; first do some preparation int flip_x = (w1 > 0) ? 1 : -1; int flip_y = (h1 > 0) ? 1 : -1; @@ -280,20 +270,36 @@ get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Re h1 = fabs(h1); // w0 and h0 will always be positive due to the definition of the width() and height() methods. - gdouble ratio_x = (w1 - r0w) / (w0 - r0w); // Only valid when the stroke is kept constant, in which case r1 = r0 - gdouble ratio_y = (h1 - r0h) / (h0 - r0h); - - // Calculating the scaling of the geometric bounding box if the stroke is kept constant - Geom::Affine direct_constant_r = Geom::Scale(flip_x * ratio_x, flip_y * ratio_y); - - // The calculation of the new strokewidth will only use the average stroke for each of the dimensions; To find the new stroke for each - // of the edges individually though, we will use the boundary condition that the ratio of the left/right strokewidth will not change due to the - // scaling. The same holds for the ratio of the top/bottom strokewidth. - 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 ((fabs(w0 - r0w) < 1e-6) && (fabs(h0 - r0h) < 1e-6)) { + return Geom::Affine(); + } - // 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 + 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 @@ -326,24 +332,43 @@ get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Re 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 - gdouble r1h= fabs((r0h*sqrt(operant)-r0h2*w1-h1*r0h*r0w)/(2*A0-2*r0h*r0w)); - gdouble 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)); + 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 - gdouble scale_x = (w1 - r1w)/(w0 - r0w); - gdouble scale_y = (h1 - r1h)/(h0 - r0h); - // 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)); + 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 *= direct; + 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) { + // 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); + } + + // The calculation of the new strokewidth will only use the average stroke for each of the dimensions; To find the new stroke for each + // of the edges individually though, we will use the boundary condition that the ratio of the left/right strokewidth will not change due to the + // scaling. The same holds for the ratio of the top/bottom strokewidth. + 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 *= direct_constant_r; + 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)); } } -- cgit v1.2.3 From 1c0a4eca434ada5675c6edc476325b7bb64da1a6 Mon Sep 17 00:00:00 2001 From: Diederik van Lierop Date: Sun, 4 Sep 2011 20:11:51 +0200 Subject: 1) Fix absolute scaling in transform dialog 2) Transform dialog now follows the user prefs for geometric vs. visual bounding box (bzr r10615) --- src/sp-item-transform.cpp | 14 +++++++------- 1 file changed, 7 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 311604153..d1fe14f20 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -78,7 +78,7 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) * * PS: This function will only return accurate results for the visual bounding box of a selection of one or more objects, all having * the same strokewidth. If the stroke width varies from object to object in this selection, then the function - * get_scale_transform_with_unequal_stroke() should be called instead + * get_scale_transform_for_variable_stroke() should be called instead * * When scaling or stretching an object using the selector, e.g. by dragging the handles or by entering a value, we will * need to calculate the affine transformation for the old dimensions to the new dimensions. When using a geometric bounding @@ -98,7 +98,7 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) */ Geom::Affine -get_scale_transform_with_uniform_stroke (Geom::Rect const &bbox_visual, gdouble strokewidth, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1) +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 p2o = Geom::Translate (-bbox_visual.min()); Geom::Affine o2n = Geom::Translate (x0, y0); @@ -210,10 +210,10 @@ get_scale_transform_with_uniform_stroke (Geom::Rect const &bbox_visual, gdouble /** * \brief Calculate the affine transformation required to transform one visual bounding box into another, accounting for a VARIABLE strokewidth * - * Note: Please try to understand get_scale_transform_with_uniform_stroke() first, and read all it's comments carefully. This function - * (get_scale_transform_with_unequal_stroke) is a bit different because it will allow for a strokewidth that's different for each + * Note: Please try to understand get_scale_transform_for_uniform_stroke() first, and read all it's comments carefully. This function + * (get_scale_transform_for_variable_stroke) is a bit different because it will allow for a strokewidth that's different for each * side of the visual bounding box. Such a situation will arise when transforming the visual bounding box of a selection of objects, - * each having a different stroke width. In fact this function is a generalized version of get_scale_transform_with_uniform_stroke(), but + * each having a different stroke width. In fact this function is a generalized version of get_scale_transform_for_uniform_stroke(), but * will not (yet) replace it because it has not been tested as carefully, and because the old function is can serve as an introduction to * understand the new one. * @@ -236,7 +236,7 @@ get_scale_transform_with_uniform_stroke (Geom::Rect const &bbox_visual, gdouble */ Geom::Affine -get_scale_transform_with_unequal_stroke (Geom::Rect const &bbox_visual, Geom::Rect const &bbox_geom, bool transform_stroke, gdouble x0, gdouble y0, gdouble x1, gdouble y1) +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 p2o = Geom::Translate (-bbox_visual.min()); Geom::Affine o2n = Geom::Translate (x0, y0); @@ -393,7 +393,7 @@ get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Affine const &abs Geom::Rect new_visual_bbox = new_geom_bbox; if (initial_strokewidth > 0 && initial_strokewidth < Geom::infinity()) { if (transform_stroke) { - // scale stroke by: sqrt (((w1-r0)/(w0-r0))*((h1-r0)/(h0-r0))) (for visual bboxes, see get_scale_transform_with_stroke) + // scale stroke by: sqrt (((w1-r0)/(w0-r0))*((h1-r0)/(h0-r0))) (for visual bboxes, see get_scale_transform_for_stroke) // equals scaling by: sqrt ((w1/w0)*(h1/h0)) for geometrical bboxes // equals scaling by: sqrt (area1/area0) for geometrical bboxes gdouble const new_strokewidth = initial_strokewidth * sqrt (new_geom_bbox.area() / initial_geom_bbox->area()); -- cgit v1.2.3 From 20097d47e6945bceb57d2335d23fe764f493ab59 Mon Sep 17 00:00:00 2001 From: "Jon A. Cruz" Date: Sun, 2 Oct 2011 20:44:17 -0700 Subject: Another minor pass of Doxygen cleanup. (bzr r10659) --- src/sp-item-transform.cpp | 66 +++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 37 deletions(-) (limited to 'src/sp-item-transform.cpp') diff --git a/src/sp-item-transform.cpp b/src/sp-item-transform.cpp index d1fe14f20..a8d553e9f 100644 --- a/src/sp-item-transform.cpp +++ b/src/sp-item-transform.cpp @@ -17,8 +17,7 @@ #include <2geom/transforms.h> #include "sp-item.h" -void -sp_item_rotate_rel(SPItem *item, Geom::Rotate const &rotation) +void sp_item_rotate_rel(SPItem *item, Geom::Rotate const &rotation) { Geom::Point center = item->getCenter(); Geom::Translate const s(item->getCenter()); @@ -36,8 +35,7 @@ sp_item_rotate_rel(SPItem *item, Geom::Rotate const &rotation) } } -void -sp_item_scale_rel (SPItem *item, Geom::Scale const &scale) +void sp_item_scale_rel(SPItem *item, Geom::Scale const &scale) { Geom::OptRect bbox = item->desktopVisualBounds(); if (bbox) { @@ -47,8 +45,7 @@ sp_item_scale_rel (SPItem *item, Geom::Scale const &scale) } } -void -sp_item_skew_rel (SPItem *item, double skewX, double skewY) +void sp_item_skew_rel(SPItem *item, double skewX, double skewY) { Geom::Point center = item->getCenter(); Geom::Translate const s(item->getCenter()); @@ -74,7 +71,7 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) } /** - * \brief Calculate the affine transformation required to transform one visual bounding box into another, accounting for a uniform strokewidth + * Calculate the affine transformation required to transform one visual bounding box into another, accounting for a uniform strokewidth. * * PS: This function will only return accurate results for the visual bounding box of a selection of one or more objects, all having * the same strokewidth. If the stroke width varies from object to object in this selection, then the function @@ -85,20 +82,18 @@ void sp_item_move_rel(SPItem *item, Geom::Translate const &tr) * box this is very straightforward, but when using a visual bounding box this become more tricky as we need to account for * 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 transform_stroke If true then the stroke will be scaled proportional to the square root of the area of the geometric bounding box - * \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 - * \param y1 Coordinate of the target visual bounding box + * @param bbox_visual Current visual bounding box + * @param strokewidth Strokewidth + * @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 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 + * @param y1 Coordinate of the target visual bounding box * PS: we have to pass each coordinate individually, to find out if we are mirroring the object; Using a Geom::Rect() instead is - 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) + * 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 p2o = Geom::Translate (-bbox_visual.min()); Geom::Affine o2n = Geom::Translate (x0, y0); @@ -208,7 +203,7 @@ get_scale_transform_for_uniform_stroke (Geom::Rect const &bbox_visual, gdouble s } /** - * \brief Calculate the affine transformation required to transform one visual bounding box into another, accounting for a VARIABLE strokewidth + * Calculate the affine transformation required to transform one visual bounding box into another, accounting for a VARIABLE strokewidth. * * Note: Please try to understand get_scale_transform_for_uniform_stroke() first, and read all it's comments carefully. This function * (get_scale_transform_for_variable_stroke) is a bit different because it will allow for a strokewidth that's different for each @@ -223,20 +218,18 @@ get_scale_transform_for_uniform_stroke (Geom::Rect const &bbox_visual, gdouble s * 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 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 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 - * \param y1 Coordinate of the target visual bounding box - PS: we have to pass each coordinate individually, to find out if we are mirroring the object; Using a Geom::Rect() instead is - 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) + * @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 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 + * @param y1 Coordinate of the target visual bounding box + * PS: we have to pass each coordinate individually, to find out if we are mirroring the object; Using a Geom::Rect() instead is + * 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 p2o = Geom::Translate (-bbox_visual.min()); Geom::Affine o2n = Geom::Translate (x0, y0); @@ -376,8 +369,7 @@ get_scale_transform_for_variable_stroke (Geom::Rect const &bbox_visual, Geom::Re return (p2o * scale * unbudge * o2n); } -Geom::Rect -get_visual_bbox (Geom::OptRect const &initial_geom_bbox, Geom::Affine const &abs_affine, gdouble const initial_strokewidth, bool const transform_stroke) +Geom::Rect get_visual_bbox(Geom::OptRect const &initial_geom_bbox, Geom::Affine const &abs_affine, gdouble const initial_strokewidth, bool const transform_stroke) { g_assert(initial_geom_bbox); -- cgit v1.2.3