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



commit eb0870cd8f25a5eda2007956f9190ddd9cb65126
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/gimpunifiedtransformationtool.c |   99 ++++++++++++++++++++++++++++-
 1 files changed, 98 insertions(+), 1 deletions(-)
---
diff --git a/app/tools/gimpunifiedtransformationtool.c b/app/tools/gimpunifiedtransformationtool.c
index e134f3d..36a7fda 100644
--- a/app/tools/gimpunifiedtransformationtool.c
+++ b/app/tools/gimpunifiedtransformationtool.c
@@ -710,6 +710,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);
@@ -775,6 +779,7 @@ gimp_unified_transformation_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;
@@ -808,6 +813,7 @@ gimp_unified_transformation_tool_motion (GimpTransformTool *transform_tool)
       return;
     }
 
+  /* rotate */
   if (function == TRANSFORM_HANDLE_ROTATION)
     {
       GimpVector2 m = { .x = transform_tool->curx,   .y = transform_tool->cury };
@@ -830,6 +836,7 @@ gimp_unified_transformation_tool_motion (GimpTransformTool *transform_tool)
       return;
     }
 
+  /* move rotation axis */
   if (function == TRANSFORM_HANDLE_PIVOT)
     {
       gdouble dx = transform_tool->curx - transform_tool->mousex;
@@ -840,7 +847,7 @@ gimp_unified_transformation_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++)
             {
@@ -867,6 +874,96 @@ gimp_unified_transformation_tool_motion (GimpTransformTool *transform_tool)
       return;
     }
 
+  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;
+
+      /* 1: northwest, 2: northeast, 3: southwest, 4: 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;
+
+      return;
+    }
+
   if (options->alternate)
     {
       gdouble *x0, *x1, *y0, *y1;



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