Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Paperjs metaballs not working/displaying

I'm trying to customize the metaballs example from Paperjs (http://paperjs.org/examples/meta-balls/). Problem is, that even copy-pasting it, it won't work. It does not draw/display the "bridges" between the balls.

Here's a jsFiddle: http://jsfiddle.net/AK47p/

And here's the code:

$(document).ready(function () {

    // Get a reference to the canvas object
    var canvas = document.getElementById('canvas');
    // Create an empty project and a view for the canvas:
    paper.setup(canvas);
    // Create a simple drawing tool:
    var tool = new paper.Tool();

    // Ported from original Metaball script by SATO Hiroyuki
    // http://park12.wakwak.com/~shp/lc/et/en_aics_script.html
    paper.project.currentStyle = {
        fillColor: 'black'
    };

    var ballPositions = [[255, 129], [610, 73], [486, 163],
        [117, 259], [484, 326], [843, 306], [789, 215], [949, 82],
        [292, 128], [917, 233], [352, 86], [92, 98]];

    var handle_len_rate = 2.4;
    var circlePaths = [];
    var radius = 50;
    for (var i = 0, l = ballPositions.length; i < l; i++) {
        var circlePath = new paper.Path.Circle({
            center: ballPositions[i],
            radius: 50
        });
        circlePaths.push(circlePath);
    }

    var largeCircle = new paper.Path.Circle({
        center: paper.view.center,
        radius: 100,
        fillColor: 'green'
    });
    circlePaths.push(largeCircle);

    tool.onMouseMove = function(event) {
        largeCircle.position = event.point;
        generateConnections(circlePaths);
    }

    var connections = new paper.Group(); var thePath;
    function generateConnections(paths) {
        // Remove the last connection paths:
        connections.children = [];

        for (var i = 0, l = paths.length; i < l; i++) {
            for (var j = i - 1; j >= 0; j--) {
                var path = metaball(paths[i], paths[j], 0.5, handle_len_rate, 300);thePath = path;
                if (path) {
                    connections.appendTop(path);
                    path.removeOnMove();
                }
            }
        }
    }

    generateConnections(circlePaths);

    // ---------------------------------------------
    function metaball(ball1, ball2, v, handle_len_rate, maxDistance) {
        var center1 = ball1.position;
        var center2 = ball2.position;
        var radius1 = ball1.bounds.width / 2;
        var radius2 = ball2.bounds.width / 2;
        var pi2 = Math.PI / 2;
        var d = center1.getDistance(center2);
        var u1, u2;

        if (radius1 == 0 || radius2 == 0)
            return;

        if (d > maxDistance || d <= Math.abs(radius1 - radius2)) {
            return;
        } else if (d < radius1 + radius2) { // case circles are overlapping
            u1 = Math.acos((radius1 * radius1 + d * d - radius2 * radius2) /
                    (2 * radius1 * d));
            u2 = Math.acos((radius2 * radius2 + d * d - radius1 * radius1) /
                    (2 * radius2 * d));
        } else {
            u1 = 0;
            u2 = 0;
        }

        var angle1 = center2.subtract(center1).getAngleInRadians();
        var angle2 = Math.acos((radius1 - radius2) / d);
        var angle1a = angle1 + u1 + (angle2 - u1) * v;
        var angle1b = angle1 - u1 - (angle2 - u1) * v;
        var angle2a = angle1 + Math.PI - u2 - (Math.PI - u2 - angle2) * v;
        var angle2b = angle1 - Math.PI + u2 + (Math.PI - u2 - angle2) * v;
        var p1a = center1 + getVector(angle1a, radius1);
        var p1b = center1 + getVector(angle1b, radius1);
        var p2a = center2 + getVector(angle2a, radius2);
        var p2b = center2 + getVector(angle2b, radius2);

        // define handle length by the distance between
        // both ends of the curve to draw
        var totalRadius = (radius1 + radius2);
        var d2 = Math.min(v * handle_len_rate, (p1a - p2a).length / totalRadius);

        // case circles are overlapping:
        d2 *= Math.min(1, d * 2 / (radius1 + radius2));

        radius1 *= d2;
        radius2 *= d2;

        var path = new paper.Path({
            segments: [p1a, p2a, p2b, p1b],
            style: ball1.style,
            closed: true
        });
        var segments = path.segments;
        segments[0].handleOut = getVector(angle1a - pi2, radius1);
        segments[1].handleIn = getVector(angle2a + pi2, radius2);
        segments[2].handleOut = getVector(angle2b - pi2, radius2);
        segments[3].handleIn = getVector(angle1b + pi2, radius1);
        return path;
    }

    // ------------------------------------------------
    function getVector(radians, length) {
        return new paper.Point({
            // Convert radians to degrees:
            angle: radians * 180 / Math.PI,
            length: length
        });
    }
});

As you can see I wrapped the code in a domReady function, as that is going to be part of a slideshow. I followed the instructions here (http://paperjs.org/tutorials/getting-started/using-javascript-directly/) to do this. Any idea what is wrong? I checked over and over, I must be missing something...

Thank you

like image 596
mjsarfatti Avatar asked Dec 03 '25 08:12

mjsarfatti


1 Answers

Found out what was missing. It is not very well documented on Paperjs, anyway if you use it like regular javascript make sure all operations on paper objects (Point, Path etc.) are expressed as methods, instead of as operators.

wrong

var d2 = Math.min(v * handle_len_rate, (point1a - point2a).length / totalRadius);

right

var d2 = Math.min(v * handle_len_rate, point1a.subtract(point2a).length / totalRadius);
like image 170
mjsarfatti Avatar answered Dec 05 '25 22:12

mjsarfatti