diff --git a/examples/Paperjs.org/MetaBalls.html b/examples/Paperjs.org/MetaBalls.html index 10073292..4933f4ff 100644 --- a/examples/Paperjs.org/MetaBalls.html +++ b/examples/Paperjs.org/MetaBalls.html @@ -9,105 +9,120 @@ // Ported from original Metaball script by SATO Hiroyuki // http://park12.wakwak.com/~shp/lc/et/en_aics_script.html project.currentStyle = { - fillColor: 'black' + fillColor: 'black' }; + var ballPositions = [[255, 129], [610, 73], [486, 363], + [117, 459], [484, 726], [843, 306], [789, 615], [1049, 82], + [1292, 428], [1117, 733], [1352, 86], [92, 798]]; + var handle_len_rate = 2.4; var circlePaths = []; - var circlePath; var radius = 50; - circlePaths.push(new Path.Circle(view.center, 100)); - function onMouseDown(event) { - circlePath = null; - for (var i = 0, l = circlePaths.length; i < l; i++) { - var path = circlePaths[i]; - if (path.position.getDistance(event.point) < 50) - circlePath = path; - } - if (!circlePath) { - circlePath = new Path.Circle(event.point, 50); - circlePaths.push(circlePath); - } - generateConnections(circlePaths); + for (var i = 0, l = ballPositions.length; i < l; i++) { + var circlePath = new Path.Circle({ + center: ballPositions[i], + radius: 50 + }); + circlePaths.push(circlePath); } - function onMouseDrag(event) { - circlePath.position = event.point; - generateConnections(circlePaths); + var largeCircle = new Path.Circle({ + center: [676, 433], + radius: 100 + }); + circlePaths.push(largeCircle); + + function onMouseMove(event) { + largeCircle.position = event.point; + generateConnections(circlePaths); } + var connections = new Group(); function generateConnections(paths) { - 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); - if (path) { - path.removeOn({ - drag: true, - down: true - }); - } - } - } + // 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); + 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; + 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 (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; - } + 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 - 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 d2 = Math.min(v * handle_len_rate, p1a.getDistance(p2a) / (radius1 + radius2)); + var angle1 = (center2 - 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); - d2 *= Math.min(1, d * 2 / (radius1 + radius2)); // case circles are overlapping - radius1 *= d2; - radius2 *= d2; + // 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); - var path = new Path([p1a, p2a, p2b, p1b]); - path.style = ball1.style; - path.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; + // case circles are overlapping: + d2 *= Math.min(1, d * 2 / (radius1 + radius2)); + + radius1 *= d2; + radius2 *= d2; + + var path = new 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 Point({ - // Convert radians to degrees: - angle: radians * 180 / Math.PI, - length: length - }); + return new Point({ + // Convert radians to degrees: + angle: radians * 180 / Math.PI, + length: length + }); }