Skip to content

Commit

Permalink
Move forward diff routine out, scaling calcs, basic tests, simple cli…
Browse files Browse the repository at this point in the history
…pping
  • Loading branch information
dpt committed Feb 13, 2024
1 parent 2bcf232 commit 4fa6ea9
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 82 deletions.
8 changes: 8 additions & 0 deletions include/framebuf/curve.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,12 @@ point_t curve_bezier_point_on_quintic_r(point_t p0,
point_t p5,
fix16_t t);

// uses forward differencing (float version)
void curve_bezier_cubic_f(point_t p0,
point_t p1,
point_t p2,
point_t p3,
int nsteps,
point_t *points);

#endif /* DPTLIB_CURVE_H */
120 changes: 116 additions & 4 deletions libraries/framebuf/curve/curve.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,26 @@ point_t curve_point_on_line(point_t p0, point_t p1, fix16_t t)
return c;
}

#define SCALE (16)

static point_t scale_up(point_t p)
{
point_t q;

q.x = p.x * SCALE;
q.y = p.y * SCALE;
return q;
}

static point_t scale_down(point_t p)
{
point_t q;

q.x = p.x / SCALE;
q.y = p.y / SCALE;
return q;
}

point_t curve_bezier_point_on_quad(point_t p0,
point_t p1,
point_t p2,
Expand All @@ -28,12 +48,16 @@ point_t curve_bezier_point_on_quad(point_t p0,
point_t a, b;
point_t ab;

p0 = scale_up(p0);
p1 = scale_up(p1);
p2 = scale_up(p2);

a = curve_point_on_line(p0, p1, t);
b = curve_point_on_line(p1, p2, t);

ab = curve_point_on_line(a, b, t);

return ab;
return scale_down(ab);
}

point_t curve_bezier_point_on_cubic(point_t p0,
Expand All @@ -46,6 +70,11 @@ point_t curve_bezier_point_on_cubic(point_t p0,
point_t ab, bc;
point_t abc;

p0 = scale_up(p0);
p1 = scale_up(p1);
p2 = scale_up(p2);
p3 = scale_up(p3);

a = curve_point_on_line(p0, p1, t);
b = curve_point_on_line(p1, p2, t);
c = curve_point_on_line(p2, p3, t);
Expand All @@ -55,7 +84,7 @@ point_t curve_bezier_point_on_cubic(point_t p0,

abc = curve_point_on_line(ab, bc, t);

return abc;
return scale_down(abc);
}

point_t curve_bezier_point_on_quartic(point_t p0,
Expand All @@ -70,6 +99,12 @@ point_t curve_bezier_point_on_quartic(point_t p0,
point_t abc, bcd;
point_t abcd;

p0 = scale_up(p0);
p1 = scale_up(p1);
p2 = scale_up(p2);
p3 = scale_up(p3);
p4 = scale_up(p4);

a = curve_point_on_line(p0, p1, t);
b = curve_point_on_line(p1, p2, t);
c = curve_point_on_line(p2, p3, t);
Expand All @@ -84,7 +119,7 @@ point_t curve_bezier_point_on_quartic(point_t p0,

abcd = curve_point_on_line(abc, bcd, t);

return abcd;
return scale_down(abcd);
}

point_t curve_bezier_point_on_quintic(point_t p0,
Expand All @@ -101,6 +136,13 @@ point_t curve_bezier_point_on_quintic(point_t p0,
point_t abcd, bcde;
point_t abcde;

p0 = scale_up(p0);
p1 = scale_up(p1);
p2 = scale_up(p2);
p3 = scale_up(p3);
p4 = scale_up(p4);
p5 = scale_up(p5);

a = curve_point_on_line(p0, p1, t);
b = curve_point_on_line(p1, p2, t);
c = curve_point_on_line(p2, p3, t);
Expand All @@ -121,7 +163,7 @@ point_t curve_bezier_point_on_quintic(point_t p0,

abcde = curve_point_on_line(abcd, bcde, t);

return abcde;
return scale_down(abcde);
}

/* ----------------------------------------------------------------------- */
Expand Down Expand Up @@ -179,3 +221,73 @@ point_t curve_bezier_point_on_quintic_r(point_t p0,

return abcde;
}

/* ----------------------------------------------------------------------- */

void curve_bezier_cubic_f(point_t p0,
point_t p1,
point_t p2,
point_t p3,
int nsteps,
point_t *points)
{
float cx, cy;
float bx, by;
float ax, ay;
float h, hh, hhh;
float d1x, d1y;
float d2x, d2y;
float d3x, d3y;
float curx, cury;
int i;
point_t *point;

cx = 3.0f * (p1.x - p0.x);
cy = 3.0f * (p1.y - p0.y);

bx = 3.0f * (p2.x - p1.x) - cx;
by = 3.0f * (p2.y - p1.y) - cy;

ax = p3.x - p0.x - cx - bx;
ay = p3.y - p0.y - cy - by;

h = 1.0f / nsteps;
hh = h * h;
hhh = hh * h;

/* first difference */
d1x = ax * hhh + bx * hh + cx * h;
d1y = ay * hhh + by * hh + cy * h;

/* second difference */
d2x = 6.0f * ax * hhh + 2.0f * bx * hh;
d2y = 6.0f * ay * hhh + 2.0f * by * hh;

/* third difference */
d3x = 6.0f * ax * hhh;
d3y = 6.0f * ay * hhh;

point = &points[0];

curx = p0.x;
cury = p0.y;

for (i = 0; ; i++)
{
point->x = curx;
point->y = cury;
point++;

if (i == nsteps)
break;

curx += d1x;
cury += d1y;

d1x += d2x;
d1y += d2y;

d2x += d3x;
d2y += d3y;
}
}
106 changes: 43 additions & 63 deletions libraries/framebuf/curve/test/curve-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,36 @@ curveteststate_t;

/* ----------------------------------------------------------------------- */

static result_t curve_basic_test(curveteststate_t *state)
{
point_t a = { 0, 0 };
point_t b = { 100, 100 };

point_t c = curve_point_on_line(a, b, 0);
assert(c.x == a.x);
assert(c.y == a.y);

point_t d = curve_point_on_line(a, b, 65536);
assert(d.x == b.x);
assert(d.y == b.y);

point_t e = curve_point_on_line(a, b, 65536 / 2);
assert(e.x == 50);
assert(e.y == 50);

point_t f = curve_point_on_line(a, b, 65536 * 1 / 3);
assert(f.x == 33);
assert(f.y == 33);

point_t g = curve_point_on_line(a, b, 65536 * 2 / 3);
assert(g.x == 66);
assert(g.y == 66);

return result_TEST_PASSED;
}

/* ----------------------------------------------------------------------- */

static point_t jitter_on(point_t p)
{
point_t q;
Expand All @@ -262,62 +292,6 @@ static point_t jitter_off(point_t p)

/* ----------------------------------------------------------------------- */

void calcBezier(point_t p1, point_t p2, point_t p3, point_t p4,
int nsteps, point_t *points)
{
float cx = 3 * (p2.x - p1.x);
float cy = 3 * (p2.y - p1.y);

float bx = 3 * (p3.x - p2.x) - cx;
float by = 3 * (p3.y - p2.y) - cy;

float ax = p4.x - p1.x - cx - bx;
float ay = p4.y - p1.y - cy - by;

float h = 1.0f / nsteps;
float hh = h * h;
float hhh = hh * h;

// first difference
float d1x = ax * hhh + bx * hh + cx * h;
float d1y = ay * hhh + by * hh + cy * h;

// second
float d2x = 6 * ax * hhh + 2 * bx * hh;
float d2y = 6 * ay * hhh + 2 * by * hh;

// third
float d3x = 6 * ax * hhh;
float d3y = 6 * ay * hhh;

float currentX = p1.x;
float currentY = p1.y;

points[0].x = currentX;
points[0].y = currentY;

// skip first and last points
for (int i = 1; i < nsteps; i++)
{
currentX += d1x;
currentY += d1y;

d1x += d2x;
d1y += d2y;

d2x += d3x;
d2y += d3y;

points[i].x = currentX;
points[i].y = currentY;
}

points[nsteps].x = p4.x;
points[nsteps].y = p4.y;
}

/* ----------------------------------------------------------------------- */

static void setup_all_curves(curveteststate_t *state)
{
int cpi;
Expand Down Expand Up @@ -418,25 +392,30 @@ static void calc_all_curves(curveteststate_t *state)
{
int set;
int o;
int np;
int i;
int t;

for (set = 0; set < NELEMS(curves); set++)
{
o = curves[set].offset;
np = curves[set].npoints;

if (curves[set].kind == FwdDiffCubic)
{
calcBezier(state->jitterfn(state->control_points[o + 0]),
state->jitterfn(state->control_points[o + 1]),
state->jitterfn(state->control_points[o + 2]),
state->jitterfn(state->control_points[o + 3]),
state->nsegments,
&state->draw_points[0]);
curve_bezier_cubic_f(state->jitterfn(state->control_points[o + 0]),
state->jitterfn(state->control_points[o + 1]),
state->jitterfn(state->control_points[o + 2]),
state->jitterfn(state->control_points[o + 3]),
state->nsegments,
&state->draw_points[0]);
}
else
{
for (i = 0; i < state->nsegments + 1; i++)
state->draw_points[0] = state->jitterfn(state->control_points[o]);
state->draw_points[state->nsegments] = state->jitterfn(state->control_points[o + np - 1]);

for (i = 1; i < state->nsegments; i++)
{
t = 65536 * i / state->nsegments;

Expand Down Expand Up @@ -795,6 +774,7 @@ result_t curve_test_one_format(const char *resources,

static const curvetestfn_t tests[] =
{
curve_basic_test,
curve_interactive_test
};

Expand Down

0 comments on commit 4fa6ea9

Please sign in to comment.