summaryrefslogtreecommitdiff
path: root/src/cairo-hull.c
diff options
context:
space:
mode:
authorCarl Worth <cworth@cworth.org>2003-10-04 14:34:42 +0000
committerCarl Worth <cworth@cworth.org>2003-10-04 14:34:42 +0000
commit61726a88f24efcbabdff980abdfe1ff8301315b2 (patch)
treeb14a5724e721f01fd4767611e9ef89950f7b7843 /src/cairo-hull.c
parenta249bd717c194d03d480d7803351ee6f21daf0c2 (diff)
Generate convex hull of pen before stroking.
Diffstat (limited to 'src/cairo-hull.c')
-rw-r--r--src/cairo-hull.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/cairo-hull.c b/src/cairo-hull.c
new file mode 100644
index 00000000..fc659853
--- /dev/null
+++ b/src/cairo-hull.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright © 2003 USC, Information Sciences Institute
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * University of Southern California not be used in advertising or
+ * publicity pertaining to distribution of the software without
+ * specific, written prior permission. The University of Southern
+ * California makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
+ * SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Carl D. Worth <cworth@isi.edu>
+ */
+
+#include "cairoint.h"
+
+typedef struct cairo_hull
+{
+ cairo_point_t point;
+ cairo_slope_t slope;
+ int discard;
+} cairo_hull_t;
+
+static cairo_hull_t *
+_cairo_hull_create (cairo_pen_vertex_t *vertices, int num_vertices)
+{
+ int i;
+ cairo_hull_t *hull;
+ cairo_point_t *p, *extremum, tmp;
+
+ extremum = &vertices[0].point;
+ for (i = 1; i < num_vertices; i++) {
+ p = &vertices[i].point;
+ if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x))
+ extremum = p;
+ }
+ /* Put the extremal point at the beginning of the array */
+ tmp = *extremum;
+ *extremum = vertices[0].point;
+ vertices[0].point = tmp;
+
+ hull = malloc (num_vertices * sizeof (cairo_hull_t));
+ if (hull == NULL)
+ return NULL;
+
+ for (i = 0; i < num_vertices; i++) {
+ hull[i].point = vertices[i].point;
+ _cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);
+
+ /* Discard all points coincident with the extremal point */
+ if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
+ hull[i].discard = 1;
+ else
+ hull[i].discard = 0;
+ }
+
+ return hull;
+}
+
+static int
+_cairo_hull_vertex_compare (const void *av, const void *bv)
+{
+ cairo_hull_t *a = (cairo_hull_t *) av;
+ cairo_hull_t *b = (cairo_hull_t *) bv;
+ int ret;
+
+ ret = _cairo_slope_compare (&a->slope, &b->slope);
+
+ /* In the case of two vertices with identical slope from the
+ extremal point discard the nearer point. */
+
+ if (ret == 0) {
+ cairo_fixed_48_16_t a_dist, b_dist;
+ a_dist = ((cairo_fixed_48_16_t) a->slope.dx * a->slope.dx +
+ (cairo_fixed_48_16_t) a->slope.dy * a->slope.dy);
+ b_dist = ((cairo_fixed_48_16_t) b->slope.dx * b->slope.dx +
+ (cairo_fixed_48_16_t) b->slope.dy * b->slope.dy);
+ if (a_dist < b_dist)
+ a->discard = 1;
+ else
+ b->discard = 1;
+ }
+
+ return ret;
+}
+
+static int
+_cairo_hull_prev_valid (cairo_hull_t *hull, int num_hull, int index)
+{
+ do {
+ /* hull[0] is always valid, so don't test and wraparound */
+ index--;
+ } while (hull[index].discard);
+
+ return index;
+}
+
+static int
+_cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index)
+{
+ do {
+ index = (index + 1) % num_hull;
+ } while (hull[index].discard);
+
+ return index;
+}
+
+static cairo_status_t
+_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
+{
+ int i, j, k;
+ cairo_slope_t slope_ij, slope_jk;
+
+ i = 0;
+ j = _cairo_hull_next_valid (hull, num_hull, i);
+ k = _cairo_hull_next_valid (hull, num_hull, j);
+
+ do {
+ _cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
+ _cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);
+
+ /* Is the angle formed by ij and jk concave? */
+ if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
+ if (i == k)
+ return CAIRO_STATUS_SUCCESS;
+ hull[j].discard = 1;
+ j = i;
+ i = _cairo_hull_prev_valid (hull, num_hull, j);
+ } else {
+ i = j;
+ j = k;
+ k = _cairo_hull_next_valid (hull, num_hull, j);
+ }
+ } while (j != 0);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices)
+{
+ int i, j = 0;
+
+ for (i = 0; i < *num_vertices; i++) {
+ if (hull[i].discard)
+ continue;
+ vertices[j++].point = hull[i].point;
+ }
+
+ *num_vertices = j;
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/* Given a set of vertices, compute the convex hull using the Graham
+ scan algorithm. */
+cairo_status_t
+_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
+{
+ cairo_hull_t *hull;
+ int num_hull = *num_vertices;
+
+ hull = _cairo_hull_create (vertices, num_hull);
+ if (hull == NULL)
+ return CAIRO_STATUS_NO_MEMORY;
+
+ qsort (hull + 1, num_hull - 1,
+ sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
+
+ _cairo_hull_eliminate_concave (hull, num_hull);
+
+ _cairo_hull_to_pen (hull, vertices, num_vertices);
+
+ free (hull);
+
+ return CAIRO_STATUS_SUCCESS;
+}