[gegl] spherize: wrap image aroudn the sphere, rather than projecting it atop it
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] spherize: wrap image aroudn the sphere, rather than projecting it atop it
- Date: Mon, 2 Oct 2017 23:45:46 +0000 (UTC)
commit e5f7c10b5f9b04ccfb1f48ee6113f8c35cc939cb
Author: Ell <ell_se yahoo com>
Date: Mon Oct 2 18:52:11 2017 -0400
spherize: wrap image aroudn the sphere, rather than projecting it atop it
Chnage the mapping so that the input image is wrapped around the
spherical cap, rather than projected on top of it. In particular,
this produces an effect even when the angle of view is 0 deg.,
i.e., when the focal length is infinite.
Change the default angle of view to 0 deg.
On a side note, taking a closer look at the Photoshop Spherize
filter, it uses the "amount" property differently than us. Both
filters produce the same effect--wrapping the image around a
hemisphere--when "amount" is 1 (and the angle of view is 0 deg.,
which can't be changed in Photoshop.) Likewise, both filters
produce the inverse transform when "amount" is -1. However,
while we use fractional amounts to control the curvature of the
spherical cap, by adjusting its apex angle and radius, Photoshop
uses fractional amounts to scale the full-amount displacement.
Furthermore, while we use negative amounts to perform the inverse
transform of the corresponding positive amount, Photoshop uses
negative amounts to scale the -1 displacemnt, which is *not* the
inverse transform of the corresponding positive amount. All in
all, I like our version better, so I'm keeping it.
operations/workshop/spherize.c | 84 +++++++++++++++++++++++----------------
1 files changed, 49 insertions(+), 35 deletions(-)
---
diff --git a/operations/workshop/spherize.c b/operations/workshop/spherize.c
index 61bf3dc..4ed58f8 100644
--- a/operations/workshop/spherize.c
+++ b/operations/workshop/spherize.c
@@ -33,13 +33,13 @@ property_enum (mode, _("Mode"),
GEGL_SPHERIZE_MODE_RADIAL)
description (_("Displacement mode"))
-property_double (angle_of_view, _("Angle of view"), 90.0)
+property_double (angle_of_view, _("Angle of view"), 0.0)
description (_("Camera angle of view"))
value_range (0.0, 180.0)
ui_meta ("unit", "degree")
property_double (amount, _("Amount"), 1.0)
- description (_("Spherical cap angle, as a fraction of the co-angle of view"))
+ description (_("Spherical cap apex angle, as a fraction of the co-angle of view"))
value_range (-1.0, 1.0)
property_enum (sampler_type, _("Resampling method"),
@@ -64,12 +64,14 @@ property_color (background_color, _("Background color"), "none")
#include "gegl-op.h"
#include <math.h>
+#define EPSILON 1e-10
+
static gboolean
is_identity (GeglOperation *operation)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
- return o->angle_of_view < 1e-10 || fabs (o->amount) < 1e-10;
+ return fabs (o->amount) < EPSILON;
}
static gboolean
@@ -164,12 +166,13 @@ process (GeglOperation *operation,
gdouble cx, cy;
gdouble dx = 0.0, dy = 0.0;
gdouble coangle_of_view_2;
- gdouble cap_angle;
gdouble focal_length;
+ gdouble cap_angle_2;
gdouble cap_radius;
- gdouble cap_height;
- gdouble f, f2, r, r2, h, f_h, f_h2, f_hf;
+ gdouble cap_depth;
+ gdouble f, f2, r, r_inv, r2, p, f_p, f_p2, f_pf, a, a_inv;
gboolean is_id;
+ gboolean perspective;
gboolean inverse;
gint i, j;
@@ -201,22 +204,26 @@ process (GeglOperation *operation,
}
coangle_of_view_2 = MAX (180.0 - o->angle_of_view, 0.01) * G_PI / 360.0;
- cap_angle = fabs (o->amount) * coangle_of_view_2;
focal_length = tan (coangle_of_view_2);
- cap_radius = 1.0 / sin (cap_angle);
- cap_height = cap_radius * cos (cap_angle);
-
- f = focal_length;
- f2 = f * f;
- r = cap_radius;
- r2 = r * r;
- h = cap_height;
- f_h = f + h;
- f_h2 = f_h * f_h;
- f_hf = f_h * f;
-
- is_id = is_identity (operation);
- inverse = o->amount < 0.0;
+ cap_angle_2 = o->amount * coangle_of_view_2;
+ cap_radius = 1.0 / sin (cap_angle_2);
+ cap_depth = cap_radius * cos (cap_angle_2);
+
+ f = focal_length;
+ f2 = f * f;
+ r = cap_radius;
+ r_inv = 1 / r;
+ r2 = r * r;
+ p = cap_depth;
+ f_p = f + p;
+ f_p2 = f_p * f_p;
+ f_pf = f_p * f;
+ a = cap_angle_2;
+ a_inv = 1 / a;
+
+ is_id = is_identity (operation);
+ perspective = o->angle_of_view > EPSILON;
+ inverse = o->amount < 0.0;
while (gegl_buffer_iterator_next (iter))
{
@@ -236,33 +243,40 @@ process (GeglOperation *operation,
d2 = x * x + y * y;
- if (! is_id && d2 <= 1.0)
+ if (! is_id && d2 > 0.0 && d2 < 1.0)
{
gdouble d = sqrt (d2);
- gdouble d2_f2 = d2 + f2;
- gdouble src_d;
+ gdouble src_d = d;
gdouble src_x, src_y;
if (! inverse)
- src_d = (f_hf - sqrt (d2_f2 * r2 - f_h2 * d2)) * d / d2_f2;
- else
- src_d = f * d / (f_h - sqrt (r2 - d2));
+ {
+ gdouble d2_f2 = d2 + f2;
- src_x = i + 0.5;
- src_y = j + 0.5;
+ if (perspective)
+ src_d = (f_pf - sqrt (d2_f2 * r2 - f_p2 * d2)) * d / d2_f2;
- if (d)
+ src_d = (G_PI_2 - acos (src_d * r_inv)) * a_inv;
+ }
+ else
{
- if (dx) src_x = cx + src_d * x / (dx * d);
- if (dy) src_y = cy + src_d * y / (dy * d);
+ src_d = r * cos (G_PI_2 - src_d * a);
+
+ if (perspective)
+ src_d = f * src_d / (f_p - sqrt (r2 - src_d * src_d));
}
+ src_x = dx ? cx + src_d * x / (dx * d) :
+ i + 0.5;
+ src_y = dy ? cy + src_d * y / (dx * d) :
+ j + 0.5;
+
gegl_sampler_get (sampler, src_x, src_y,
NULL, out_pixel, GEGL_ABYSS_NONE);
}
else
{
- if (d2 <= 1.0 || o->keep_surroundings)
+ if (d2 < 1.0 || o->keep_surroundings)
memcpy (out_pixel, in_pixel, sizeof (gfloat) * 4);
else
memcpy (out_pixel, bg_color, sizeof (gfloat) * 4);
@@ -293,7 +307,7 @@ gegl_op_class_init (GeglOpClass *klass)
operation_class->get_required_for_output = get_required_for_output;
operation_class->process = parent_process;
- filter_class->process = process;
+ filter_class->process = process;
gegl_operation_class_set_keys (operation_class,
"name", "gegl:spherize",
@@ -301,7 +315,7 @@ gegl_op_class_init (GeglOpClass *klass)
"categories", "distort:map",
"position-dependent", "true",
"license", "GPL3+",
- "description", _("Project image atop a spherical cap"),
+ "description", _("Wrap image around a spherical cap"),
NULL);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]