5 Replies Latest reply on Aug 14, 2012 8:19 AM by Ghoulfool

    Circular path

    Ghoulfool Level 1

      A while back I asked if anyone had messed about with scripting paths in Photoshop. I got little response. Anyway I persevered with the hope of creating a circle. Just for kicks, you understand (I must get out more). Turns out there isn't much info out there on the subject only that it's not possible to create a true circle with bezier curves. I've had a look it into it and I've managed a circular approximation with paths.


      // draw circular path
      // use at your own risk
      // Author: ghoulfool
      // Thanks to G. Adam Stanislav for the kappa explanation
      // Kappa Kappa Hey!
      app.preferences.rulerUnits = Units.PIXELS;
      // OPTIONALS
      var radius = 150; // radius of the circle to be drawn
      var circX = 160; // centre of circle X
      var circY = 160; // centre of circle Y
      //  create a document to work with
      var docRef = app.documents.add("320px", "320px", 72, "Circle");
      // call the source document
      var srcDoc = app.activeDocument;
      // create new layer
      var layerRef = srcDoc.artLayers.add()
      layerRef.name = "circle"
      layerRef.blendMode = BlendMode.NORMAL
      //draw circle
      drawCircle(circX , circY, radius, "circle")
      function drawCircle(X,Y,rad, pathName)
      var K = (4 * (Math.sqrt(2) - 1) / 3)* rad
      // define circle points
      var C = new Array();
      C = [X, Y - rad, X + rad, Y, X, Y + rad, X - rad, Y, X + K, Y - rad, X + rad, Y - K, X + rad, Y + K, X - K, Y + rad, X + K, Y + rad, X - rad, Y + K, X - rad, Y - K, X - K, Y - rad];
      // create the array of PathPointInfo objects
      var lineArray = new Array();
      lineArray.push(new PathPointInfo());
      lineArray[0].kind = PointKind.CORNERPOINT;
      lineArray[0].anchor = new Array(C[0], C[1]); // A
      lineArray[0].leftDirection =  [C[8], C[9]];
      lineArray[0].rightDirection = lineArray[0].anchor;
      lineArray.push(new PathPointInfo());
      lineArray[1].kind = PointKind.CORNERPOINT;
      lineArray[1].anchor = new Array(C[2], C[3]); // B
      lineArray[1].leftDirection = [C[12], C[13]];
      lineArray[1].rightDirection =  [C[10], C[11]];
      lineArray.push(new PathPointInfo());
      lineArray[2].kind = PointKind.CORNERPOINT;
      lineArray[2].anchor = new Array(C[4], C[5]); // C
      lineArray[2].leftDirection = [C[14], C[15]];
      lineArray[2].rightDirection =  [C[16], C[17]];
      lineArray.push(new PathPointInfo());
      lineArray[3].kind = PointKind.CORNERPOINT;
      lineArray[3].anchor = new Array(C[6], C[7]);    // D
      lineArray[3].leftDirection = [C[20], C[21]];
      lineArray[3].rightDirection =  [C[18], C[19]];
      lineArray.push(new PathPointInfo());
      lineArray[4].kind = PointKind.CORNERPOINT;
      lineArray[4].anchor = new Array(C[0], C[1]); 
      lineArray[4].leftDirection = lineArray[4].anchor; 
      lineArray[4].rightDirection =  [C[22], C[23]];
      // create a SubPathInfo object, which holds the line array in its entireSubPath property.
      var lineSubPathArray = new Array();
      lineSubPathArray.push(new SubPathInfo());
      lineSubPathArray[0].operation = ShapeOperation.SHAPEXOR;
      lineSubPathArray[0].closed = false;
      lineSubPathArray[0].entireSubPath = lineArray;
      //create the path item, passing subpath to add method
      var myPathItem = docRef.pathItems.add(pathName, lineSubPathArray);
      // set foreground colour to green
      var fgColor = new SolidColor;
      fgColor.rgb.hexValue="00ff80"  //green colour
      foregroundColor = fgColor
      //fill the path 
      //deselect path
      // =======================================================
      var id630 = charIDToTypeID( "Dslc" );
      var desc154 = new ActionDescriptor();
      var id631 = charIDToTypeID( "null" );
      var ref127 = new ActionReference();
      var id632 = charIDToTypeID( "Path" );
      ref127.putClass( id632 );
      desc154.putReference( id631, ref127 );
      executeAction( id630, desc154, DialogModes.NO );


      This was my second attempt. The first was on a semi circle basis with two points - but the circles looked very oval. This is much better I feel.


        • 1. Re: Circular path
          c.pfaffenbichler Level 9

          Turns out there isn't much info out there on the subject only that it's not possible to create a true circle with bezier curves.

          Is that so indeed?

          The Ellipse Tool (constrained) seems to create a decent crircular Path and if that is pasted above itself and rotated I cannot notice any misalignments.

          1 person found this helpful
          • 2. Re: Circular path
            Ghoulfool Level 1

            I was well aware that you can convert the ellipsis tool to a path (make work path) but the resulting path is perfectly circular, but rather messy (in terms of point placement)path_close_up.png


            The whole point of the exercise was for me to gain a better understanding on how bezier paths work within scripting. So i'm happy.

            • 3. Re: Circular path
              c.pfaffenbichler Level 9

              The result of the Ellipse Tool is a Path (with 4 points), did you mean the Elliptical Marquee Tool?


              Edit: I mean the Ellipse Tool which is tertiary to the Rectangle Tool (U).

              1 person found this helpful
              • 4. Re: Circular path
                JJMack Most Valuable Participant

                This would be very easy to do with scriptlistner code using either the elliptical marquee tool or elliptical tool. The elliptical tool can create a Path directly and the elliptical marquee tool can create selection which in turn can be turned in a path all can be transformed. The elliptical tool would create a better Path a circle would have 4 point.  Converting a slection is to a path would not work that well.


                I created a plug-in script based on "Fit Image.jsx"  that combine the rectangle and elliptical selection tools so you can record making aspect ratio selection for documents in actions. The plugin http://www.mouseprints.net/old/dpr/AspectRatioSelection.jsx


                /* ==========================================================

                // Christmass 2007 John J. McAssey (JJMack) and the

                // Day I descovered Photoshop had what I wanted

                // a way to pass Prams to Scripts throught menu File>Automate

                // ======================================================= */



                /* SetMarqueeSelection function from Scriptlistner plugin

                // ========================================================================== */

                function setMarqueeSelection(x1, y1, x2, y2, type, shape, feather, antiAlias) {

                          var SelectionType =null;

                          if (type ==null)      {          var SelectionType = "setd" }

                          if (type ==diminish)  {          var SelectionType = "SbtF" }

                          if (type ==extend)    {          var SelectionType = "AddT" }

                          if (type ==intersect) {          var SelectionType = "IntW" }

                          if (type ==replace)   {          var SelectionType = "setd" }



                          var id3          = charIDToTypeID( SelectionType          );

                              var          desc2 =          new ActionDescriptor();

                              var          id4 = charIDToTypeID( "null" );

                                    var ref1 = new ActionReference();

                                    var id5          = charIDToTypeID( "Chnl" );

                                    var id6          = charIDToTypeID( "fsel" );

                                    ref1.putProperty( id5, id6 );

                              desc2.putReference(          id4, ref1 );

                              var          id7 = charIDToTypeID( "T   " );

                                    var desc3 = new          ActionDescriptor();

                                    var id8          = charIDToTypeID( "Top " );

                                    var id9          = charIDToTypeID( "#Pxl" );

                                    desc3.putUnitDouble( id8, id9, y1 );

                                    var id10 = charIDToTypeID( "Left" );

                                    var id11 = charIDToTypeID( "#Pxl" );

                                    desc3.putUnitDouble( id10, id11, x1 );

                                    var id12 = charIDToTypeID( "Btom" );

                                    var id13 = charIDToTypeID( "#Pxl" );

                                    desc3.putUnitDouble( id12, id13, y2 );

                                    var id14 = charIDToTypeID( "Rght" );

                                    var id15 = charIDToTypeID( "#Pxl" );

                                    desc3.putUnitDouble( id14, id15, x2 );

                              var          id16 = charIDToTypeID( shape );

                              desc2.putObject( id7, id16,          desc3 );

                              var          id17 = charIDToTypeID( "Fthr" );

                              var          id18 = charIDToTypeID( "#Pxl" );

                              desc2.putUnitDouble( id17, id18, feather );

                              var          id19 = charIDToTypeID( "AntA" );

                              desc2.putBoolean( id19, antiAlias );

                          executeAction( id3, desc2, DialogModes.NO );



                1 person found this helpful
                • 5. Re: Circular path
                  Ghoulfool Level 1


                  You're right about the ellipse tool. It does a good job. Yes....and there was a bit of confusion with Ellipse tool and Elliptical Marquee Tool.

                  1 person found this helpful