[gtk/path-work-rebased: 98/121] curve: Handle degenerate cases
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/path-work-rebased: 98/121] curve: Handle degenerate cases
- Date: Sun, 5 Dec 2021 03:59:04 +0000 (UTC)
commit ad145e201bf2d3fa4effd73753ca7494ec5576bb
Author: Matthias Clasen <mclasen redhat com>
Date: Sat Dec 19 22:14:26 2020 -0500
curve: Handle degenerate cases
Nothing prevents control points from being identical,
and if that happens, some of our constructions involving
tangents and normals break down. Handle these cases in
get_{start,end}_tangent and offset, for the case of
cubics.
gsk/gskcurve.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 99 insertions(+), 16 deletions(-)
---
diff --git a/gsk/gskcurve.c b/gsk/gskcurve.c
index b4a43ad497..db997b10e1 100644
--- a/gsk/gskcurve.c
+++ b/gsk/gskcurve.c
@@ -558,7 +558,15 @@ gsk_curve_curve_get_start_tangent (const GskCurve *curve,
{
const GskCurveCurve *self = &curve->curve;
- get_tangent (&self->points[0], &self->points[1], tangent);
+ if (graphene_point_near (&self->points[0], &self->points[1], 0.0001))
+ {
+ if (graphene_point_near (&self->points[0], &self->points[2], 0.0001))
+ get_tangent (&self->points[0], &self->points[3], tangent);
+ else
+ get_tangent (&self->points[0], &self->points[2], tangent);
+ }
+ else
+ get_tangent (&self->points[0], &self->points[1], tangent);
}
static void
@@ -567,7 +575,15 @@ gsk_curve_curve_get_end_tangent (const GskCurve *curve,
{
const GskCurveCurve *self = &curve->curve;
- get_tangent (&self->points[2], &self->points[3], tangent);
+ if (graphene_point_near (&self->points[2], &self->points[3], 0.0001))
+ {
+ if (graphene_point_near (&self->points[1], &self->points[3], 0.0001))
+ get_tangent (&self->points[0], &self->points[3], tangent);
+ else
+ get_tangent (&self->points[1], &self->points[3], tangent);
+ }
+ else
+ get_tangent (&self->points[2], &self->points[3], tangent);
}
static void
@@ -667,25 +683,92 @@ gsk_curve_curve_offset (const GskCurve *curve,
graphene_vec2_t n;
graphene_point_t p[4];
graphene_point_t m1, m2, m3, m4;
+ int coinc;
- /* Simply scale control points, a la Tiller and Hanson */
- get_normal (&pts[0], &pts[1], &n);
- scale_point (&pts[0], &n, distance, &p[0]);
- scale_point (&pts[1], &n, distance, &m1);
+ coinc = (graphene_point_near (&pts[0], &pts[1], 0.001) << 0) |
+ (graphene_point_near (&pts[1], &pts[2], 0.001) << 1) |
+ (graphene_point_near (&pts[2], &pts[3], 0.001) << 2);
- get_normal (&pts[1], &pts[2], &n);
- scale_point (&pts[1], &n, distance, &m2);
- scale_point (&pts[2], &n, distance, &m3);
+ if (coinc == 7)
+ {
+ /* just give up */
+ p[0] = pts[0];
+ p[1] = pts[1];
+ p[2] = pts[2];
+ p[3] = pts[3];
+ }
+ else if (coinc == 3 || coinc == 5 || coinc == 6)
+ {
+ /* a straight line */
+ get_normal (&pts[0], &pts[3], &n);
+ scale_point (&pts[0], &n, distance, &p[0]);
+ scale_point (&pts[3], &n, distance, &p[3]);
- get_normal (&pts[2], &pts[3], &n);
- scale_point (&pts[2], &n, distance, &m4);
- scale_point (&pts[3], &n, distance, &p[3]);
+ if (coinc & (1 << 0))
+ p[1] = p[0];
+ else
+ p[1] = p[3];
+ if (coinc & (1 << 2))
+ p[2] = p[3];
+ else
+ p[2] = p[0];
+ }
+ else if (coinc == 1 || coinc == 2 || coinc == 4)
+ {
+ graphene_point_t p1;
- if (!line_intersection (&p[0], &m1, &m2, &m3, &p[1]))
- p[1] = m1;
+ if (coinc == 1)
+ p1 = pts[2];
+ else
+ p1 = pts[1];
+
+ get_normal (&pts[0], &p1, &n);
+ scale_point (&pts[0], &n, distance, &p[0]);
+ scale_point (&p1, &n, distance, &m1);
+
+ get_normal (&p1, &pts[3], &n);
+ scale_point (&p1, &n, distance, &m2);
+ scale_point (&pts[3], &n, distance, &p[3]);
+
+ if (!line_intersection (&p[0], &m1, &m2, &p[3], &m3))
+ m3 = m1;
+
+ if (coinc == 1)
+ {
+ p[1] = p[0];
+ p[2] = m3;
+ }
+ else if (coinc == 2)
+ {
+ p[1] = m3;
+ p[2] = m3;
+ }
+ else
+ {
+ p[1] = m3;
+ p[2] = p[3];
+ }
+ }
+ else if (coinc == 0)
+ {
+ get_normal (&pts[0], &pts[1], &n);
+ scale_point (&pts[0], &n, distance, &p[0]);
+ scale_point (&pts[1], &n, distance, &m1);
+
+ get_normal (&pts[1], &pts[2], &n);
+ scale_point (&pts[1], &n, distance, &m2);
+ scale_point (&pts[2], &n, distance, &m3);
+
+ get_normal (&pts[2], &pts[3], &n);
+ scale_point (&pts[2], &n, distance, &m4);
+ scale_point (&pts[3], &n, distance, &p[3]);
- if (!line_intersection (&m2, &m3, &m4, &p[3], &p[2]))
- p[2] = m4;
+ if (!line_intersection (&p[0], &m1, &m2, &m3, &p[1]))
+ p[1] = m1;
+
+ if (!line_intersection (&m2, &m3, &m4, &p[3], &p[2]))
+ p[2] = m4;
+ }
gsk_curve_curve_init_from_points (&offset->curve, p);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]