Advertisement
Cronos

Illustrator Fit Circle to Corner Script

Oct 20th, 2012
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // script.name = fitCircleToCorner,jsx
  2. // script.description = it moves a circle to the tightest fit in a selected corner point
  3. // script.required = One circle and one Straight Lines Corner Anchor Point selected.
  4. // script.parent = CarlosCanto // 10/20/12;
  5. // script.elegant = false;
  6.  
  7. // USAGE select a circle and a single coner point on a polygone to fit the circle tangent to that corner.
  8. // for easy selection, use the white arrow and click on the center of the circle and then on a single point on a polygone
  9.        
  10.  
  11. #target "illustrator"
  12.  
  13. var doc = app.activeDocument;
  14. var sel = doc.selection;
  15.  
  16. if (sel.length==2) { // need two selected paths, the circle and the polygone
  17.     var circle = null;
  18.     var polygone = null;
  19.     var polyPoints = null;
  20.    
  21.     for (j=0; j<sel.length; j++) { //
  22.         var pat = sel[j];
  23.         // check each selected path for a corner point, if one is not then the path is the circle
  24.         var obj = isCornerPoint(pat); // the obj returned holds wether there is a corner point selected and wich points of the 3 are p1, p0, p2
  25.  
  26.         if (obj.selected=='true') { // then this is the polygon
  27.             polygone = pat;
  28.             polyPoints = obj;
  29.         }
  30.         else {
  31.             // NOT the corner point, now check if it is a "true" circle
  32.            if (pat.pathPoints.length == 4) {
  33.                 if (isItAcircle (pat)) {
  34.                     circle = pat;
  35.                 }
  36.                 else
  37.                     alert('the path is not a circle');
  38.             }
  39.         }
  40.     }
  41.     // if either circle or polygone are null, abort
  42.     if (circle==null || polygone ==null) { // circle = null, both the circle and the polygone have 3 selected pathPoints,
  43.         if (polygone == null) alert('a single corner point needs to be selected')
  44.         alert('Select ONE single Corner Point on a Polygone and ONE Fully selected Circle');          // polygone = null, it needs to have only on anchor point selected
  45.     }
  46.     else {
  47.         //alert ('good, continue');
  48.         fitCircle (polyPoints, circle);
  49.     }
  50. }
  51. else {
  52.     alert('select a circle and a single coner point on a polygon');
  53. }
  54.  
  55. //---------------------------------------------------------------------------
  56. // check if pathItem passed is a "corner" point, meaning the path has1 anchor point selected
  57. // return if it is a corner + the acutal anchor (p0) + p1 and p2, which makes the angle p1-p0-p2
  58. function isCornerPoint(pi /*pathItem*/) {
  59.     var anchorsSelected = 0;
  60.     var cornerCount = 0;
  61.     var p0 = [];
  62.     var p12 = [];
  63.     var idx = null;
  64.    
  65.     var sPP = pi.selectedPathPoints;
  66.     if (sPP.length != 3) {  // if other than 3 points are selected, exit, this path has not a corner point selected
  67.         return {selected:'false',  idx:idx, p0:p0, p12:p12}
  68.     }
  69.     // continue if 3 pathPoints are selected (1 anchor + 2 handles)
  70.     var selRt = PathPointSelection.RIGHTDIRECTION;
  71.     var selAn = PathPointSelection.ANCHORPOINT;
  72.     var selLt = PathPointSelection.LEFTDIRECTION;
  73.    
  74.     // loop thru all 3 points to get only 1 anchor selected
  75.     for (i=0; i<sPP.length; i++) {
  76.         if (sPP[i].selected == selAn) {
  77.             cornerCount ++;
  78.             idx = i; // if idx = 0, then it is the path's first anchor, idx=2, then is the path's last anchor, idx =1, then it is any other anchor
  79.             anchorsSelected++; // count them, if more than 1, it can't be used as a "corner"
  80.             p0.push(sPP[i]); // this will hold p0, if more than one, then it can't be used as a "corner" point
  81.         }
  82.         else {
  83.             // check if point is not "smooth", handles towards corner must be at the same x,y as point.Anchor
  84.             if (sPP[i].selected == selRt && sPP[i].anchor.toString() == sPP[i].rightDirection.toString()) {
  85.                 cornerCount ++;
  86.             }
  87.             else if (sPP[i].selected == selLt && sPP[i].anchor.toString() == sPP[i].leftDirection.toString()) {
  88.                 cornerCount ++;
  89.             }
  90.             p12.push(sPP[i]); // push the pathPoints that are not selected, it will hold p1 and p2
  91.         }
  92.     }
  93.  
  94.     if (p0.length==1 && cornerCount==3) {
  95.         return {selected:'true', idx:idx, p0:p0, p12:p12}
  96.     }
  97.  
  98.     return {selected:'false',  idx:idx, p0:p0, p12:p12}
  99. }
  100.  
  101. // --------------------------------------------------------------------------------------------------------
  102. // --------------------------------------------------------------------------------------------------------
  103.  
  104. function fitCircle (cornerPathPoints, circle) {
  105.  
  106.     var pat = cornerPathPoints;
  107.     var circle = circle;
  108.  
  109.     var r = circle.width/2;
  110.     var angRad = get3pointAngle(pat); // this is the angle info object
  111.  
  112.     var h = r/Math.sin(angRad.ang1o2/2); // hypotenuse, distance from selected point to center of circle at half the agnle between points
  113.  
  114.     var x1 = h*Math.cos(angRad.angHalf)+angRad.Po[0]; // center of circle pos x
  115.     var y1 = h*Math.sin(angRad.angHalf)+angRad.Po[1]; // center of circle pos y
  116.    
  117.     reposition(circle, x1, y1, r);
  118.  
  119.     function reposition (obj, x, y, r) {
  120.         obj.position = [x-r, y+r];
  121.     }
  122.  
  123.     function get3pointAngle(pi /*pathPoints object*/) {
  124.         var p1 = pi.p12[0].anchor;
  125.         var o = pi.p0[0].anchor;
  126.         var p2 = pi.p12[1].anchor;
  127.  
  128.     // get both angles individually
  129.         var ang1 = get2pointAngle(o,p1);
  130.         var ang2 = get2pointAngle(o,p2);
  131.     // who's the bigger    
  132.         var angbig = Math.max (ang1, ang2);
  133.         var angsmall = Math.min (ang1, ang2);
  134.  
  135.         ang1 = angsmall; // make 1 the smaller
  136.         ang2 = angbig; // make 2 the bigger
  137.        
  138.         var ang1o2 = ang2-ang1; // this is the p1-o-p2 angle (ie 60)
  139.         var halfangle = ((ang2 - ang1) /2)+ang1;  // this is half the p1-o-p2 angle (ie 30) but from the horizon (ie 135)
  140.        
  141.         // if angle 1o2 is over 180 deg then inside corner should be on the other side (add 180 deg or Pi)
  142.         if (Math.abs(ang1o2)>Math.PI) {
  143.             halfangle = halfangle + Math.PI;
  144.         }
  145.         var angle = {ang1o2:ang1o2, angHalf:halfangle, Po:o}; // angle info object
  146.         return angle;
  147.     }
  148.  
  149.  
  150.     // return the angle from p1 to p2 in Radians. p1 is the origin, p2 rotates around p1
  151.     function get2pointAngle(p1, p2) {
  152.         var angl = Math.atan2(p2[1] - p1[1], p2[0] - p1[0]);
  153.         if (angl<0) {   // atan2 returns angles from 0 to Pi, if angle is negative it means is over 180 deg or over Pi, add 360 deg or 2Pi, to get the an absolute Positive angle from 0-360 deg
  154.             angl = angl + 2*Math.PI;
  155.         }
  156.       return angl; //
  157.     }
  158.  
  159. }
  160.  
  161.  
  162. // ---------------------------------------------------------------------------------------------------------------------
  163. // ---------------------------------------------------------------------------------------------------------------------
  164. // based on Area and Perimeter  Circle formulas, solving for Pi, both should be equal, or close but they're not. Bezier approx may it be?
  165. // if both are equal to the hard coded Pi, then tha path is a circle. 2 pt circles result as "not circles" with 3 digit precision
  166. function isItAcircle (path) {
  167.     var sel = path;
  168.     var areaPi = sel.area/Math.pow(sel.width/2,2);
  169.     var periPi = sel.length/sel.width;
  170.     var decimals = 2; // two decimal gives us some distortion tolerance, we don't want to be too precise and rule all shapes as 'not circles'
  171.     var bezierPi = 3.14;
  172.  
  173.     areaPi = roundnumber (areaPi, decimals);
  174.     periPi = roundnumber (periPi, decimals);
  175.  
  176.     if (areaPi==bezierPi && periPi==bezierPi)
  177.         return true; //x = 'circle';
  178.     else
  179.         return false; //x = 'not a circle';
  180. }
  181.  
  182. // ---------------------------------------------------------------------------------------------------------------------
  183. // ---------------------------------------------------------------------------------------------------------------------
  184.  
  185. // round a number by x decimals
  186. function roundnumber(number, decimals) {
  187.     rounded = (Math.round(number*Math.pow(10,decimals))/Math.pow(10,decimals));//.toFixed(decimals); // to pad with zeros if necessary
  188.     return rounded;
  189. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement