[gimp/soc-2012-unified-transformation: 15/39] transformtool: Make perspective op behave as spec



commit 42be84d2b7ea96bc9fd41df514bc78fb1efb263e
Author: Mikael Magnusson <mikachu src gnome org>
Date:   Fri Jun 15 09:11:48 2012 +0200

    transformtool: Make perspective op behave as spec

 app/tools/gimpunifiedtransformtool.c |   97 +++++++++++++++++++++++++++++++++-
 1 files changed, 96 insertions(+), 1 deletions(-)
---
diff --git a/app/tools/gimpunifiedtransformtool.c b/app/tools/gimpunifiedtransformtool.c
index 48839b4..44e1359 100644
--- a/app/tools/gimpunifiedtransformtool.c
+++ b/app/tools/gimpunifiedtransformtool.c
@@ -696,6 +696,10 @@ static inline GimpVector2 scalemult (GimpVector2 a, gdouble b) {
     return c;
 }
 
+static inline GimpVector2 vectorproject (GimpVector2 a, GimpVector2 b) {
+    return scalemult (b, dotprod (a, b)/dotprod (b, b));
+}
+
 /* finds the clockwise angle between the vectors given, 0-2Ï */
 static inline gdouble calcangle (GimpVector2 a, GimpVector2 b) {
     gdouble angle, angle2, length = norm (a) * norm (b);
@@ -754,6 +758,7 @@ gimp_unified_transform_tool_motion (GimpTransformTool *transform_tool)
   ppivot_x = (*transform_tool->prev_trans_info)[PIVOT_X];
   ppivot_y = (*transform_tool->prev_trans_info)[PIVOT_Y];
 
+  /* move */
   if (function == TRANSFORM_HANDLE_CENTER)
     {
       gdouble dx = transform_tool->curx - transform_tool->mousex;
@@ -786,6 +791,7 @@ gimp_unified_transform_tool_motion (GimpTransformTool *transform_tool)
       }
     }
 
+  /* rotate */
   if (function == TRANSFORM_HANDLE_ROTATION)
     {
       GimpVector2 m = { .x = transform_tool->curx,   .y = transform_tool->cury };
@@ -807,6 +813,7 @@ gimp_unified_transform_tool_motion (GimpTransformTool *transform_tool)
       }
     }
 
+  /* move rotation axis */
   if (function == TRANSFORM_HANDLE_PIVOT)
     {
       gdouble dx = transform_tool->curx - transform_tool->mousex;
@@ -817,7 +824,7 @@ gimp_unified_transform_tool_motion (GimpTransformTool *transform_tool)
       if (constrain)
         {
           /* snap to corner points and center */
-          gint closest;
+          gint closest = 0;
           gdouble closest_dist = G_MAXDOUBLE, dist;
           for (i = 0; i < 5; i++)
             {
@@ -842,6 +849,94 @@ gimp_unified_transform_tool_motion (GimpTransformTool *transform_tool)
       *pivot_y = ppivot_y + dy;
     }
 
+  if (function == TRANSFORM_HANDLE_NW ||
+      function == TRANSFORM_HANDLE_NE ||
+      function == TRANSFORM_HANDLE_SE ||
+      function == TRANSFORM_HANDLE_SW)
+    {
+      //TODO: scale through corner
+    }
+
+  if (function == TRANSFORM_HANDLE_N ||
+      function == TRANSFORM_HANDLE_E ||
+      function == TRANSFORM_HANDLE_S ||
+      function == TRANSFORM_HANDLE_W)
+    {
+      //TODO: scale through side
+    }
+
+  if (function == TRANSFORM_HANDLE_N_S ||
+      function == TRANSFORM_HANDLE_E_S ||
+      function == TRANSFORM_HANDLE_S_S ||
+      function == TRANSFORM_HANDLE_W_S)
+    {
+      //TODO: shear
+    }
+
+  /* perspective transform */
+  if (function == TRANSFORM_HANDLE_NW_P ||
+      function == TRANSFORM_HANDLE_NE_P ||
+      function == TRANSFORM_HANDLE_SE_P ||
+      function == TRANSFORM_HANDLE_SW_P)
+    {
+      gdouble dx = transform_tool->curx - transform_tool->mousex;
+      gdouble dy = transform_tool->cury - transform_tool->mousey;
+      gint this, left, right, opposite;
+
+      /* 0: northwest, 1: northeast, 2: southwest, 3: southeast */
+      if (function == TRANSFORM_HANDLE_NW_P) {
+        this = 0; left = 1; right = 2; opposite = 3;
+      } else if (function == TRANSFORM_HANDLE_NE_P) {
+        this = 1; left = 3; right = 0; opposite = 2;
+      } else if (function == TRANSFORM_HANDLE_SW_P) {
+        this = 2; left = 0; right = 3; opposite = 1;
+      } else if (function == TRANSFORM_HANDLE_SE_P) {
+        this = 3; left = 2; right = 1; opposite = 0;
+      } else g_assert_not_reached ();
+
+      if (constrain)
+        { /* when the constrain transformation constraint is enabled, the
+             translation shall only be either along the side angles of the
+             two sides that run to this corner point, or along the
+             diagonal that runs trough this corner point. */
+
+          GimpVector2 l = { .x = px[left],     .y = py[left] };
+          GimpVector2 r = { .x = px[right],    .y = py[right] };
+          GimpVector2 o = { .x = px[opposite], .y = py[opposite] };
+          GimpVector2 t = { .x = px[this],     .y = py[this] };
+          GimpVector2 p = { .x = dx,           .y = dy };
+          GimpVector2 lp, rp, op;
+          gdouble rej_lp, rej_rp, rej_op;
+
+          /* get the vectors along the sides and the diagonal */
+          l = vectorsubtract (t, l);
+          r = vectorsubtract (t, r);
+          o = vectorsubtract (t, o);
+
+          /* project p on l, r and o and see which has the shortest rejection */
+          lp = vectorproject (p, l);
+          rp = vectorproject (p, r);
+          op = vectorproject (p, o);
+
+          rej_lp = norm (vectorsubtract (p, lp));
+          rej_rp = norm (vectorsubtract (p, rp));
+          rej_op = norm (vectorsubtract (p, op));
+
+          if (rej_lp < rej_rp && rej_lp < rej_op)
+            p = lp;
+          else if (rej_rp < rej_op)
+            p = rp;
+          else
+            p = op;
+
+          dx = p.x;
+          dy = p.y;
+        }
+
+      *x[this] = px[this] + dx;
+      *y[this] = py[this] + dy;
+    }
+
   /* old code below */
 #if 0
   if (options->alternate)



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]