svg-path.cpp revision 6b15695578f07a3f72c4c9475c1a261a3021472a
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering svg-path.c: Parse SVG path element data into bezier path.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Copyright (C) 2000 Eazel, Inc.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Copyright (C) 2000 Lauris Kaplinski
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Copyright (C) 2001 Ximian, Inc.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering This program is free software; you can redistribute it and/or
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering modify it under the terms of the GNU General Public License as
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering published by the Free Software Foundation; either version 2 of the
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering License, or (at your option) any later version.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering This program is distributed in the hope that it will be useful,
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering but WITHOUT ANY WARRANTY; without even the implied warranty of
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering General Public License for more details.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering You should have received a copy of the GNU General Public
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering License along with this program; if not, write to the
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Free Software Foundation, Inc., 59 Temple Place - Suite 330,
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Boston, MA 02111-1307, USA.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Raph Levien <raph@artofcode.com>
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Lauris Kaplinski <lauris@ximian.com>
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering/* This module parses an SVG path element into an RsvgBpathDef.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering At present, there is no support for <marker> or any other contextual
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering information from the SVG file. The API will need to change rather
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering significantly to support these.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Reference: SVG working draft 3 March 2000, section 8.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#endif /* M_PI */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering/* We are lazy ;-) (Lauris) */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#define rsvg_bpath_def_new gnome_canvas_bpath_def_new
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#define rsvg_bpath_def_moveto gnome_canvas_bpath_def_moveto
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#define rsvg_bpath_def_lineto gnome_canvas_bpath_def_lineto
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#define rsvg_bpath_def_curveto gnome_canvas_bpath_def_curveto
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering#define rsvg_bpath_def_closepath gnome_canvas_bpath_def_closepath
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering double rpx, rpy; /* reflection point (for 's' and 't' commands) */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering double spx, spy; /* beginning of current subpath point */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering char cmd; /* current command (lowercase) */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering gboolean rel; /* true if relative coords */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering double params[7]; /* parameters that have been parsed */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poetteringstatic void rsvg_path_arc_segment(RSVGParsePathCtx *ctx,
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering double rx, double ry, double x_axis_rotation)
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering sin_th = sin (x_axis_rotation * (M_PI / 180.0));
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering cos_th = cos (x_axis_rotation * (M_PI / 180.0));
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* inverse transform compared with rsvg_path_arc */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering a00 * x1 + a01 * y1, a10 * x1 + a11 * y1,
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering a00 * x2 + a01 * y2, a10 * x2 + a11 * y2,
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering a00 * x3 + a01 * y3, a10 * x3 + a11 * y3);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * rsvg_path_arc: Add an RSVG arc to the path context.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * @ctx: Path context.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * @rx: Radius in x direction (before rotation).
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * @ry: Radius in y direction (before rotation).
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * @x_axis_rotation: Rotation angle for axes.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * @large_arc_flag: 0 for arc length <= 180, 1 for arc >= 180.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * @sweep: 0 for "negative angle", 1 for "positive angle".
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * @x: New x coordinate.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * @y: New y coordinate.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poetteringstatic void rsvg_path_arc (RSVGParsePathCtx *ctx,
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering double rx, double ry, double x_axis_rotation,
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering double x, double y)
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering sin_th = sin (x_axis_rotation * (M_PI / 180.0));
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering cos_th = cos (x_axis_rotation * (M_PI / 180.0));
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering Correction of out-of-range radii as described in Appendix F.6.6:
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering 1. Ensure radii are non-zero (Done?).
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering 2. Ensure that radii are positive.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering 3. Ensure that radii are large enough.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering px = cos_th * (ctx->cpx - x) * 0.5 + sin_th * (ctx->cpy - y) * 0.5;
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering py = cos_th * (ctx->cpy - y) * 0.5 - sin_th * (ctx->cpx - x) * 0.5;
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering pl = (px * px) / (rx * rx) + (py * py) / (ry * ry);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* Proceed with computations as described in Appendix F.6.5 */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* (x0, y0) is current point in transformed coordinate space.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering (x1, y1) is new point in transformed coordinate space.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering The arc fits a unit-radius circle in this space.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering if (sweep_flag == large_arc_flag) sfactor = -sfactor;
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* (xc, yc) is center of the circle. */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering n_segs = (int) ceil (fabs (th_arc / (M_PI * 0.5 + 0.001)));
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering for (i = 0; i < n_segs; i++) {
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering/* supply defaults for missing parameters, assuming relative coordinates
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering are to be interpreted as x,y */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poetteringstatic void rsvg_parse_path_default_xy(RSVGParsePathCtx *ctx, int n_params)
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering for (i = ctx->param; i < n_params; i++) {
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering else if (i == 1)
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering else if (i == 0)
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* we shouldn't get here (usually ctx->param > 0 as
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering precondition) */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering for (i = ctx->param; i < n_params; i++) {
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poetteringstatic void rsvg_parse_path_do_cmd(RSVGParsePathCtx *ctx, gboolean final)
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering ctx->cpx = ctx->rpx = ctx->spx = ctx->params[0];
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering ctx->cpy = ctx->rpy = ctx->spy = ctx->params[1];
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering g_print ("'c' curveto %g,%g %g,%g, %g,%g\n",
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* smooth curveto */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering g_print ("'s' curveto %g,%g %g,%g, %g,%g\n",
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* horizontal lineto */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* vertical lineto */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* quadratic bezier curveto */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* non-normative reference:
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering http://www.icce.rug.nl/erikjan/bluefuzz/beziers/beziers/beziers.html
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* raise quadratic bezier to cubic */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering x1 = (ctx->cpx + 2 * ctx->params[0]) * (1.0 / 3.0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering y1 = (ctx->cpy + 2 * ctx->params[1]) * (1.0 / 3.0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering x2 = (x3 + 2 * ctx->params[0]) * (1.0 / 3.0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering y2 = (y3 + 2 * ctx->params[1]) * (1.0 / 3.0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering g_print("'q' curveto %g,%g %g,%g, %g,%g\n",
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* Truetype quadratic bezier curveto */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering double xc, yc; /* quadratic control point */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* generate a quadratic bezier with control point = xc, yc */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering g_print ("'t' curveto %g,%g %g,%g, %g,%g\n",
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* raise quadratic bezier to cubic */
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering x1 = (ctx->cpx + 2 * ctx->params[0]) * (1.0 / 3.0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering y1 = (ctx->cpy + 2 * ctx->params[1]) * (1.0 / 3.0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering x2 = (x3 + 2 * ctx->params[0]) * (1.0 / 3.0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering y2 = (y3 + 2 * ctx->params[1]) * (1.0 / 3.0);
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering g_print ("'t' curveto %g,%g %g,%g, %g,%g\n",
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering ctx->params[0], ctx->params[1], ctx->params[2],
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering (int) ctx->params[3], (int) ctx->params[4],
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poetteringstatic void rsvg_parse_path_data(RSVGParsePathCtx *ctx, const char *data)
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering /* fixme: Do better error processing: e.g. at least stop parsing as soon as we find an error.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * At some point we'll need to do all of
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering * http://www.w3.org/TR/SVG11/implnote.html#ErrorProcessing.
4f5dd3943bef8a04be7e3b838b822bb9a7ad6cb3Lennart Poettering for (i = 0; ; i++)
else if (in_frac)
exp = 0;
if (!in_num)
exp = 0;
val = 0;
exp = 0;
else if (in_num)
val = 0;
val = 0;
exp = 0;
return bpath;
bool closed=false;
case NR_LINETO:
case NR_CURVETO:
case NR_MOVETO_OPEN:
case NR_MOVETO:
if (closed) {
if (closed) {
// std::string s = os.str();
// gchar *ret = g_strdup(s.c_str());