Strict Standards: Only variables should be passed by reference in /home/abeall/public_html/fireworks/download.php on line 28

Warning: Cannot modify header information - headers already sent by (output started at /home/abeall/public_html/fireworks/download.php:28) in /home/abeall/public_html/fireworks/download.php on line 44
// Fireworks JavaScript Command // Distort the points of selected paths in a "fisheye" deformation // Install by copying to Fireworks/Configuration/Commands/ // Run in Fireworks via the Commands menu // Aaron Beall 2008-2011 - http://abeall.com // Version 1.2 /* TODO - [DONE] find paths within groups - [DONE-v1.1] better validate ellipse selection - [DONE-v1.1] work correctly on rotated ellipse - [DONE-v1.2] change all for..in to strict loops */ var dom = fw.getDocumentDOM(); var sel = [].concat(fw.selection); var dom = fw.getDocumentDOM(); var sel = [].concat(fw.selection); function Fisheye() { // require active document if (!dom) return false; // filter selection to paths var paths = []; function pathsIn(elems){ for(var e = 0; e < elems.length; e++){ if(elems[e] == '[object Path]') paths.push(elems[e]); if(elems[e] == '[object Group]') pathsIn(elems[e].elements) } } pathsIn(sel); // validate selection if(paths.length < 2) return alert('This command requires at least one selected path to be deformed, and a top ellipse to determine the fisheye area.'); if(paths[0].contours.length != 1) return alert('The top path must be an ellipse with only one contour.'); if(paths[0].contours[0].nodes.length != 4) return alert('The top path must be an ellipse with exactly 4 points.'); var a1 = getAngle(paths[0].contours[0].nodes[0], paths[0].contours[0].nodes[2]); var a2 = getAngle(paths[0].contours[0].nodes[1], paths[0].contours[0].nodes[3]); var dif = Math.abs(a1 - a2), DIF_TOLERANCE = 1; while(dif > 180) dif -= 180; if(Math.abs(90-dif) > DIF_TOLERANCE) return alert('The top path is not a valid ellipse.'); // user input var strength; do{ strength = prompt('Enter a strength (-100 to 100):', fw.Fisheye_strength || 100); }while(!validate()); function validate(){ if(strength == null) return true; strength = Number(strength); if(isNaN(strength)) return alert('Invalid input! Enter numbers only.'); strength = Math.min(Math.max(strength, -100), 100); return true; } if(strength == null) return false; fw.Fisheye_strength = strength; strength = strength / 100; if(strength == 0) return; // rotate deformation ellipse if necessary var rotate = Math.abs(a1) != 90 && Math.abs(a2) != 90; if(rotate){ fw.selection = paths; dom.rotateSelection(90 - a1, 'autoTrimImages transformAttributes'); paths = []; var s = fw.selection.length; while(s--) paths.push(fw.selection[s]); } // remove top most path and make it the deformer contour var ellipse = paths.shift(); // determine ellipse dimensions var center = { x:ellipse.left + ellipse.width / 2, y:ellipse.top + ellipse.height / 2 } // map all points relative to the bouding box var nodes, node, nod, pt, ln, prevNode, nextNode, SMOOTH_HANDLE_PERCENT = .35; var p = paths.length; while(p--){ if(paths[p].left + paths[p].width < ellipse.left || paths[p].left > ellipse.left + ellipse.width || paths[p].top + paths[p].height < ellipse.top || paths[p].top > ellipse.top + ellipse.height) continue; for(var c = 0; c < paths[p].contours.length; c++){ nodes = paths[p].contours[c].nodes; ln = nodes.length; for(var n = 0; n < ln; n++){ node = nodes[n]; // if node-to-prevNode is a line, make smooth prevNode = n == 0 ? nodes[ln - 1] : nodes[n - 1]; if(node.x == node.predX && node.y == node.predY && prevNode.succX == prevNode.x && prevNode.succY == prevNode.y){ node.predX = node.x + (prevNode.succX - node.x) * SMOOTH_HANDLE_PERCENT; node.predY = node.y + (prevNode.succY - node.y) * SMOOTH_HANDLE_PERCENT; prevNode.succX = prevNode.x + (node.x - prevNode.succX) * SMOOTH_HANDLE_PERCENT; prevNode.succY = prevNode.y + (node.y - prevNode.succY) * SMOOTH_HANDLE_PERCENT; } // if node-to-nextNode is a line, make smooth nextNode = n == ln - 1 ? nodes[0] : nodes[n + 1]; if(node.x == node.succX && node.y == node.succY && nextNode.predX == nextNode.x && nextNode.predY == nextNode.y){ node.succX = node.x + (nextNode.predX - node.x) * SMOOTH_HANDLE_PERCENT; node.succY = node.y + (nextNode.predY - node.y) * SMOOTH_HANDLE_PERCENT; nextNode.predX = nextNode.x + (node.x - nextNode.predX) * SMOOTH_HANDLE_PERCENT; nextNode.predY = nextNode.y + (node.y - nextNode.predY) * SMOOTH_HANDLE_PERCENT; } // deform node x,y nod = {x:node.x, y:node.y}; pt = interpolateNode(nod, center, ellipse); if(pt){ node.x = node.x + (pt.x - node.x) * strength; node.y = node.y + (pt.y - node.y) * strength; } // deform node pred x,y nod = {x:node.predX, y:node.predY}; pt = interpolateNode(nod, center, ellipse); if(pt){ node.predX = node.predX + (pt.x - node.predX) * strength; node.predY = node.predY + (pt.y - node.predY) * strength; } // deform node succ x,y nod = {x:node.succX, y:node.succY}; pt = interpolateNode(nod, center, ellipse); if(pt){ node.succX = node.succX + (pt.x - node.succX) * strength; node.succY = node.succY + (pt.y - node.succY) * strength; } // smooth out curve handles var predAngle, succAngle, avgAngle, dif, dist, traj; if(node.isCurvePoint){ // find average handle tangent predAngle = getAngle({x:node.predX, y:node.predY}, node); succAngle = getAngle(node, {x:node.succX, y:node.succY}); dif = predAngle - succAngle; avgAngle = succAngle + dif / 2; if(Math.abs(dif) >180) avgAngle += 180; // determine if handles already tangent if(predAngle == avgAngle || succAngle == avgAngle) continue; // adjust successor handle to average dist = getDistance(node, {x:node.succX, y:node.succY}); traj = getTrajectory(dist, avgAngle); node.succX = node.x + traj.x; node.succY = node.y + traj.y; // adjust predecessor handle to average dist = getDistance(node, {x:node.predX, y:node.predY}); traj = getTrajectory(dist, avgAngle + 180); node.predX = node.x + traj.x; node.predY = node.y + traj.y; } } } } // restore selection fw.selection = paths.concat(ellipse); // roate back if necessary if(rotate) dom.rotateSelection(-(90 - a1), 'autoTrimImages transformAttributes'); } //try{ Fisheye(); //}catch(e){ alert([e, e.lineNumber, e.fileName].join("\n")) }; // interpolates a node based on ellipse container function interpolateNode(nod, center, ellipse){ if(nod.x < ellipse.left || nod.y < ellipse.top || ellipse.x > ellipse.left + ellipse.width || ellipse.y > ellipse.top + ellipse.height) return null; var angle = getAngleRadians(center, nod); var perim = getEllipse(center, ellipse, angle); //dom.addNewLine(center,perim); var perimDistance = getDistance(center, perim); var nodeDistance = getDistance(center, nod); var weight = nodeDistance / perimDistance; if(weight < 1){ return { x:interpolateQuad(weight, center.x, perim.x - center.x, 1), y:interpolateQuad(weight, center.y, perim.y - center.y, 1) } }else{ return null; } } // find point on ellipse perimeter that is angle(in radians) from center function getEllipse(center, ellipse, angle){ var r = 0.5 / Math.sqrt(Math.pow(Math.cos(angle) / ellipse.width, 2) + Math.pow(Math.sin(angle) / ellipse.height, 2) ) ; var x = center.x + r * Math.cos(angle); var y = center.y + r * Math.sin(angle); return {x:x, y:y}; } // quadratic interpolation // t: current time, b: beginning value, c: change in value, d: duration function interpolateQuad(t, b, c, d){ return -c *(t/=d) * (t - 2) + b; } // circular interpolation // t: current time, b: beginning value, c: change in position, d: duration //function interpolateCirc(t, b, c, d) { //return c * Math.sqrt(1 - (t=t/d-1)*t) + b; //} // sine interpolation // t: current time, b: beginning value, c: change in position, d: duration //function interpolateSine(t, b, c, d) { //return c * Math.sin(t/d * (Math.PI/2)) + b; //} // get the angle in radians between two points function getAngleRadians(p1,p2){ return Math.atan2(p2.y - p1.y, p2.x - p1.x); } // get the distance between two points function getDistance(p1,p2){ return Math.sqrt(((p1.x-p2.x)*(p1.x-p2.x))+((p1.y-p2.y)*(p1.y-p2.y))); } // get the angle in degrees between two points function getAngle(p1,p2){ return -Math.atan2((p1.x-p2.x), (p1.y-p2.y))/(Math.PI/180); } // given angle and distance, find x,y translation function getTrajectory(distance,angle){ var xS = distance*Math.sin(angle*(Math.PI/180)); var yS = -distance*Math.cos(angle*(Math.PI/180)); return {x:xS,y:yS}; }