static int _cairo_pen_vertices_needed (double tolerance, double radius, cairo_matrix_t *matrix) { /* * the pen is a circle that gets transformed to an ellipse by matrix. * compute major axis length for a pen with the specified radius. * we don't need the minor axis length. */ double major_axis = _cairo_matrix_transformed_circle_major_axis(matrix, radius); /* * compute number of vertices needed */ int num_vertices; /* Where tolerance / M is > 1, we use 4 points */ if (tolerance >= major_axis) { num_vertices = 4; } else { double delta = acos (1 - tolerance / major_axis); num_vertices = ceil (M_PI / delta); /* number of vertices must be even */ if (num_vertices % 2) num_vertices++; } return num_vertices; }
int _cairo_pen_vertices_needed (double tolerance, double radius, const cairo_matrix_t *matrix) { /* * the pen is a circle that gets transformed to an ellipse by matrix. * compute major axis length for a pen with the specified radius. * we don't need the minor axis length. */ double major_axis = _cairo_matrix_transformed_circle_major_axis (matrix, radius); int num_vertices; if (tolerance >= 4*major_axis) { /* XXX relaxed from 2*major for inkscape */ num_vertices = 1; } else if (tolerance >= major_axis) { num_vertices = 4; } else { num_vertices = ceil (2*M_PI / acos (1 - tolerance / major_axis)); /* number of vertices must be even */ if (num_vertices % 2) num_vertices++; /* And we must always have at least 4 vertices. */ if (num_vertices < 4) num_vertices = 4; } return num_vertices; }
/* * Verifies if _cairo_stroke_style_dash_approximate should be used to generate * an approximation of the dash pattern in the specified style, when used for * stroking a path with the given CTM and tolerance. * Always %FALSE for non-dashed styles. */ cairo_bool_t _cairo_stroke_style_dash_can_approximate (const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, double tolerance) { double period; if (! style->num_dashes) return FALSE; period = _cairo_stroke_style_dash_period (style); return _cairo_matrix_transformed_circle_major_axis (ctm, period) < tolerance; }
static int _arc_segments_needed (double angle, double radius, cairo_matrix_t *ctm, double tolerance) { double major_axis, max_angle; /* the error is amplified by at most the length of the * major axis of the circle; see cairo-pen.c for a more detailed analysis * of this. */ major_axis = _cairo_matrix_transformed_circle_major_axis (ctm, radius); max_angle = _arc_max_angle_for_tolerance_normalized (tolerance / major_axis); return ceil (fabs (angle) / max_angle); }
/* * Create a 2-dashes approximation of a dashed style, by making the "on" and "off" * parts respect the original ratio. */ void _cairo_stroke_style_dash_approximate (const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, double tolerance, double *dash_offset, double *dashes, unsigned int *num_dashes) { double coverage, scale, offset; cairo_bool_t on = TRUE; unsigned int i = 0; coverage = _cairo_stroke_style_dash_stroked (style) / _cairo_stroke_style_dash_period (style); coverage = MIN (coverage, 1.0); scale = tolerance / _cairo_matrix_transformed_circle_major_axis (ctm, 1.0); /* We stop searching for a starting point as soon as the * offset reaches zero. Otherwise when an initial dash * segment shrinks to zero it will be skipped over. */ offset = style->dash_offset; while (offset > 0.0 && offset >= style->dash[i]) { offset -= style->dash[i]; on = !on; if (++i == style->num_dashes) i = 0; } *num_dashes = 2; /* * We want to create a new dash pattern with the same relative coverage, * but composed of just 2 elements with total length equal to scale. * Based on the formula in _cairo_stroke_style_dash_stroked: * scale * coverage = dashes[0] + cap_scale * MIN (dashes[1], line_width) * = MIN (dashes[0] + cap_scale * (scale - dashes[0]), * dashes[0] + cap_scale * line_width) = * = MIN (dashes[0] * (1 - cap_scale) + cap_scale * scale, * dashes[0] + cap_scale * line_width) * * Solving both cases we get: * dashes[0] = scale * (coverage - cap_scale) / (1 - cap_scale) * when scale - dashes[0] <= line_width * dashes[0] = scale * coverage - cap_scale * line_width * when scale - dashes[0] > line_width. * * Comparing the two cases we get: * second > first * second > scale * (coverage - cap_scale) / (1 - cap_scale) * second - cap_scale * second - scale * coverage + scale * cap_scale > 0 * (scale * coverage - cap_scale * line_width) - cap_scale * second - scale * coverage + scale * cap_scale > 0 * - line_width - second + scale > 0 * scale - second > line_width * which is the condition for the second solution to be the valid one. * So when second > first, the second solution is the correct one (i.e. * the solution is always MAX (first, second). */ printf("cairostroke-style.c part 2 clear"); switch (style->line_cap) { default: ASSERT_NOT_REACHED; dashes[0] = 0.0; break; //TODO DONE add LINE_CAP_TRIANGULAR case CAIRO_LINE_CAP_BUTT: /* Simplified formula (substituting 0 for cap_scale): */ dashes[0] = scale * coverage; break; case CAIRO_LINE_CAP_ROUND: dashes[0] = MAX(scale * (coverage - ROUND_MINSQ_APPROXIMATION) / (1.0 - ROUND_MINSQ_APPROXIMATION), scale * coverage - ROUND_MINSQ_APPROXIMATION * style->line_width); break; case CAIRO_LINE_CAP_TRIANGULAR: dashes[0] = MAX(scale * (coverage - 0.5) / (1.0 - 0.5), scale * coverage - 0.5 * style->line_width); break; case CAIRO_LINE_CAP_SQUARE: /* * Special attention is needed to handle the case cap_scale == 1 (since the first solution * is either indeterminate or -inf in this case). Since dash lengths are always >=0, using * 0 as first solution always leads to the correct solution. */ dashes[0] = MAX(0.0, scale * coverage - style->line_width); break; } dashes[1] = scale - dashes[0]; *dash_offset = on ? 0.0 : dashes[0]; }