summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Spitzak <spitzak@gmail.com>2016-08-30 22:03:04 -0700
committerSøren Sandmann Pedersen <soren.sandmann@gmail.com>2016-09-02 00:40:11 -0400
commit99b574109dabff9c3c6fa9296b3b0534411b6fdb (patch)
treed5ed371f1d29d626d29f394dd4e633bd8bf297b4
parentb9ead7ddf7c2bb373808e59a4f625e2e732ef2e2 (diff)
demos/scale: Compute filter size using boundary of xformed ellipse
Instead of using the boundary of xformed rectangle, use the boundary of xformed ellipse. This is much more accurate and less blurry. In particular the filtering does not change as the image is rotated. Signed-off-by: Bill Spitzak <spitzak@gmail.com> Reviewed-by: Oded Gabbay <oded.gabbay@gmail.com> Reviewed-by: Soren Sandmann <soren.sandmann@gmail.com>
-rw-r--r--demos/scale.c102
1 files changed, 61 insertions, 41 deletions
diff --git a/demos/scale.c b/demos/scale.c
index d00307e..0995ad0 100644
--- a/demos/scale.c
+++ b/demos/scale.c
@@ -55,50 +55,70 @@ get_widget (app_t *app, const char *name)
return widget;
}
-static double
-min4 (double a, double b, double c, double d)
-{
- double m1, m2;
-
- m1 = MIN (a, b);
- m2 = MIN (c, d);
- return MIN (m1, m2);
-}
-
-static double
-max4 (double a, double b, double c, double d)
-{
- double m1, m2;
-
- m1 = MAX (a, b);
- m2 = MAX (c, d);
- return MAX (m1, m2);
-}
-
+/* Figure out the boundary of a diameter=1 circle transformed into an ellipse
+ * by trans. Proof that this is the correct calculation:
+ *
+ * Transform x,y to u,v by this matrix calculation:
+ *
+ * |u| |a c| |x|
+ * |v| = |b d|*|y|
+ *
+ * Horizontal component:
+ *
+ * u = ax+cy (1)
+ *
+ * For each x,y on a radius-1 circle (p is angle to the point):
+ *
+ * x^2+y^2 = 1
+ * x = cos(p)
+ * y = sin(p)
+ * dx/dp = -sin(p) = -y
+ * dy/dp = cos(p) = x
+ *
+ * Figure out derivative of (1) relative to p:
+ *
+ * du/dp = a(dx/dp) + c(dy/dp)
+ * = -ay + cx
+ *
+ * The min and max u are when du/dp is zero:
+ *
+ * -ay + cx = 0
+ * cx = ay
+ * c = ay/x (2)
+ * y = cx/a (3)
+ *
+ * Substitute (2) into (1) and simplify:
+ *
+ * u = ax + ay^2/x
+ * = a(x^2+y^2)/x
+ * = a/x (because x^2+y^2 = 1)
+ * x = a/u (4)
+ *
+ * Substitute (4) into (3) and simplify:
+ *
+ * y = c(a/u)/a
+ * y = c/u (5)
+ *
+ * Square (4) and (5) and add:
+ *
+ * x^2+y^2 = (a^2+c^2)/u^2
+ *
+ * But x^2+y^2 is 1:
+ *
+ * 1 = (a^2+c^2)/u^2
+ * u^2 = a^2+c^2
+ * u = hypot(a,c)
+ *
+ * Similarily the max/min of v is at:
+ *
+ * v = hypot(b,d)
+ *
+ */
static void
compute_extents (pixman_f_transform_t *trans, double *sx, double *sy)
{
- double min_x, max_x, min_y, max_y;
- pixman_f_vector_t v[4] =
- {
- { { 1, 1, 1 } },
- { { -1, 1, 1 } },
- { { -1, -1, 1 } },
- { { 1, -1, 1 } },
- };
-
- pixman_f_transform_point (trans, &v[0]);
- pixman_f_transform_point (trans, &v[1]);
- pixman_f_transform_point (trans, &v[2]);
- pixman_f_transform_point (trans, &v[3]);
-
- min_x = min4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]);
- max_x = max4 (v[0].v[0], v[1].v[0], v[2].v[0], v[3].v[0]);
- min_y = min4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]);
- max_y = max4 (v[0].v[1], v[1].v[1], v[2].v[1], v[3].v[1]);
-
- *sx = (max_x - min_x) / 2.0;
- *sy = (max_y - min_y) / 2.0;
+ *sx = hypot (trans->m[0][0], trans->m[0][1]) / trans->m[2][2];
+ *sy = hypot (trans->m[1][0], trans->m[1][1]) / trans->m[2][2];
}
typedef struct