예제 #1
0
파일: bezier.c 프로젝트: EliteTK/Bezier
static struct point lerp_points(struct point points[2], double factor)
{
	struct point delta;

	delta.x = points[1].x - points[0].x;
	delta.y = points[1].y - points[0].y;

	delta.x *= factor;
	delta.y *= factor;

	return (struct point){.x = points[0].x + delta.x,
			      .y = points[0].y + delta.y};
}

static struct point bezier_point(struct point *points, int count, double factor)
{
	struct point retval = points[0];

	if (count < 2)
		return retval;

	if (count == 2)
		return lerp_points(points, factor);

	struct point newpoints[count - 1];

	for (int i = 0; i < count - 1; i++)
		newpoints[i] = lerp_points(points + i, factor);

	return bezier_point(newpoints, count - 1, factor);
}

void plot_bezier(struct point *points, int count, colour_t *buff,
		 uint32_t width, uint32_t height, colour_t colour)
{
	struct point last = points[0];

	for (double factor = 0; factor < 1; factor += step) {
		struct point next = bezier_point(points, count, factor);
		uint32_t x = next.x, y = next.y;

		if (x > width)
			x = width;

		if (y > height)
			y = height;

		buff[x + width * y] = colour;
	}
}
예제 #2
0
static void vd_flatten(double p0x, double p0y, double p1x, double p1y, double p2x, double p2y, double p3x, double p3y)
{
#ifdef DEBUG
    double flat = 0.5;
    double d2x0 = (p0x - 2 * p1x + p2x), d2y0 = (p0y - 2 * p1y + p2y);
    double d2x1 = (p1x - 2 * p2x + p3x), d2y1 = (p1y - 2 * p2y + p3y);
    double d2norm0 = hypot(d2x0, d2y0);
    double d2norm1 = hypot(d2x1, d2y1);
    double D = max(d2norm0, d2norm1); /* This is half of maximum norm of 2nd derivative of the curve by parameter t. */
    int NN = (int)ceil(sqrt(D * 3 / 4 / flat)); /* Number of output segments. */
    int i;
    int N = max(NN, 1); /* safety (if the curve degenerates to line) */
    double e = 0.5 / N;

    for (i = 0; i < N; i++) {
        double t = (double)i / N + e;
        double px = bezier_point(p0x, p1x, p2x, p3x, t);
        double py = bezier_point(p0y, p1y, p2y, p3y, t);

        vd_lineto(px, py);
    }
    vd_lineto(p3x, p3y);
#endif
}
예제 #3
0
파일: actions.c 프로젝트: chrismdp/texplay
void
bezier_do_action(VALUE points, texture_info * tex, VALUE hash_arg, texplay_sync sync_mode,
                 bool primary, action_struct * payload)
{
    float u = 0.0;
    action_struct cur;
    float x1, y1, x2, y2;
    int first_x, first_y;
    int format;
    int num_point_pairs;
    bool closed = false;
    VALUE offset_val;
    int draw_offset_x, draw_offset_y;

    /* defaults to 200 (1 / 0.005) samples per curve */
    float step_size = 0.005;
    
    draw_prologue(&cur, tex, XMAX_OOB, YMAX_OOB, XMIN_OOB, YMIN_OOB, &hash_arg, sync_mode, primary, &payload);

    /* calculate offset */
    offset_val = get_image_local(tex->image, DRAW_OFFSET);

    draw_offset_x = NUM2INT(get_from_array(offset_val, 0));
    draw_offset_y = NUM2INT(get_from_array(offset_val, 1));

    if(is_a_hash(hash_arg)) {

        /* if the polyline is 'closed' make the last point the first */
        if(RTEST(get_from_hash(hash_arg, "closed")) || RTEST(get_from_hash(hash_arg, "close"))) {

            /* so that our additional point is not persistent */
            points = rb_obj_dup(points);
            closed = true;
        }
        
        /* number of points to sample */
        if(RTEST(get_from_hash(hash_arg, "sample_size"))) {
            VALUE c = get_from_hash(hash_arg, "sample_size");
            Check_Type(c, T_FIXNUM);
            step_size = 1.0 / (float)FIX2INT(c);
        }
    }

    if(is_a_point(get_from_array(points, 0))) {
        format = POINT_FORMAT;

        if(closed)
            rb_ary_push(points, get_from_array(points, 0));
        
        num_point_pairs = RARRAY_LEN(points);
    }
    else {
        format = SIMPLE_FORMAT;

        /* ensure points are given in pairs */
        if(RARRAY_LEN(points) % 2)
            rb_raise(rb_eArgError, "bezier needs an even number of points. got %d\n", (int)RARRAY_LEN(points));

        if(closed) {
            rb_ary_push(points, get_from_array(points, 0));
            rb_ary_push(points, get_from_array(points, 1));
        }
        
        num_point_pairs = RARRAY_LEN(points) / 2;
    }

    if(num_point_pairs > 17)
        rb_raise(rb_eArgError, "too many points for bezier curve. 17 points is current maximum. got %d\n",
                 num_point_pairs);

    /* get the first point */
    bezier_point(points, 0, &x1, &y1, num_point_pairs, format, draw_offset_x, draw_offset_y);

    /* save it so we can link up with last point properly if the curve is 'closed' */
    first_x = x1;
    first_y = y1;

    while(u <= 1) {
        bezier_point(points, u, &x2, &y2, num_point_pairs, format, draw_offset_x, draw_offset_y);
 
        line_do_action(x1, y1, x2, y2, tex, hash_arg, no_sync, false, payload);

        /* update drawing rectangle */
        update_bounds(payload, x1, y1, x2, y2);

        x1 = x2;
        y1 = y2;

        u += step_size;
    }

    /* sometimes beziers dont close properly, so we'll ensure it's closed */
    if(closed)
        line_do_action(x2, y2, first_x, first_y, tex, hash_arg, no_sync, false, payload);

    draw_epilogue(&cur, tex, primary);
}