1
/* cairo - a vector graphics library with display and print output
2
 *
3
 * Copyright © 2002 University of Southern California
4
 * Copyright © 2008 Chris Wilson
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is University of Southern
32
 * California.
33
 *
34
 * Contributor(s):
35
 *	Carl D. Worth <cworth@cworth.org>
36
 *	Chris Wilson <chris@chris-wilson.co.uk>
37
 */
38

            
39
#include "cairoint.h"
40

            
41
#include "cairo-error-private.h"
42
#include "cairo-slope-private.h"
43

            
44
static void
45
_cairo_pen_compute_slopes (cairo_pen_t *pen);
46

            
47
cairo_status_t
48
4260
_cairo_pen_init (cairo_pen_t	*pen,
49
		 double		 radius,
50
		 double		 tolerance,
51
		 const cairo_matrix_t	*ctm)
52
{
53
    int i;
54
    int reflect;
55

            
56
    if (CAIRO_INJECT_FAULT ())
57
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
58

            
59
    VG (VALGRIND_MAKE_MEM_UNDEFINED (pen, sizeof (cairo_pen_t)));
60

            
61
4260
    pen->radius = radius;
62
4260
    pen->tolerance = tolerance;
63

            
64
4260
    reflect = _cairo_matrix_compute_determinant (ctm) < 0.;
65

            
66
4260
    pen->num_vertices = _cairo_pen_vertices_needed (tolerance,
67
						    radius,
68
						    ctm);
69

            
70
4260
    if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
71
909
	pen->vertices = _cairo_malloc_ab (pen->num_vertices,
72
					  sizeof (cairo_pen_vertex_t));
73
909
	if (unlikely (pen->vertices == NULL))
74
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
75
    } else {
76
3351
	pen->vertices = pen->vertices_embedded;
77
    }
78

            
79
    /*
80
     * Compute pen coordinates.  To generate the right ellipse, compute points around
81
     * a circle in user space and transform them to device space.  To get a consistent
82
     * orientation in device space, flip the pen if the transformation matrix
83
     * is reflecting
84
     */
85
139746
    for (i=0; i < pen->num_vertices; i++) {
86
135486
	cairo_pen_vertex_t *v = &pen->vertices[i];
87
135486
	double theta = 2 * M_PI * i / (double) pen->num_vertices, dx, dy;
88
135486
	if (reflect)
89
10776
	    theta = -theta;
90
135486
	dx = radius * cos (theta);
91
135486
	dy = radius * sin (theta);
92
135486
	cairo_matrix_transform_distance (ctm, &dx, &dy);
93
135486
	v->point.x = _cairo_fixed_from_double (dx);
94
135486
	v->point.y = _cairo_fixed_from_double (dy);
95
    }
96

            
97
4260
    _cairo_pen_compute_slopes (pen);
98

            
99
4260
    return CAIRO_STATUS_SUCCESS;
100
}
101

            
102
void
103
4260
_cairo_pen_fini (cairo_pen_t *pen)
104
{
105
4260
    if (pen->vertices != pen->vertices_embedded)
106
909
	free (pen->vertices);
107

            
108

            
109
    VG (VALGRIND_MAKE_MEM_UNDEFINED (pen, sizeof (cairo_pen_t)));
110
4260
}
111

            
112
cairo_status_t
113
_cairo_pen_init_copy (cairo_pen_t *pen, const cairo_pen_t *other)
114
{
115
    VG (VALGRIND_MAKE_MEM_UNDEFINED (pen, sizeof (cairo_pen_t)));
116

            
117
    *pen = *other;
118

            
119
    if (CAIRO_INJECT_FAULT ())
120
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
121

            
122
    pen->vertices = pen->vertices_embedded;
123
    if (pen->num_vertices) {
124
	if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
125
	    pen->vertices = _cairo_malloc_ab (pen->num_vertices,
126
					      sizeof (cairo_pen_vertex_t));
127
	    if (unlikely (pen->vertices == NULL))
128
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
129
	}
130

            
131
	memcpy (pen->vertices, other->vertices,
132
		pen->num_vertices * sizeof (cairo_pen_vertex_t));
133
    }
134

            
135
    return CAIRO_STATUS_SUCCESS;
136
}
137

            
138
cairo_status_t
139
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
140
{
141
    cairo_status_t status;
142
    int num_vertices;
143
    int i;
144

            
145
    if (CAIRO_INJECT_FAULT ())
146
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
147

            
148
    num_vertices = pen->num_vertices + num_points;
149
    if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
150
	pen->vertices != pen->vertices_embedded)
151
    {
152
	cairo_pen_vertex_t *vertices;
153

            
154
	if (pen->vertices == pen->vertices_embedded) {
155
	    vertices = _cairo_malloc_ab (num_vertices,
156
		                         sizeof (cairo_pen_vertex_t));
157
	    if (unlikely (vertices == NULL))
158
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
159

            
160
	    memcpy (vertices, pen->vertices,
161
		    pen->num_vertices * sizeof (cairo_pen_vertex_t));
162
	} else {
163
	    vertices = _cairo_realloc_ab (pen->vertices,
164
					  num_vertices,
165
					  sizeof (cairo_pen_vertex_t));
166
	    if (unlikely (vertices == NULL))
167
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
168
	}
169

            
170
	pen->vertices = vertices;
171
    }
172

            
173
    pen->num_vertices = num_vertices;
174

            
175
    /* initialize new vertices */
176
    for (i=0; i < num_points; i++)
177
	pen->vertices[pen->num_vertices-num_points+i].point = point[i];
178

            
179
    status = _cairo_hull_compute (pen->vertices, &pen->num_vertices);
180
    if (unlikely (status))
181
	return status;
182

            
183
    _cairo_pen_compute_slopes (pen);
184

            
185
    return CAIRO_STATUS_SUCCESS;
186
}
187

            
188
/*
189
The circular pen in user space is transformed into an ellipse in
190
device space.
191

            
192
We construct the pen by computing points along the circumference
193
using equally spaced angles.
194

            
195
We show that this approximation to the ellipse has maximum error at the
196
major axis of the ellipse.
197

            
198
Set
199

            
200
	    M = major axis length
201
	    m = minor axis length
202

            
203
Align 'M' along the X axis and 'm' along the Y axis and draw
204
an ellipse parameterized by angle 't':
205

            
206
	    x = M cos t			y = m sin t
207

            
208
Perturb t by ± d and compute two new points (x+,y+), (x-,y-).
209
The distance from the average of these two points to (x,y) represents
210
the maximum error in approximating the ellipse with a polygon formed
211
from vertices 2∆ radians apart.
212

            
213
	    x+ = M cos (t+∆)		y+ = m sin (t+∆)
214
	    x- = M cos (t-∆)		y- = m sin (t-∆)
215

            
216
Now compute the approximation error, E:
217

            
218
	Ex = (x - (x+ + x-) / 2)
219
	Ex = (M cos(t) - (Mcos(t+∆) + Mcos(t-∆))/2)
220
	   = M (cos(t) - (cos(t)cos(∆) + sin(t)sin(∆) +
221
			  cos(t)cos(∆) - sin(t)sin(∆))/2)
222
	   = M(cos(t) - cos(t)cos(∆))
223
	   = M cos(t) (1 - cos(∆))
224

            
225
	Ey = y - (y+ - y-) / 2
226
	   = m sin (t) - (m sin(t+∆) + m sin(t-∆)) / 2
227
	   = m (sin(t) - (sin(t)cos(∆) + cos(t)sin(∆) +
228
			  sin(t)cos(∆) - cos(t)sin(∆))/2)
229
	   = m (sin(t) - sin(t)cos(∆))
230
	   = m sin(t) (1 - cos(∆))
231

            
232
	E² = Ex² + Ey²
233
	   = (M cos(t) (1 - cos (∆)))² + (m sin(t) (1-cos(∆)))²
234
	   = (1 - cos(∆))² (M² cos²(t) + m² sin²(t))
235
	   = (1 - cos(∆))² ((m² + M² - m²) cos² (t) + m² sin²(t))
236
	   = (1 - cos(∆))² (M² - m²) cos² (t) + (1 - cos(∆))² m²
237

            
238
Find the extremum by differentiation wrt t and setting that to zero
239

            
240
∂(E²)/∂(t) = (1-cos(∆))² (M² - m²) (-2 cos(t) sin(t))
241

            
242
         0 = 2 cos (t) sin (t)
243
	 0 = sin (2t)
244
	 t = nπ
245

            
246
Which is to say that the maximum and minimum errors occur on the
247
axes of the ellipse at 0 and π radians:
248

            
249
	E²(0) = (1-cos(∆))² (M² - m²) + (1-cos(∆))² m²
250
	      = (1-cos(∆))² M²
251
	E²(π) = (1-cos(∆))² m²
252

            
253
maximum error = M (1-cos(∆))
254
minimum error = m (1-cos(∆))
255

            
256
We must make maximum error ≤ tolerance, so compute the ∆ needed:
257

            
258
	    tolerance = M (1-cos(∆))
259
	tolerance / M = 1 - cos (∆)
260
	       cos(∆) = 1 - tolerance/M
261
                    ∆ = acos (1 - tolerance / M);
262

            
263
Remembering that ∆ is half of our angle between vertices,
264
the number of vertices is then
265

            
266
             vertices = ceil(2π/2∆).
267
                      = ceil(π/∆).
268

            
269
Note that this also equation works for M == m (a circle) as it
270
doesn't matter where on the circle the error is computed.
271
*/
272

            
273
int
274
44313
_cairo_pen_vertices_needed (double	    tolerance,
275
			    double	    radius,
276
			    const cairo_matrix_t  *matrix)
277
{
278
    /*
279
     * the pen is a circle that gets transformed to an ellipse by matrix.
280
     * compute major axis length for a pen with the specified radius.
281
     * we don't need the minor axis length.
282
     */
283
44313
    double major_axis = _cairo_matrix_transformed_circle_major_axis (matrix,
284
								     radius);
285
    int num_vertices;
286

            
287
44313
    if (tolerance >= 4*major_axis) { /* XXX relaxed from 2*major for inkscape */
288
36
	num_vertices = 1;
289
44277
    } else if (tolerance >= major_axis) {
290
1014
	num_vertices = 4;
291
    } else {
292
43263
	double divisor = acos (1 - tolerance / major_axis);
293

            
294
43263
	if (divisor == 0.0)
295
	    return 4;
296

            
297
43263
	num_vertices = ceil (2*M_PI / divisor);
298

            
299
	/* number of vertices must be even */
300
43263
	if (num_vertices % 2)
301
2673
	    num_vertices++;
302

            
303
	/* And we must always have at least 4 vertices. */
304
43263
	if (num_vertices < 4)
305
	    num_vertices = 4;
306
    }
307

            
308
44313
    return num_vertices;
309
}
310

            
311
static void
312
4260
_cairo_pen_compute_slopes (cairo_pen_t *pen)
313
{
314
    int i, i_prev;
315
    cairo_pen_vertex_t *prev, *v, *next;
316

            
317
4260
    for (i=0, i_prev = pen->num_vertices - 1;
318
139746
	 i < pen->num_vertices;
319
135486
	 i_prev = i++) {
320
135486
	prev = &pen->vertices[i_prev];
321
135486
	v = &pen->vertices[i];
322
135486
	next = &pen->vertices[(i + 1) % pen->num_vertices];
323

            
324
135486
	_cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
325
135486
	_cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
326
    }
327
4260
}
328
/*
329
 * Find active pen vertex for clockwise edge of stroke at the given slope.
330
 *
331
 * The strictness of the inequalities here is delicate. The issue is
332
 * that the slope_ccw member of one pen vertex will be equivalent to
333
 * the slope_cw member of the next pen vertex in a counterclockwise
334
 * order. However, for this function, we care strongly about which
335
 * vertex is returned.
336
 *
337
 * [I think the "care strongly" above has to do with ensuring that the
338
 * pen's "extra points" from the spline's initial and final slopes are
339
 * properly found when beginning the spline stroking.]
340
 */
341
int
342
_cairo_pen_find_active_cw_vertex_index (const cairo_pen_t *pen,
343
					const cairo_slope_t *slope)
344
{
345
    int i;
346

            
347
    for (i=0; i < pen->num_vertices; i++) {
348
	if ((_cairo_slope_compare (slope, &pen->vertices[i].slope_ccw) < 0) &&
349
	    (_cairo_slope_compare (slope, &pen->vertices[i].slope_cw) >= 0))
350
	    break;
351
    }
352

            
353
    /* If the desired slope cannot be found between any of the pen
354
     * vertices, then we must have a degenerate pen, (such as a pen
355
     * that's been transformed to a line). In that case, we consider
356
     * the first pen vertex as the appropriate clockwise vertex.
357
     */
358
    if (i == pen->num_vertices)
359
	i = 0;
360

            
361
    return i;
362
}
363

            
364
/* Find active pen vertex for counterclockwise edge of stroke at the given slope.
365
 *
366
 * Note: See the comments for _cairo_pen_find_active_cw_vertex_index
367
 * for some details about the strictness of the inequalities here.
368
 */
369
int
370
_cairo_pen_find_active_ccw_vertex_index (const cairo_pen_t *pen,
371
					 const cairo_slope_t *slope)
372
{
373
    cairo_slope_t slope_reverse;
374
    int i;
375

            
376
    slope_reverse = *slope;
377
    slope_reverse.dx = -slope_reverse.dx;
378
    slope_reverse.dy = -slope_reverse.dy;
379

            
380
    for (i=pen->num_vertices-1; i >= 0; i--) {
381
	if ((_cairo_slope_compare (&pen->vertices[i].slope_ccw, &slope_reverse) >= 0) &&
382
	    (_cairo_slope_compare (&pen->vertices[i].slope_cw, &slope_reverse) < 0))
383
	    break;
384
    }
385

            
386
    /* If the desired slope cannot be found between any of the pen
387
     * vertices, then we must have a degenerate pen, (such as a pen
388
     * that's been transformed to a line). In that case, we consider
389
     * the last pen vertex as the appropriate counterclockwise vertex.
390
     */
391
    if (i < 0)
392
	i = pen->num_vertices - 1;
393

            
394
    return i;
395
}
396

            
397
void
398
4764
_cairo_pen_find_active_cw_vertices (const cairo_pen_t *pen,
399
				    const cairo_slope_t *in,
400
				    const cairo_slope_t *out,
401
				    int *start, int *stop)
402
{
403

            
404
4764
    int lo = 0, hi = pen->num_vertices;
405
    int i;
406

            
407
4764
    i = (lo + hi) >> 1;
408
    do {
409
21636
	if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0)
410
8319
	    lo = i;
411
	else
412
13317
	    hi = i;
413
21636
	i = (lo + hi) >> 1;
414
21636
    } while (hi - lo > 1);
415
4764
    if (_cairo_slope_compare (&pen->vertices[i].slope_cw, in) < 0)
416
4761
	if (++i == pen->num_vertices)
417
99
	    i = 0;
418
4764
    *start = i;
419

            
420
4764
    if (_cairo_slope_compare (out, &pen->vertices[i].slope_ccw) >= 0) {
421
4032
	lo = i;
422
4032
	hi = i + pen->num_vertices;
423
4032
	i = (lo + hi) >> 1;
424
	do {
425
18654
	    int j = i;
426
18654
	    if (j >= pen->num_vertices)
427
7386
		j -= pen->num_vertices;
428
18654
	    if (_cairo_slope_compare (&pen->vertices[j].slope_cw, out) > 0)
429
8043
		hi = i;
430
	    else
431
10611
		lo = i;
432
18654
	    i = (lo + hi) >> 1;
433
18654
	} while (hi - lo > 1);
434
4032
	if (i >= pen->num_vertices)
435
1845
	    i -= pen->num_vertices;
436
    }
437
4764
    *stop = i;
438
4764
}
439

            
440
void
441
7107
_cairo_pen_find_active_ccw_vertices (const cairo_pen_t *pen,
442
				     const cairo_slope_t *in,
443
				     const cairo_slope_t *out,
444
				     int *start, int *stop)
445
{
446
7107
    int lo = 0, hi = pen->num_vertices;
447
    int i;
448

            
449
7107
    i = (lo + hi) >> 1;
450
    do {
451
36192
	if (_cairo_slope_compare (in, &pen->vertices[i].slope_ccw) < 0)
452
22083
	    lo = i;
453
	else
454
14109
	    hi = i;
455
36192
	i = (lo + hi) >> 1;
456
36192
    } while (hi - lo > 1);
457
7107
    if (_cairo_slope_compare (in, &pen->vertices[i].slope_ccw) < 0)
458
7107
	if (++i == pen->num_vertices)
459
840
	    i = 0;
460
7107
    *start = i;
461

            
462
7107
    if (_cairo_slope_compare (&pen->vertices[i].slope_cw, out) <= 0) {
463
6321
	lo = i;
464
6321
	hi = i + pen->num_vertices;
465
6321
	i = (lo + hi) >> 1;
466
	do {
467
32517
	    int j = i;
468
32517
	    if (j >= pen->num_vertices)
469
13464
		j -= pen->num_vertices;
470
32517
	    if (_cairo_slope_compare (out, &pen->vertices[j].slope_ccw) > 0)
471
9102
		hi = i;
472
	    else
473
23415
		lo = i;
474
32517
	    i = (lo + hi) >> 1;
475
32517
	} while (hi - lo > 1);
476
6321
	if (i >= pen->num_vertices)
477
2814
	    i -= pen->num_vertices;
478
    }
479
7107
    *stop = i;
480
7107
}