Beispiel #1
0
real_coordinate_type
evaluate_spline (spline_type s, real t)
{
  spline_type V[4];    /* We need degree+1 splines, but assert degree <= 3.  */
  unsigned i, j;
  real one_minus_t = 1.0 - t;
  polynomial_degree degree = SPLINE_DEGREE (s);

  for (i = 0; i <= degree; i++)
    V[0].v[i] = s.v[i];

  for (j = 1; j <= degree; j++)
    for (i = 0; i <= degree - j; i++)
      {
#if defined (__GNUC__)
        real_coordinate_type t1 = Pmult_scalar (V[j - 1].v[i], one_minus_t);
        real_coordinate_type t2 = Pmult_scalar (V[j - 1].v[i + 1], t);
        V[j].v[i] = Padd (t1, t2);
#else
	/* HB: the above is really nice, but is there any other compiler
	 * supporting this ??
	 */
        real_coordinate_type t1;
        real_coordinate_type t2;
        t1.x = V[j - 1].v[i].x * one_minus_t;
        t1.y = V[j - 1].v[i].y * one_minus_t;
        t2.x = V[j - 1].v[i + 1].x * t;
        t2.y = V[j - 1].v[i + 1].y * t;
        V[j].v[i].x = t1.x + t2.x;
        V[j].v[i].y = t1.y + t2.y;
#endif
      }

  return V[degree].v[0];
}
Beispiel #2
0
static void
digitize_spline (spline_type s)
{
    coordinate_type start = real_cartesian_to_offset_x (START_POINT (s)),
                    control1 = real_cartesian_to_offset_x (CONTROL1 (s)),
                    control2 = real_cartesian_to_offset_x (CONTROL2 (s)),
                    end = real_cartesian_to_offset_x (END_POINT (s));

    /* These a_i are the coefficients of the polynomial
       p(t) = a_3 t^3 + a_2 t^2 + a_1 t + a_0,
       computed by expanding the Bernshte\u in polynomial
       z(t) = (1 - t)^3z_1 + 3(1 - t)^2tz_2 + 3(1 - t)t^2z_3 + t^3z_4,
       where z_1 is the starting point of the spline, z_2 and z_3 the
       control points, and z_4 the ending point.  We have two such
       polynomials p(t), one for the x-coordinate, one for the
       y-coordinate.  So everything here is done with points and vectors,
       instead of just numbers.

       a_0 = x_0
       a_1 = 3(x_1 - x_0)
       a_2 = 3(x_0 + x_2 - 2x_1)
       a_3 = x_3 - x_0 + 3(x_1 - x_2)  */

    coordinate_type /* a0 = start, */
    a1 = IPmult_scalar (IPsubtractP (control1, start), 3),
    a2 = IPmult_scalar (IPsubtractP (IPadd (start, control2),
                                     IPmult_scalar (control1, 2)),
                        3),
         a3 = IPadd (IPsubtractP (end, start),
                     IPmult_scalar (IPsubtractP (control1, control2), 3));

    /* The step size.  We want to use the length of the bounding rectangle
       to compute this, instead of the distance between the starting point
       and the ending point, since the latter will be zero if the spline
       is cyclic.  */
    real factor = int_distance (control1, start)
                  + int_distance (control2, control1)
                  + int_distance (end, control2)
                  + int_distance (start, end),
                  /* Avoid division by zero, in pathological cases.  (We will just
                     produce one point.  */
                  delta = 1.0 / MAX (factor, 1),
                  delta_squared = delta * delta,
                  delta_cubed = delta_squared * delta;

    /* The current position.  */
    coordinate_type p = start,
                    previous_p = { start.x - 1, 0 };
    /* The real current position.  */
    real_coordinate_type real_p = int_to_real_coord (p);

    /* The first three forward differences evaluated at t = 0.  */
    vector_type d = make_vector (Padd (IPmult_real (a3, delta_cubed),
                                       Padd (IPmult_real (a2, delta_squared),
                                               IPmult_real (a1, delta)))),
                    d2 = make_vector (Padd (IPmult_real (a3, 6 * delta_cubed),
                                            IPmult_real (a2, 2 * delta_squared))),
                         d3 = make_vector (IPmult_real (a3, 6 * delta_cubed));

    /* Where we will collect the points to output.  */
    unsigned point_count = 0;
    XPoint point_list[(unsigned) (1.0 / delta) + 1];

    real t;

    for (t = 0.0; t <= 1.0; t += delta)
    {
        if (!IPequal (p, previous_p))
        {
            point_list[point_count].x = p.x;
            point_list[point_count].y = p.y;
            point_count++;
            previous_p = p;
        }

        /* We must keep track of the current position in unrounded
           coordinates, so the calculations do not lose precision.  */
        real_p = Padd_vector (real_p, d);
        p.x = ROUND (real_p.x);
        p.y = ROUND (real_p.y);
        d = Vadd (d, d2);
        d2 = Vadd (d2, d3);
        /* d3 is constant with respect to t.  */
    }

#if 0
    /* GDB under system V doesn't grok XPoint, so here's a way to print
       out the points we find.  */
    {
        unsigned i;
        for (i = 0; i < point_count; i++)
            printf ("(%d,%d)", point_list[i].x, point_list[i].y);
        puts ("");
    }
#endif

    XDrawPoints (display, pixmap, gc, point_list, point_count,
                 CoordModeOrigin);
}