Code

Fix pattern knotholder
authorKrzysztof Kosiński <tweenk.pl@gmail.com>
Sat, 3 Apr 2010 16:22:32 +0000 (18:22 +0200)
committerKrzysztof Kosiński <tweenk.pl@gmail.com>
Sat, 3 Apr 2010 16:22:32 +0000 (18:22 +0200)
src/knot-holder-entity.cpp

index 2d0d5eb029f65b9ca1b1e1fc84031c0e277023a1..6fcb262475a674e30b1536ed21752070a9cdf184 100644 (file)
@@ -135,21 +135,16 @@ KnotHolderEntity::snap_knot_position_constrained(Geom::Point const &p, Inkscape:
 
 /*  TODO: this pattern manipulation is not able to handle general transformation matrices. Only matrices that are the result of a pure scale times a pure rotation. */
 
-static gdouble sp_pattern_extract_theta(SPPattern *pat)
+Geom::Point
+PatternKnotHolderEntityXY::knot_get()
 {
-    Geom::Matrix transf = pat->patternTransform;
-    return Geom::atan2(transf.xAxis());
-}
+    SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
 
-static Geom::Point sp_pattern_extract_scale(SPPattern *pat)
-{
-    Geom::Matrix transf = pat->patternTransform;
-    return Geom::Point( transf.expansionX(), transf.expansionY() );
-}
+    gdouble x = 0;
+    gdouble y = -pattern_height(pat);
 
-static Geom::Point sp_pattern_extract_trans(SPPattern const *pat)
-{
-    return Geom::Point(pat->patternTransform[4], pat->patternTransform[5]);
+    Geom::Point delta = Geom::Point(x,y) * pat->patternTransform;
+    return delta;
 }
 
 void
@@ -169,32 +164,23 @@ PatternKnotHolderEntityXY::knot_set(Geom::Point const &p, Geom::Point const &ori
     }
 
     if (state)  {
-        Geom::Point const q = p_snapped - sp_pattern_extract_trans(pat);
+        Geom::Point knot_relpos(0, -pattern_height(pat));
+        Geom::Point const q = p_snapped - (knot_relpos * pat->patternTransform);
         sp_item_adjust_pattern(item, Geom::Matrix(Geom::Translate(q)));
     }
 
     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 }
 
-Geom::Point
-PatternKnotHolderEntityXY::knot_get()
-{
-    SPPattern const *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
-    return sp_pattern_extract_trans(pat);
-}
-
 Geom::Point
 PatternKnotHolderEntityAngle::knot_get()
 {
     SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
 
-    gdouble x = (pattern_width(pat));
-    gdouble y = 0;
-    Geom::Point delta = Geom::Point(x,y);
-    Geom::Point scale = sp_pattern_extract_scale(pat);
-    gdouble theta = sp_pattern_extract_theta(pat);
-    delta = delta * Geom::Matrix(Geom::Scale(scale))*Geom::Matrix(Geom::Rotate(theta));
-    delta = delta + sp_pattern_extract_trans(pat);
+    gdouble x = pattern_width(pat);
+    gdouble y = -pattern_height(pat);
+
+    Geom::Point delta = Geom::Point(x,y) * pat->patternTransform;
     return delta;
 }
 
@@ -206,24 +192,38 @@ PatternKnotHolderEntityAngle::knot_set(Geom::Point const &p, Geom::Point const &
 
     SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
 
-    // get the angle from pattern 0,0 to the cursor pos
-    Geom::Point delta = p - sp_pattern_extract_trans(pat);
-    gdouble theta = atan2(delta);
+    // rotate pattern around XY knot position
+    Geom::Point knot_relpos(pattern_width(pat), -pattern_height(pat));
+    Geom::Point xy_knot_relpos(0, -pattern_height(pat));
+    Geom::Point transform_origin = xy_knot_relpos * pat->patternTransform;
+
+    Geom::Point oldp = (knot_relpos * pat->patternTransform) - transform_origin;
+    Geom::Point newp = p - transform_origin;
+
+    gdouble theta = Geom::angle_between(oldp, newp);
 
     if ( state & GDK_CONTROL_MASK ) {
         theta = sp_round(theta, M_PI/snaps);
     }
 
-    // get the scale from the current transform so we can keep it.
-    Geom::Point scl = sp_pattern_extract_scale(pat);
-    Geom::Matrix rot = Geom::Matrix(Geom::Scale(scl)) * Geom::Matrix(Geom::Rotate(theta));
-    Geom::Point const t = sp_pattern_extract_trans(pat);
-    rot[4] = t[Geom::X];
-    rot[5] = t[Geom::Y];
-    sp_item_adjust_pattern(item, rot, true);
+    Geom::Matrix rot = Geom::Matrix(Geom::Translate(-transform_origin))
+                     * Geom::Rotate(theta)
+                     * Geom::Translate(transform_origin);
+    sp_item_adjust_pattern(item, rot);
     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 }
 
+Geom::Point
+PatternKnotHolderEntityScale::knot_get()
+{
+    SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
+
+    gdouble x = pattern_width(pat);
+    gdouble y = 0;
+    Geom::Point delta = Geom::Point(x,y) * pat->patternTransform;
+    return delta;
+}
+
 void
 PatternKnotHolderEntityScale::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
 {
@@ -232,49 +232,32 @@ PatternKnotHolderEntityScale::knot_set(Geom::Point const &p, Geom::Point const &
     // FIXME: this snapping should be done together with knowing whether control was pressed. If GDK_CONTROL_MASK, then constrained snapping should be used.
     Geom::Point p_snapped = snap_knot_position(p);
 
-    // get angle from current transform
-    gdouble theta = sp_pattern_extract_theta(pat);
+    Geom::Point knot_relpos(pattern_width(pat), 0);
+    Geom::Point xy_knot_relpos(0, -pattern_height(pat));
+    Geom::Point transform_origin = xy_knot_relpos * pat->patternTransform;
 
-    // Get the new scale from the position of the knotholder
-    Geom::Point d = p_snapped - sp_pattern_extract_trans(pat);
-    gdouble pat_x = pattern_width(pat);
-    gdouble pat_y = pattern_height(pat);
-    Geom::Scale scl(1);
-    if ( state & GDK_CONTROL_MASK ) {
-        // if ctrl is pressed: use 1:1 scaling
-        gdouble pat_h = hypot(pat_x, pat_y);
-        scl = Geom::Scale(d.length() / pat_h);
+    // do the scaling in pattern coordinate space
+    Geom::Point oldp = knot_relpos - xy_knot_relpos;
+    Geom::Point newp = p_snapped * pat->patternTransform.inverse() - xy_knot_relpos;
+
+    if (Geom::are_near(newp.length(), 0)) return;
+
+    Geom::Scale s(1);
+    if (state & GDK_CONTROL_MASK) {
+        // uniform scaling
+        s = Geom::Scale(oldp * (newp.length() * oldp.length()));
     } else {
-        d *= Geom::Rotate(-theta);
-        scl = Geom::Scale(d[Geom::X] / pat_x, d[Geom::Y] / pat_y);
+        s = Geom::Scale(newp[Geom::X] / oldp[Geom::X], newp[Geom::Y] / oldp[Geom::Y]);
     }
 
-    Geom::Matrix rot = (Geom::Matrix)scl * Geom::Rotate(theta);
-
-    Geom::Point const t = sp_pattern_extract_trans(pat);
-    rot[4] = t[Geom::X];
-    rot[5] = t[Geom::Y];
-    sp_item_adjust_pattern(item, rot, true);
+    Geom::Matrix scl = Geom::Matrix(Geom::Translate(-xy_knot_relpos))
+                     * s
+                     * Geom::Translate(xy_knot_relpos)
+                     * pat->patternTransform;
+    sp_item_adjust_pattern(item, scl, true);
     item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
 }
 
-
-Geom::Point
-PatternKnotHolderEntityScale::knot_get()
-{
-    SPPattern *pat = SP_PATTERN(SP_STYLE_FILL_SERVER(SP_OBJECT(item)->style));
-
-    gdouble x = pattern_width(pat);
-    gdouble y = pattern_height(pat);
-    Geom::Point delta = Geom::Point(x,y);
-    Geom::Matrix a = pat->patternTransform;
-    a[4] = 0;
-    a[5] = 0;
-    delta = delta * a;
-    delta = delta + sp_pattern_extract_trans(pat);
-    return delta;
-}
-
 /*
   Local Variables:
   mode:c++