[gtk/path-work-rebased: 127/149] curve: Add some curve utilities
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/path-work-rebased: 127/149] curve: Add some curve utilities
- Date: Fri, 8 Apr 2022 02:53:29 +0000 (UTC)
commit 3306a46cef525205f2ee31b8b7873817364d01ac
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Apr 7 14:15:28 2022 -0400
curve: Add some curve utilities
These apis will be used in the stroker.
gsk/gskcurve.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++
gsk/gskcurveprivate.h | 6 ++
2 files changed, 156 insertions(+)
---
diff --git a/gsk/gskcurve.c b/gsk/gskcurve.c
index c7a3974acc..1f6f542f11 100644
--- a/gsk/gskcurve.c
+++ b/gsk/gskcurve.c
@@ -1846,6 +1846,156 @@ gsk_curve_print (const GskCurve *curve)
get_class (curve->op)->print (curve);
}
+/* }}} */
+/* {{{ Utilities */
+
+static void
+align_points (const graphene_point_t *p,
+ const graphene_point_t *a,
+ const graphene_point_t *b,
+ graphene_point_t *q,
+ int n)
+{
+ graphene_vec2_t n1;
+ float angle;
+ float s, c;
+
+ get_tangent (a, b, &n1);
+ angle = - atan2 (graphene_vec2_get_y (&n1), graphene_vec2_get_x (&n1));
+ sincosf (angle, &s, &c);
+
+ for (int i = 0; i < n; i++)
+ {
+ q[i].x = (p[i].x - a->x) * c - (p[i].y - a->y) * s;
+ q[i].y = (p[i].x - a->x) * s + (p[i].y - a->y) * c;
+ }
+}
+
+/* find solutions for at^2 + bt + c = 0 */
+static int
+solve_quadratic (float a, float b, float c, float t[2])
+{
+ float d;
+ int n = 0;
+
+ if (fabs (a) > 0.0001)
+ {
+ if (b*b > 4*a*c)
+ {
+ d = sqrt (b*b - 4*a*c);
+ t[n++] = (-b + d)/(2*a);
+ t[n++] = (-b - d)/(2*a);
+ }
+ else
+ {
+ t[n++] = -b / (2*a);
+ }
+ }
+ else if (fabs (b) > 0.0001)
+ {
+ t[n++] = -c / b;
+ }
+
+ return n;
+}
+
+static int
+filter_allowable (float t[3],
+ int n)
+{
+ float g[3];
+ int j = 0;
+
+ for (int i = 0; i < n; i++)
+ if (0 < t[i] && t[i] < 1)
+ g[j++] = t[i];
+ for (int i = 0; i < j; i++)
+ t[i] = g[i];
+ return j;
+}
+
+/* Get the points where the curvature of curve is
+ * zero, or a maximum or minimum, inside the open
+ * interval from 0 to 1.
+ */
+int
+gsk_curve_get_curvature_points (const GskCurve *curve,
+ float t[3])
+{
+ const graphene_point_t *pts = curve->curve.points;
+ graphene_point_t p[4];
+ float a, b, c, d;
+ float x, y, z;
+ int n;
+
+ if (curve->op != GSK_PATH_CURVE)
+ return 0;
+
+ align_points (pts, &pts[0], &pts[3], p, 4);
+
+ a = p[2].x * p[1].y;
+ b = p[3].x * p[1].y;
+ c = p[1].x * p[2].y;
+ d = p[3].x * p[2].y;
+
+ x = - 3*a + 2*b + 3*c - d;
+ y = 3*a - b - 3*c;
+ z = c - a;
+
+ n = solve_quadratic (x, y, z, t);
+ return filter_allowable (t, n);
+}
+
+/* Find cusps inside the open interval from 0 to 1. According
+ * to Stone & deRose, A Geometric Characterization of Parametric
+ * Cubic curves, a necessary and sufficient condition is that
+ * the first derivative vanishes.
+ */
+int
+gsk_curve_get_cusps (const GskCurve *curve,
+ float t[2])
+{
+ const graphene_point_t *pts = curve->curve.points;
+ graphene_point_t p[3];
+ float ax, bx, cx;
+ float ay, by, cy;
+ float tx[3];
+ int nx;
+ int n = 0;
+
+ if (curve->op != GSK_PATH_CURVE)
+ return 0;
+
+ p[0].x = 3 * (pts[1].x - pts[0].x);
+ p[0].y = 3 * (pts[1].y - pts[0].y);
+ p[1].x = 3 * (pts[2].x - pts[1].x);
+ p[1].y = 3 * (pts[2].y - pts[1].y);
+ p[2].x = 3 * (pts[3].x - pts[2].x);
+ p[2].y = 3 * (pts[3].y - pts[2].y);
+
+ ax = p[0].x - 2 * p[1].x + p[2].x;
+ bx = - 2 * p[0].x + 2 * p[1].x;
+ cx = p[0].x;
+
+ nx = solve_quadratic (ax, bx, cx, tx);
+ nx = filter_allowable (tx, nx);
+
+ ay = p[0].y - 2 * p[1].y + p[2].y;
+ by = - 2 * p[0].y + 2 * p[1].y;
+ cy = p[0].y;
+
+ for (int i = 0; i < nx; i++)
+ {
+ float ti = tx[i];
+
+ if (0 < ti && ti < 1 &&
+ fabs (ay * ti * ti + by * ti + cy) < 0.001)
+ t[n++] = ti;
+ }
+
+ return n;
+}
+
/* }}} */
/* vim:set foldmethod=marker expandtab: */
diff --git a/gsk/gskcurveprivate.h b/gsk/gskcurveprivate.h
index c3ffd0d99f..f0cc4292d0 100644
--- a/gsk/gskcurveprivate.h
+++ b/gsk/gskcurveprivate.h
@@ -152,6 +152,12 @@ float gsk_curve_get_curvature (const GskCurve
void gsk_curve_print (const GskCurve *curve);
+int gsk_curve_get_curvature_points (const GskCurve *curve,
+ float t[3]);
+
+int gsk_curve_get_cusps (const GskCurve *curve,
+ float t[2]);
+
G_END_DECLS
#endif /* __GSK_CURVE_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]