Parse

File Parse rope.js

This tree is parsed live from the source file.

Classes

  • {{ item.name }}

    • {{ key }}

Not Classes

{{ getTree() }}

Comments

{{ getTreeComments() }}

Source

            /*

The _rope_ provides constraints through vertlet chain solutions.

*/

class RopeReactor {

    gravity = 0.35;

    constructor(pins={}, dynamicPins=[]) {
        this.pinnedPositions = pins == undefined? {}: pins
        this.dynamicPins = dynamicPins== undefined? {}: dynamicPins
    }

    getPinIndicies(points) {
        const pinnedPositions = this.getPins(points)
        const pinnedIndices = Object.keys(pinnedPositions).map(Number);
        return pinnedIndices
    }

    applyPhysics(points, gravity=this.gravity, pinnedIndices) {
        if(pinnedIndices == undefined) {
            pinnedIndices = this.getPinIndicies(points)
        }

        points.forEach((p, index) => {
            if(pinnedIndices.includes(index)) { return }

            const vx = (p.x - p.oldX) * 0.98;
            const vy = (p.y - p.oldY) * 0.98;

            p.oldX = p.x;
            p.oldY = p.y;

            if(gravity.x !== undefined) {
                p.x += vx + gravity.x;
                p.y += vy + gravity.y;
                return
            }

            p.x += vx;
            p.y += vy + gravity;
        });
    }

    applyPhysics2(points, gravity2D, pinnedIndices){
        const pinnedPositions = this.getPins(points)
        if(pinnedIndices == undefined) {
            pinnedIndices = Object.keys(pinnedPositions).map(Number);
        }
        points.forEach((p, index) => {
            if (!pinnedIndices.includes(index) && (p.invMass ?? 1) !== 0) {
                p.x += gravity2D.x * (p.invMass ?? 1) * this.gravity;
                p.y += gravity2D.y * (p.invMass ?? 1) * this.gravity;
            }
        });
    }

    solveConstraints1(points, segmentLength, iterations = 5) {
        for (let j = 0; j < iterations; j++) {
            for (let i = 0; i < points.length - 1; i++) {
                const p1 = points[i];
                const p2 = points[i + 1];

                let dx = p2.x - p1.x;
                let dy = p2.y - p1.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                const difference = segmentLength - distance;
                const percent = difference / distance / 2;

                const offsetX = dx * percent;
                const offsetY = dy * percent;

                if (i !== 0) {
                    p1.x -= offsetX;
                    p1.y -= offsetY;
                }
                p2.x += offsetX;
                p2.y += offsetY;
            }
        }
    }

    solveConstraints2(points, segmentLength, iterations = 5) {
        const pl = points.last()
        let endPin = this.endPin
        const pinnedPositions = {
            // 0: this.mouse.point
            // , [~~(points.length *.5)]: this.midPin
            // , [points.length - 1]: endPin
        };

        const pinnedIndices = Object.keys(pinnedPositions)

        for (let j = 0; j < iterations; j++) {
            for (let i = 0; i < points.length - 1; i++) {
                const p1 = points[i];
                const p2 = points[i + 1];

                let dx = p2.x - p1.x;
                let dy = p2.y - p1.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                const difference = segmentLength - distance;
                const percent = difference / distance / 2;

                const offsetX = dx * percent;
                const offsetY = dy * percent;

                if (!pinnedIndices.includes(i)) {
                    p1.x -= offsetX;
                    p1.y -= offsetY;
                }

                if (!pinnedIndices.includes(i + 1)) {
                    p2.x += offsetX;
                    p2.y += offsetY;
                }
            }

            // Reinforce pinned positions after constraint adjustment
            pinnedIndices.forEach(index => {
                points[index].x = pinnedPositions[index].x;
                points[index].y = pinnedPositions[index].y;
            });
        }
    }

    pin(index, point) {
        /* pin an internal index item, to the XY given.
        */
       if(point == undefined) {
            // generate a point, essentially _pinning_ the current location.
            this.dynamicPins.push(index)
       }
       this.pinnedPositions[index] = point;
    }

    getPins(points) {
        let pins = Object.assign({}, this.pinnedPositions)
        this.dynamicPins.forEach((v,i)=>{
            if(pins[v] == undefined) {
                pins[v] = points[i]
            }
        })

        return pins
    }

    solveConstraints3(points, segmentLength, iterations = 5) {
        const pinnedPositions = this.getPins(points)
        const pinnedIndices = Object.keys(pinnedPositions).map(Number);
        for (let j = 0; j < iterations; j++) {
            for (let i = 0; i < points.length - 1; i++) {
                const p1 = points[i];
                const p2 = points[i + 1];

                let dx = p2.x - p1.x;
                let dy = p2.y - p1.y;
                const distance = Math.sqrt(dx * dx + dy * dy) || 0.0001; // prevent NaN
                const difference = segmentLength - distance;

                const invMass1 = p1.invMass ?? 1; // Default to 1 if undefined
                const invMass2 = p2.invMass ?? 1;
                const totalInvMass = invMass1 + invMass2 || 0.0001; // prevent division by zero

                const percent1 = (invMass1 / totalInvMass) * difference / distance;
                const percent2 = (invMass2 / totalInvMass) * difference / distance;

                if (!pinnedIndices.includes(i)) {
                    p1.x -= dx * percent1;
                    p1.y -= dy * percent1;
                }

                if (!pinnedIndices.includes(i + 1)) {
                    p2.x += dx * percent2;
                    p2.y += dy * percent2;
                }
            }

            // Re-pin positions
            pinnedIndices.forEach(index => {
                points[index].x = pinnedPositions[index].x;
                points[index].y = pinnedPositions[index].y;
            });
        }
    }
}
copy