Use bezier curves to draw cables.

master
q3k 2013-02-25 18:26:09 +01:00
parent 16d07323ed
commit c7024336d1
1 changed files with 80 additions and 41 deletions

121
main.js
View File

@ -15,6 +15,7 @@ var Verlet = function(Width, Height)
this.AddConstraint = function(Constraint)
{
this.Constraints.push(Constraint);
return Constraint;
}
this.Update = function(TimeDelta)
@ -139,28 +140,75 @@ var Constraint = function(Mass1, Mass2)
}
}
var Cable = function(Verlet, X1, Y1, X2, Y2, Steps)
{
Steps = Steps || 10;
var StepX = (X2 - X1) / Steps;
var StepY = (Y2 - Y1) / Steps;
this.Masses = [];
var LastMass = v.AddMass(new Mass(X1, Y1, 0.5));
this.Masses.push(LastMass);
LastMass.Active = false;
for (var i = 1; i <= Steps; i++)
{
var NewMass = v.AddMass(new Mass(X1 + StepX * i, Y1 + StepY * i, 1));
this.Masses.push(NewMass);
v.AddConstraint(new Constraint(LastMass, NewMass));
LastMass = NewMass;
}
this.BinomialCache = {}
this.FastBinomial = function(n, k)
{
var key = n + ".." + k;
if (key in this.BinomialCache)
return this.BinomialCache[key];
function Factorial(num)
{
var rval=1;
for (var i = 2; i <= num; i++)
rval = rval * i;
return rval;
}
return (Factorial(n) / (Factorial(k) * Factorial(n - k)));
}
this.Bezier = function(t)
{
var Points = this.Masses.length - 1;
var ValueX = 0;
var ValueY = 0;
for (var i = 0; i <= Points; i++)
{
var Coef = this.FastBinomial(Points, i) * Math.pow(1 -t, Points - i) * Math.pow(t, i);
ValueX += Coef * this.Masses[i].X;
ValueY += Coef * this.Masses[i].Y;
}
return {X: ValueX, Y: ValueY};
}
this.Render = function(context)
{
context.strokeStyle = '#FFFFFF';
context.beginPath();
var First = this.Bezier(0);
context.moveTo(First.X, First.Y);
for (var T = 1; T < 100; T++)
{
var t = T / 100;
var Next = this.Bezier(t);
context.lineTo(Next.X, Next.Y);
}
context.stroke();
}
}
var v = new Verlet(800, 600);
var m1 = v.AddMass(new Mass( 5, 5, 1));
var m2 = v.AddMass(new Mass(20, 5, 1));
var m3 = v.AddMass(new Mass(35, 5, 1));
var m4 = v.AddMass(new Mass(50, 5, 1));
var m5 = v.AddMass(new Mass(65, 5, 1));
var m6 = v.AddMass(new Mass(80, 5, 1));
m6.Active = false;
var cable = new Cable(v, 5, 5, 500, 5);
var t1 = v.AddMass(new Mass(20, 15, 2));
var t2 = v.AddMass(new Mass(0, 45, 2));
var t3 = v.AddMass(new Mass(40, 45, 2));
v.AddConstraint(new Constraint(m1, m2));
v.AddConstraint(new Constraint(m2, m3));
v.AddConstraint(new Constraint(m3, m4));
v.AddConstraint(new Constraint(m4, m5));
v.AddConstraint(new Constraint(m5, m6));
v.AddConstraint(new Constraint(t1, t2));
v.AddConstraint(new Constraint(t1, t3));
v.AddConstraint(new Constraint(t3, t2));
v.AddConstraint(new Constraint(m1, t1));
var c = document.getElementById("main");
var ctx = c.getContext('2d');
@ -177,30 +225,21 @@ setInterval(function()
v.Update(1/50);
cable.Render(ctx);
ctx.fillStyle = '#FFFFFF';
for (k in v.Masses)
{
var m = v.Masses[k];
if (typeof(m) == "function")
continue;
ctx.beginPath();
ctx.arc(m.X, m.Y, 5, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}
ctx.strokeStyle = '#FFFFFF';
for (k in v.Constraints)
{
var c = v.Constraints[k];
if (typeof(c) == "function")
continue;
var First = v.Masses[0];
var Last = v.Masses[v.Masses.length - 1];
ctx.beginPath();
ctx.arc(First.X, First.Y, 5, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(c.Mass1.X, c.Mass1.Y);
ctx.lineTo(c.Mass2.X, c.Mass2.Y);
ctx.stroke();
}
ctx.beginPath();
ctx.arc(Last.X, Last.Y, 5, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
}, 1000/50);