Reputation: 2527
I've written a function that calculates the points for a b-spline curve, drawing the curve on the screen as the points are generated using the built in setinterval()
function. The problem is that when these points are drawn to the screen, there is merely a portion or small segment of the curve that is visible moving along the interpolated curve, but the entire curve doesn't persist as the curve is plotted. In addition to this, the curve will trail off the screen once it reaches a certain point. The code appears to be designed in such a way that the function will end (i.e. the interval will be cleared) once the value of t reaches 1, but for some reason, the function continues to be called, causing the curve to continue being animated off screen.
Conversely, I have another function that simply uses a for loop to draw the curve with the same points, but with this function a small curve is drawn once, clearly fitting on the screen. Below is the code for both functions:
//function that draws the spline one time
function bspline(context, points) {
context.beginPath();
for (var t = 0; t < 1; t += 0.1) {
var ax = (-points[0].x + 3 * points[1].x - 3 * points[2].x + points[3].x) / 6;
var ay = (-points[0].y + 3 * points[1].y - 3 * points[2].y + points[3].y) / 6;
var bx = (-points[0].x - 2 * points[1].x + points[2].x) / 2;
var by = (-points[0].y - 2 * points[1].y + points[2].y) / 2;
var cx = (-points[0].x + points[2].x) / 2;
var cy = (-points[0].y + points[2].y) / 2;
var dx = (points[0].x + 4 * points[1].x + points[2].x) / 6;
var dy = (points[0].y + 4 * points[1].y + points[2].y) / 6;
context.moveTo(
ax*Math.pow(t,3) + bx*Math.pow(t,2) + cx*t + dx,
ay*Math.pow(t,3) + by*Math.pow(t,2) + cy*t + dy
);
context.lineTo(
ax*Math.pow(t+0.1, 3) + bx*Math.pow(t+0.1, 2) + cx*(t+0.1) + dx,
ay*Math.pow(t+0.1,3) + by*Math.pow(t+0.1,2) + cy*(t+0.1) + dy
);
//m.translate(ax * Math.pow(t + 0.1, 3) + bx * Math.pow(t + 0.1, 2) + cx * (t + 0.1) + dx, ay * Math.pow(t + 0.1, 3) + by * Math.pow(t + 0.1, 2) + cy * (t + 0.1) + dy,0);
}
context.stroke();
}
var interval;
//sets the interval for the spline to be animated over
function drawSpline(context, points, newpts) {
interval = setInterval(splineAnim(context, points, newpts), 1600.67);
console.log("interval set");
}
var t = 0;
//determines and draws the points of the spline
function splineAnim(context, points, newpts) {
// Draw curve segment
var ax = (-points[0].x + 3 * points[1].x - 3 * points[2].x + points[3].x) / 6;
var ay = (-points[0].y + 3 * points[1].y - 3 * points[2].y + points[3].y) / 6;
var bx = (-points[0].x - 2 * points[1].x + points[2].x) / 2;
var by = (-points[0].y - 2 * points[1].y + points[2].y) / 2;
var cx = (-points[0].x + points[2].x) / 2;
var cy = (-points[0].y + points[2].y) / 2;
var dx = (points[0].x + 4 * points[1].x + points[2].x) / 6;
var dy = (points[0].y + 4 * points[1].y + points[2].y) / 6;
context.beginPath();
context.moveTo(
ax * Math.pow(t, 3) + bx * Math.pow(t, 2) + cx * t + dx,
ay * Math.pow(t, 3) + by * Math.pow(t, 2) + cy * t + dy
);
var ax2 = ax * Math.pow(t + 0.1, 3) + bx * Math.pow(t + 0.1, 2) + cx * (t + 0.1) + dx;
var ay2 = ay * Math.pow(t + 0.1, 3) + by * Math.pow(t + 0.1, 2) + cy * (t + 0.1) + dy;
context.lineTo(
ax * Math.pow(t + 0.1, 3) + bx * Math.pow(t + 0.1, 2) + cx * (t + 0.1) + dx,
ay * Math.pow(t + 0.1, 3) + by * Math.pow(t + 0.1, 2) + cy * (t + 0.1) + dy
);
context.stroke();
//m.translate(ax * Math.pow(t + 0.1, 3) + bx * Math.pow(t + 0.1, 2) + cx * (t + 0.1) + dx, ay * Math.pow(t + 0.1, 3) + by * Math.pow(t + 0.1, 2) + cy * (t + 0.1) + dy, 0);
//console.log("ax2: " + ax2 + ", ay2: " + ay2);
var arr = [ax2, ay2];
newpts.push(arr);
t += 0.02;
//Reached end of curve
if (t > 1) clearInterval(interval);
}
Upvotes: 0
Views: 149
Reputation: 51845
not a JAVAscript coder but in many languages 3
means integer
so try to add .0
to all floating constants... My bet is that your compiler/interpreter detect integer and truncate the result changing subresults so the curve does not match and sometimes it could look like is above 1.0
range even if it is not.
Also better for
stop for this is:
for (t=0.0,e=1;e;t=0.1)
{
if (t>=1.0) { e=0; t=1.0; }
// here do your stuff
}
This way you can use any step not just exact division of range. Also this take care of not exact number representation of step and cumulative round off error.
Just few hints
pow
for small integer exponents is a huge overkill and performance killerso when put all together (C++)
int e;
float t,tt,ttt,dt;
vec2 a0,a1,a2,a3; // coefficients 2D vectors
vec2 p0,p1,p2,p3; // your input control points 2D vectors
vec2 p; // temp point
a0= ( p0);
a1= (3.0*p1)-(3.0*p0);
a2= (3.0*p2)-(6.0*p1)+(3.0*p0);
a3=( p3)-(3.0*p2)+(3.0*p1)-( p0);
t=0.0; dt=0.1; tt=t*t; ttt=tt*t;
p=a0+(a1*t)+(a2*tt)+(a3*ttt);
MoveTo(p.x,p.y);
for (t+=dt,e=1;e;t=dt)
{
if (t>=1.0) { e=0; t=1.0; }
// here do your stuff
tt=t*t;
ttt=tt*t;
p=a0+(a1*t)+(a2*tt)+(a3*ttt);
LineTo(p.x,p.y);
}
vec2
is just 2D vector containing x,y
membersUpvotes: 1