コード例 #1
0
ファイル: svg-path.c プロジェクト: benjohnson2001/base
/**
 * rsvg_path_arc: Add an RSVG arc to the path context.
 * @ctx: Path context.
 * @rx: Radius in x direction (before rotation).
 * @ry: Radius in y direction (before rotation).
 * @x_axis_rotation: Rotation angle for axes.
 * @large_arc_flag: 0 for arc length <= 180, 1 for arc >= 180.
 * @sweep: 0 for "negative angle", 1 for "positive angle".
 * @x: New x coordinate.
 * @y: New y coordinate.
 *
 **/
static void
rsvg_path_arc (RSVGParsePathCtx *ctx,
	      double rx, double ry, double x_axis_rotation,
	      int large_arc_flag, int sweep_flag,
	      double x, double y)
{
  double sin_th, cos_th;
  double a00, a01, a10, a11;
  double x0, y0, x1, y1, xc, yc;
  double d, sfactor, sfactor_sq;
  double th0, th1, th_arc;
  int i, n_segs;

  sin_th = sin (x_axis_rotation * (M_PI / 180.0));
  cos_th = cos (x_axis_rotation * (M_PI / 180.0));
  a00 = cos_th / rx;
  a01 = sin_th / rx;
  a10 = -sin_th / ry;
  a11 = cos_th / ry;
  x0 = a00 * ctx->cpx + a01 * ctx->cpy;
  y0 = a10 * ctx->cpx + a11 * ctx->cpy;
  x1 = a00 * x + a01 * y;
  y1 = a10 * x + a11 * y;
  /* (x0, y0) is current point in transformed coordinate space.
     (x1, y1) is new point in transformed coordinate space.

     The arc fits a unit-radius circle in this space.
  */
  d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
  sfactor_sq = 1.0 / d - 0.25;
  if (sfactor_sq < 0) sfactor_sq = 0;
  sfactor = sqrt (sfactor_sq);
  if (sweep_flag == large_arc_flag) sfactor = -sfactor;
  xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
  yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
  /* (xc, yc) is center of the circle. */

  th0 = atan2 (y0 - yc, x0 - xc);
  th1 = atan2 (y1 - yc, x1 - xc);

  th_arc = th1 - th0;
  if (th_arc < 0 && sweep_flag)
    th_arc += 2 * M_PI;
  else if (th_arc > 0 && !sweep_flag)
    th_arc -= 2 * M_PI;

  n_segs = (int) ceil (fabs (th_arc / (M_PI * 0.5 + 0.001)));

  for (i = 0; i < n_segs; i++)
    rsvg_path_arc_segment (ctx, xc, yc,
			  th0 + i * th_arc / n_segs,
			  th0 + (i + 1) * th_arc / n_segs,
			  rx, ry, x_axis_rotation);

  ctx->cpx = x;
  ctx->cpy = y;
}
コード例 #2
0
ファイル: rsvg-path.c プロジェクト: kinglulu/librsvg
/**
 * rsvg_path_arc: Add an RSVG arc to the path context.
 * @ctx: Path context.
 * @rx: Radius in x direction (before rotation).
 * @ry: Radius in y direction (before rotation).
 * @x_axis_rotation: Rotation angle for axes.
 * @large_arc_flag: 0 for arc length <= 180, 1 for arc >= 180.
 * @sweep: 0 for "negative angle", 1 for "positive angle".
 * @x: New x coordinate.
 * @y: New y coordinate.
 *
 **/
static void
rsvg_path_arc (RSVGParsePathCtx * ctx,
               double rx, double ry, double x_axis_rotation,
               int large_arc_flag, int sweep_flag, double x, double y)
{

  /* See Appendix F.6 Elliptical arc implementation notes
     http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes */

  double f, sinf, cosf;
  double x1, y1, x2, y2;
  double x1_, y1_;
  double cx_, cy_, cx, cy;
  double gamma;
  double theta1, delta_theta;
  double k1, k2, k3, k4, k5;

  int i, n_segs;

    /* Start and end of path segment */
    x1 = ctx->cpx;
    y1 = ctx->cpy;

    x2 = x;
    y2 = y;

    if(x1 == x2 && y1 == y2)
      return;

    /* X-axis */
    f = x_axis_rotation * M_PI / 180.0;
    sinf = sin(f);
    cosf = cos(f);

    /* Check the radius */
    if ((rx == 0.0) || (ry == 0.0))
      {
	rsvg_bpath_def_lineto (ctx->bpath, x, y);
        return;
      }

    if(rx < 0)rx = -rx;
    if(ry < 0)ry = -ry;

    k1 = (x1 - x2)/2;
    k2 = (y1 - y2)/2;

    x1_ = cosf * k1 + sinf * k2;
    y1_ = -sinf * k1 + cosf * k2;

    gamma = (x1_*x1_)/(rx*rx) + (y1_*y1_)/(ry*ry);
    if(gamma > 1)
      {
	rx *= sqrt(gamma);
	ry *= sqrt(gamma);
      }

    /* Compute the center */

    k1 = rx*rx*y1_*y1_ + ry*ry*x1_*x1_;
    if(k1 == 0)    
      return;

    k1 = sqrt(fabs((rx*rx*ry*ry)/k1 - 1));
    if(sweep_flag == large_arc_flag)
      k1 = -k1;

    cx_ = k1*rx*y1_/ry;
    cy_ = -k1*ry*x1_/rx;
    
    cx = cosf*cx_ - sinf*cy_ + (x1+x2)/2;
    cy = sinf*cx_ + cosf*cy_ + (y1+y2)/2;

    /* Compute start angle */

    k1 = (x1_ - cx_)/rx;
    k2 = (y1_ - cy_)/ry;
    k3 = (-x1_ - cx_)/rx;
    k4 = (-y1_ - cy_)/ry;

    k5 = sqrt(fabs(k1*k1 + k2*k2));
    if(k5 == 0)return;

    k5 = k1/k5;
    if(k5 < -1)k5 = -1;
    else if(k5 > 1)k5 = 1;
    theta1 = acos(k5);
    if(k2 < 0)theta1 = -theta1;

    /* Compute delta_theta */

    k5 = sqrt(fabs((k1*k1 + k2*k2)*(k3*k3 + k4*k4)));
    if(k5 == 0)return;

    k5 = (k1*k3 + k2*k4)/k5;
    if(k5 < -1)k5 = -1;
    else if(k5 > 1)k5 = 1;
    delta_theta = acos(k5);
    if(k1*k4 - k3*k2 < 0)delta_theta = -delta_theta;

    if(sweep_flag && delta_theta < 0)
      delta_theta += M_PI*2;
    else if(!sweep_flag && delta_theta > 0)
      delta_theta -= M_PI*2;
   
    /* Now draw the arc */

    n_segs = ceil (fabs (delta_theta / (M_PI * 0.5 + 0.001)));

    for (i = 0; i < n_segs; i++)
      rsvg_path_arc_segment (ctx, cx, cy,
			     theta1 + i * delta_theta / n_segs,
			     theta1 + (i + 1) * delta_theta / n_segs,
			     rx, ry, x_axis_rotation);

    ctx->cpx = x;
    ctx->cpy = y;
}