Parse
File Parse functions/springs.js
This tree is parsed live from the source file.
Classes
-
{{ item.name }}
- {{ key }}
Not Classes
{{ getTree() }}
Comments
{{ getTreeComments() }}
Source
const applySpringForce = function(pointA, pointB, restLength, springConstant, dampingFactor) {
// Calculate the distance between pointA and pointB
const dx = pointA.x - pointB.x;
const dy = pointA.y - pointB.y;
const distance = Math.sqrt(dx * dx + dy * dy);
// Calculate the force exerted by the spring
const forceMagnitude = (springConstant * (distance - restLength))
// Calculate the direction of the force
const fx = (dx / distance) * forceMagnitude;
const fy = (dy / distance) * forceMagnitude;
// Apply the force to pointA and pointB
pointA.vx -= fx / pointA.mass;
pointA.vy -= fy / pointA.mass;
pointB.vx += fx / pointB.mass;
pointB.vy += fy / pointB.mass;
// Apply damping to reduce oscillation
pointA.vx *= dampingFactor;
pointA.vy *= dampingFactor;
pointB.vx *= dampingFactor;
pointB.vy *= dampingFactor;
// Update positions based on velocities
pointA.x += pointA.vx;
pointA.y += pointA.vy;
pointB.x += pointB.vx;
pointB.y += pointB.vy;
}
const applySpringForceLocking = function(pointA, pointB, restLength, springConstant, dampingFactor, lockedPoints = new Set()) {
// Calculate the distance between pointA and pointB
const dx = pointA.x - pointB.x;
const dy = pointA.y - pointB.y;
const distance = Math.sqrt(dx * dx + dy * dy);
// Calculate the force exerted by the spring
const forceMagnitude = springConstant * (distance - restLength);
// Calculate the direction of the force
const fx = (dx / distance) * forceMagnitude;
const fy = (dy / distance) * forceMagnitude;
// Apply the force to pointA and pointB, only if they are not locked
if (!lockedPoints.has(pointA)) {
pointA.vx -= fx / pointA.mass;
pointA.vy -= fy / pointA.mass;
}
if (!lockedPoints.has(pointB)) {
pointB.vx += fx / pointB.mass;
pointB.vy += fy / pointB.mass;
}
// Apply damping to reduce oscillation
if (!lockedPoints.has(pointA)) {
pointA.vx *= dampingFactor;
pointA.vy *= dampingFactor;
}
if (!lockedPoints.has(pointB)) {
pointB.vx *= dampingFactor;
pointB.vy *= dampingFactor;
}
// Update positions based on velocities
if (!lockedPoints.has(pointA)) {
pointA.x += pointA.vx;
pointA.y += pointA.vy;
}
if (!lockedPoints.has(pointB)) {
pointB.x += pointB.vx;
pointB.y += pointB.vy;
}
}
const applySpringForceDistributed = function() {
return applySpringForceDistributedWithTime.apply(this, arguments)
}
const applySpringForceDistributedWithTime = function(pointA, pointB, restLength,
springConstant, dampingFactor, lockedPoints = new Set(), deltaTime = 1) {
// Calculate the distance between pointA and pointB
const dx = pointA.x - pointB.x;
const dy = pointA.y - pointB.y;
const distance = Math.sqrt(dx * dx + dy * dy);
// Calculate the force exerted by the spring
const forceMagnitude = springConstant * (distance - restLength);
// Calculate the direction of the force
const fx = ((dx / distance) * forceMagnitude);
const fy = ((dy / distance) * forceMagnitude);
let aLocked = lockedPoints.has(pointA);
let bLocked = lockedPoints.has(pointB);
let noLock = !aLocked && !bLocked;
let aSideLock = aLocked && !bLocked;
let bSideLock = !aLocked && bLocked;
// Distribute the force to non-locked points
if (noLock) {
pointA.vx -= (fx / pointA.mass) * deltaTime;
pointA.vy -= (fy / pointA.mass) * deltaTime;
pointB.vx += (fx / pointB.mass) * deltaTime;
pointB.vy += (fy / pointB.mass) * deltaTime;
} else if (aSideLock) {
pointB.vx += (fx / pointB.mass) * deltaTime;
pointB.vy += (fy / pointB.mass) * deltaTime;
} else if (bSideLock) {
pointA.vx -= (fx / pointA.mass) * deltaTime;
pointA.vy -= (fy / pointA.mass) * deltaTime;
}
// Apply damping to reduce oscillation
if (!aLocked) {
pointA.vx *= Math.pow(dampingFactor, deltaTime);
pointA.vy *= Math.pow(dampingFactor, deltaTime);
}
if (!bLocked) {
pointB.vx *= Math.pow(dampingFactor, deltaTime);
pointB.vy *= Math.pow(dampingFactor, deltaTime);
}
// Update positions based on velocities
if (!aLocked) {
pointA.x += pointA.vx * deltaTime;
pointA.y += pointA.vy * deltaTime;
}
if (!bLocked) {
pointB.x += pointB.vx * deltaTime;
pointB.y += pointB.vy * deltaTime;
}
}
class PointSpring {
constructor(point) {
this.parent = point
}
to(other, restLength, springConstant=.6, dampingFactor=.99, lockedPoints=new Set, deltaTime=1) {
return applySpringForceDistributedWithTime(this.parent, other,
restLength, springConstant, dampingFactor, lockedPoints, deltaTime);
}
}
class PointListSpring {
/* An extension to the PointList for 'springs' */
restLength = 100
springConstant = .6
dampingFactor = 0.92 // Adjust this value between 0 and 1
deltaTime = .9
constructor(pointList) {
this.parent = pointList
}
chain(rLen=this.restLength,
springConstant=this.springConstant,
damping=this.damping,
lockedPoints=this.lockedPoints,
deltaTime=this.deltaTime) {
/* Connect from tip to tip without connecting the first to the last. */
let ps = this.parent
let previous = ps[0]
for (var i = 1; i < ps.length; i++) {
let current = ps[i]
previous.spring.to(current, rLen, springConstant, damping, lockedPoints, deltaTime)
previous = current
}
}
closedChain() {
return this.loop.apply(this, arguments)
}
loop(rLen=this.restLength,
springConstant=this.springConstant,
damping=this.damping,
lockedPoints=this.lockedPoints,
deltaTime=this.deltaTime) {
let ps = this.parent
this.chain.apply(this, arguments)
ps.last().spring.to(ps[0], rLen, springConstant, damping, lockedPoints, deltaTime)
}
}
Polypoint.head.deferredProp('PointList', function() {
return new PointListSpring(this)
}, 'spring')
Polypoint.head.lazyProp('Point', {
spring() {
let r = this._spring
if(r == undefined) {
r = new PointSpring(this)
this._spring = r
}
return r
}
})
copy