diff options
author | Carl Worth <cworth@cworth.org> | 2003-10-04 14:34:42 +0000 |
---|---|---|
committer | Carl Worth <cworth@cworth.org> | 2003-10-04 14:34:42 +0000 |
commit | 61726a88f24efcbabdff980abdfe1ff8301315b2 (patch) | |
tree | b14a5724e721f01fd4767611e9ef89950f7b7843 /src/cairo-hull.c | |
parent | a249bd717c194d03d480d7803351ee6f21daf0c2 (diff) |
Generate convex hull of pen before stroking.
Diffstat (limited to 'src/cairo-hull.c')
-rw-r--r-- | src/cairo-hull.c | 190 |
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; +} |