[gegl] Add rotate-on-center operation



commit c7f4aba65657b4a7a0df47c97006bd34d188d336
Author: Vilson Vieira <vilson void cc>
Date:   Mon Sep 28 22:35:41 2015 -0300

    Add rotate-on-center operation
    
    Rotate a given buffer, translating to its center first. After
    rotation, calculate the amount needed to keep the produced extent
    on the positive quadrant (always having the origin at its top-left
    corner). Then translate that amount. Everything is done with
    an unique affine matrix.
    
    Because always translate to center, both origin-x and origin-y
    parameters are ignored. Their descriptions are changed to inform
    about that.
    
    Composition test includes a crop step to make it sure we have
    origin at top-left.

 operations/transform/Makefile.am                  |    1 +
 operations/transform/module.c                     |    2 +
 operations/transform/rotate-on-center.c           |  128 +++++++++++++++++++++
 tests/compositions/Makefile.am                    |    1 +
 tests/compositions/reference/rotate-on-center.png |  Bin 0 -> 308940 bytes
 tests/compositions/rotate-on-center.xml           |   24 ++++
 6 files changed, 156 insertions(+), 0 deletions(-)
---
diff --git a/operations/transform/Makefile.am b/operations/transform/Makefile.am
index 30d8f1e..41fd0ee 100644
--- a/operations/transform/Makefile.am
+++ b/operations/transform/Makefile.am
@@ -13,6 +13,7 @@ transformops_la_SOURCES = \
        module.h        \
        reflect.c       \
        rotate.c        \
+       rotate-on-center.c      \
        scale-ratio.c \
        scale-size.c \
        scale-size-keepaspect.c \
diff --git a/operations/transform/module.c b/operations/transform/module.c
index 5148dfa..6210d80 100644
--- a/operations/transform/module.c
+++ b/operations/transform/module.c
@@ -40,6 +40,7 @@ gegl_module_query (GTypeModule *module)
 }
 
 GType rotate_get_type      (void);
+GType rotate_on_center_get_type (void);
 GType scale_ratio_get_type  (void);
 GType scale_size_get_type   (void);
 GType scale_size_keepaspect_get_type   (void);
@@ -56,6 +57,7 @@ gegl_module_register (GTypeModule *module)
 
   dummy = op_transform_get_type ();
   dummy = rotate_get_type ();
+  dummy = rotate_on_center_get_type ();
   dummy = scale_ratio_get_type ();
   dummy = scale_size_get_type ();
   dummy = scale_size_keepaspect_get_type ();
diff --git a/operations/transform/rotate-on-center.c b/operations/transform/rotate-on-center.c
new file mode 100644
index 0000000..0dd7360
--- /dev/null
+++ b/operations/transform/rotate-on-center.c
@@ -0,0 +1,128 @@
+/* This file is part of GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2014 Jon Nordby, The Grid <jononor gmail com>
+ * Copyright 2015 Vilson Vieira, The Grid <vilson void cc>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_double (degrees, -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+  _("Angle to rotate (clockwise)"))
+/*
+ * Override the original properties' descriptions, informing they are ignored
+ * and always set to buffer's center coordinates.
+ */
+gegl_chant_double (origin_x, -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+  _("Ignored. Always uses center of input buffer"))
+gegl_chant_double (origin_y, -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+  _("Ignored. Always uses center of input buffer"))
+
+#else
+
+#define GEGL_CHANT_NAME rotate_on_center
+#define GEGL_CHANT_OPERATION_NAME "gegl:rotate-on-center"
+#define GEGL_CHANT_DESCRIPTION  _("Rotate the buffer around its center, taking care of possible offsets.")
+#define GEGL_CHANT_SELF "rotate-on-center.c"
+#include "chant.h"
+
+#include <math.h>
+
+static void
+generate_matrix (GeglMatrix3 *matrix,
+                 gdouble degrees,
+                 gdouble x,
+                 gdouble y,
+                 gdouble width,
+                 gdouble height)
+{
+  gint i;
+  gdouble radians = degrees * (2 * G_PI / 360.0),
+          tx = 0.0,
+          ty = 0.0,
+          tcoords[4][2];
+  /*
+   * Find coordinates of each corner of the bounding box around buffer,
+   * after the requested rotation.
+   */
+  tcoords[0][0] = - x*cos (radians) - y*sin (radians);
+  tcoords[0][1] =   x*sin (radians) - y*cos (radians);
+
+  tcoords[1][0] =   width*cos (radians) + tcoords[0][0];
+  tcoords[1][1] = - width*sin (radians) + tcoords[0][1];
+
+  tcoords[2][0] =   width*cos (radians) + height*sin (radians) + tcoords[0][0];
+  tcoords[2][1] = - width*sin (radians) + height*cos (radians) + tcoords[0][1];
+
+  tcoords[3][0] =   height*sin (radians) + tcoords[0][0];
+  tcoords[3][1] =   height*cos (radians) + tcoords[0][1];
+
+  /*
+   * Find translation needed to make the bounding box stays in the positive
+   * quadrant.
+   */
+  for (i=0; i<G_N_ELEMENTS (tcoords); i++) {
+    tx = MIN (tx, tcoords[i][0]);
+    ty = MIN (ty, tcoords[i][1]);
+  }
+
+  /*
+   * Define an affine matrix that:
+   * 1. Translates buffer's center to origin
+   * 2. Rotates buffer by given degrees
+   * 3. Translates to the positive quadrant
+   */
+  matrix->coeff [0][0] =  cos (radians);
+  matrix->coeff [0][1] =  sin (radians);
+  matrix->coeff [0][2] = -tx - x*cos (radians) - y*sin (radians);
+
+  matrix->coeff [1][0] = -sin (radians);
+  matrix->coeff [1][1] =  cos (radians);
+  matrix->coeff [1][2] = -ty + x*sin (radians) - y*cos (radians);
+
+  matrix->coeff [2][0] = 0;
+  matrix->coeff [2][1] = 0;
+  matrix->coeff [2][2] = 1;
+}
+
+static void
+create_matrix (OpTransform *op,
+               GeglMatrix3 *matrix)
+{
+  GeglChantOperation *chant = GEGL_CHANT_OPERATION (op);
+  GeglOperation *operation  = GEGL_OPERATION (op);
+  GeglRectangle  in_rect = {0.0,0.0,0.0,0.0};
+
+  if (gegl_operation_source_get_bounding_box (operation, "input"))
+    in_rect = *gegl_operation_source_get_bounding_box (operation, "input");
+
+  // Avoid divide-by-zero
+  if (in_rect.width < 1)
+    in_rect.width = 1;
+  if (in_rect.height < 1)
+    in_rect.height = 1;
+
+  generate_matrix (matrix,
+                   chant->degrees,
+                   in_rect.width,
+                   in_rect.height,
+                   in_rect.width,
+                   in_rect.height);
+}
+
+#endif
diff --git a/tests/compositions/Makefile.am b/tests/compositions/Makefile.am
index cdfa07c..c2d9de4 100644
--- a/tests/compositions/Makefile.am
+++ b/tests/compositions/Makefile.am
@@ -53,6 +53,7 @@ TESTS = \
   reinhard05.xml                  \
   rgb-params.xml                  \
   rotate.xml                      \
+  rotate-on-center.xml            \
   simple-scale.xml                \
   scale-size-keepaspect.xml       \
   sinus.xml                       \
diff --git a/tests/compositions/reference/rotate-on-center.png 
b/tests/compositions/reference/rotate-on-center.png
new file mode 100644
index 0000000..2bc8633
Binary files /dev/null and b/tests/compositions/reference/rotate-on-center.png differ
diff --git a/tests/compositions/rotate-on-center.xml b/tests/compositions/rotate-on-center.xml
new file mode 100644
index 0000000..3a725ec
--- /dev/null
+++ b/tests/compositions/rotate-on-center.xml
@@ -0,0 +1,24 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gegl>
+  <node operation='gegl:crop'>
+    <params>
+      <param name='x'>0</param>
+      <param name='y'>0</param>
+      <param name='width'>280</param>
+      <param name='height'>270</param>
+    </params>
+  </node>
+  <node operation='gegl:rotate-on-center'>
+    <params>
+        <param name='degrees'>45.8</param>
+        <param name='sampler'>linear</param>
+        <param name='origin-x'>0</param>
+        <param name='origin-y'>0</param>
+    </params>
+  </node>
+  <node operation='gegl:load'>
+    <params>
+      <param name="path">data/duck.png</param>
+    </params>
+  </node>
+</gegl>


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