12 Replies Latest reply on Feb 18, 2012 1:23 AM by c.pfaffenbichler

    Point coordinates using for loop w/o closure problem?

    Steven Mathisen

      Currently I'm working on a script that iterates through all the points in a path and assigns a number value of the current point, and then returns the coordinates of that point. No matter how I structure the scope of the functions I'm not getting the current anchor points coordinates, just the final value. Everything else behaves as expected.. I've read every article I can on closures, but any attempt to make a anonymous function returns the code itself, not a value. I'm rather perplexed and guessing I'm missing something about the architecture of .anchor and how it assigns and returns values. Could someone help me get the correct .anchor coordinates to go with the correct point?

       

            i=0;
            j=0;
            var currentPath = app.activeDocument.pathItems.getByName("path");
            currentPath.select()
            var totalPoints = currentPath.subPathItems[0].pathPoints.length;
            var currentX = currentPath.subPathItems[0].pathPoints[i].anchor[0];
            var currentY = currentPath.subPathItems[0].pathPoints[i].anchor[1];
            currentPoint = Array(currentX, currentY)
      //Point Loop  
      for(i=0, j=0; i <= totalPoints; i++, j++){
                   fileOut.write("\n Point "+i+ "of " +totalPoints+ "Coords: "+currentPoint+ "\n")
                   };
              

       

      currentX, currentY and currentPoint are just new attempts to pass the values on. I'm not wedded to any of this script in particular, just trying to wrap my head around how .js functions in these situations. I'm using fileOut.write as a log generator, but will eventually use returns once I get over this problem.

       

      Thanks in advance!

        • 1. Re: Point coordinates using for loop w/o closure problem?
          c.pfaffenbichler Level 9

          I’m not sure what you want really – could you please explain what you expect to get from a path exactly?

           

          Maybe this can help; it should return an Array of Arrays of Arrays …

           

          Edit:

          var pathInfo = collectPathInfoFromDesc(app.activeDocument, getByName("path"));
          alert (pathInfo("\n\n"));
          

           

           

          ////// collect path info from actiondescriptor //////
          function collectPathInfoFromDesc (myDocument, thePath) {
          //var myDocument = app.activeDocument;
          var originalRulerUnits = app.preferences.rulerUnits;
          app.preferences.rulerUnits = Units.POINTS;
          // based of functions from xbytor’s stdlib;
          var ref = new ActionReference();
          for (var l = 0; l < myDocument.pathItems.length; l++) {
                    var thisPath = myDocument.pathItems[l];
                    if (thisPath == thePath && thisPath.name == "Work Path") {
                              ref.putProperty(cTID("Path"), cTID("WrPt"));
                              };
                    if (thisPath == thePath && thisPath.name != "Work Path" && thisPath.kind != PathKind.VECTORMASK) {
                              ref.putIndex(cTID("Path"), l + 1);
                              };
                    if (thisPath == thePath && thisPath.kind == PathKind.VECTORMASK) {
                  var idPath = charIDToTypeID( "Path" );
                  var idPath = charIDToTypeID( "Path" );
                  var idvectorMask = stringIDToTypeID( "vectorMask" );
                  ref.putEnumerated( idPath, idPath, idvectorMask );
                              };
                    };
          var desc = app.executeActionGet(ref);
          var pname = desc.getString(cTID('PthN'));
          // create new array;
          var theArray = new Array;
          var pathComponents = desc.getObjectValue(cTID("PthC")).getList(sTID('pathComponents'));
          // for subpathitems;
          for (var m = 0; m < pathComponents.count; m++) {
                    var listKey = pathComponents.getObjectValue(m).getList(sTID("subpathListKey"));
                var operation1 = pathComponents.getObjectValue(m).getEnumerationValue(sTID("shapeOperation"));
                    switch (operation1) {
                              case 1097098272:
                              var operation = ShapeOperation.SHAPEADD;
                              break;
                              case 1398961266:
                              var operation = ShapeOperation.SHAPESUBTRACT;
                              break;
                              case 1231975538:
                              var operation = ShapeOperation.SHAPEINTERSECT;
                              break;
                              default:
          //                    case 1102:
                              var operation = ShapeOperation.SHAPEXOR;
                              break;
                              };
          // for subpathitem’s count;
                    for (var n = 0; n < listKey.count; n++) {
                              theArray.push(new Array);
                              var points = listKey.getObjectValue(n).getList(sTID('points'));
                              try {var closed = listKey.getObjectValue(n).getBoolean(sTID("closedSubpath"))}
                              catch (e) {var closed = false};
          // for subpathitem’s segment’s number of points;
                              for (var o = 0; o < points.count; o++) {
                                        var anchorObj = points.getObjectValue(o).getObjectValue(sTID("anchor"));
                                        var anchor = [anchorObj.getUnitDoubleValue(sTID('horizontal')), anchorObj.getUnitDoubleValue(sTID('vertical'))];
                                        var thisPoint = [anchor];
                                        try {
                                                  var left = points.getObjectValue(o).getObjectValue(cTID("Fwd "));
                                                  var leftDirection = [left.getUnitDoubleValue(sTID('horizontal')), left.getUnitDoubleValue(sTID('vertical'))];
                                                  thisPoint.push(leftDirection)
                                                  }
                                        catch (e) {
                                                  thisPoint.push(anchor)
                                                  };
                                        try {
                                                  var right = points.getObjectValue(o).getObjectValue(cTID("Bwd "));
                                                  var rightDirection = [right.getUnitDoubleValue(sTID('horizontal')), right.getUnitDoubleValue(sTID('vertical'))]
                                                  thisPoint.push(rightDirection)
                                                  }
                                        catch (e) {
                                                  thisPoint.push(anchor)
                                                  };
                                        theArray[theArray.length - 1].push(thisPoint);
                                        };
                              theArray[theArray.length - 1].push(closed);
                              theArray[theArray.length - 1].push(operation);
                              };
                    };
          // by xbytor, thanks to him;
          function cTID (s) { return cTID[s] || cTID[s] = app.charIDToTypeID(s); };
          function sTID (s) { return sTID[s] || sTID[s] = app.stringIDToTypeID(s); };
          // reset;
          app.preferences.rulerUnits = originalRulerUnits;
          return theArray;
          };
          
          1 person found this helpful
          • 2. Re: Point coordinates using for loop w/o closure problem?
            Steven Mathisen Level 1

            Mostly fumbling my way through learning .js better as I move from actions to scripts. What I'm building towards is a final script that counts the points, stores the relative x/y coordinates for that point, and assigns it num value via the array for later access. From there I want to then filter/constrain the points within some different x/y coordinate ranges and either make a selection off of those point values, or duplicate a closed path with only those constrained values constructing it...whichever executes faster and easier.

             

            That's a bit of script to digest, so I'll take a look at it and see if it's what I need. Thanks so much for the response! It's a struggle to learn some of these closure issues in .js off of tutorials built for browser based .js. Just have not been able to figure out how to access and pass .anchor variables in a for loop.

            • 3. Re: Point coordinates using for loop w/o closure problem?
              c.pfaffenbichler Level 9

              I may still not follow – could you make it easier and post a sketch (edit: or screenshot) of what the path looks like now and what it is supposed to look like afterwards?

               

              So you don’t want to access the left- and right handles?

              • 4. Re: Point coordinates using for loop w/o closure problem?
                Steven Mathisen Level 1

                So this is just a hypothetical description, not what I'm working on.. but lets assume the bottom of the circular path falls with in the constraint range after we've fetched the points and captured their x/y vals without directional handles is fine, I don't think I need them but I may if we go the copy path approach, just not certain at this point.

                 

                Picture 4.png

                 

                I'l need the script to either make the selection from the subpath values captured within the constraint range or copy the path points within those ranges and close the path for making a selection, like below.

                Picture 5.png

                Hope this helps! Thanks again!

                • 5. Re: Point coordinates using for loop w/o closure problem?
                  c.pfaffenbichler Level 9

                  the bottom of the circular path falls with in the constraint range after we've fetched the points

                  How ist that range defined?

                  If it is numerical it might be easier to simply create a Path that contains an additional subPathItem set to Intersect.

                  pathIntersect.jpg

                  • 6. Re: Point coordinates using for loop w/o closure problem?
                    Steven Mathisen Level 1

                    Constraint range will be defined by the lowest points on the path and two or three of it's nearest neighbors, without ascending out of the constraint region. However it may need to be factored against the overall height of the path, and width (lowest, highest x/y ranges) to get these specific areas I need, it's hard for me to say at this time without testing outputs. Shapes are slightly irregular so there is an angle I need to account for at a later stage, that probably is visually closer to this actually.

                     

                     

                    Picture 8.png

                    So the tricky part is to access those points and their values for me. I just have not been able to get anchor capture/iteration to work. Always the last x/y value. I do like the path intersection idea, that or a selection box like this is definitely what I'm going for.

                    • 7. Re: Point coordinates using for loop w/o closure problem?
                      c.pfaffenbichler Level 9

                      The height of a path is not necessarily determined by its points, alas.

                       

                      This function should get you the anchors, but in some cases subPathItems will not represent all separate segments.

                       

                      function collectPathPoints (myDocument, thePath) {

                      var originalRulerUnits = app.preferences.rulerUnits;

                      app.preferences.rulerUnits = Units.POINTS;

                      var theArray = [];

                      for (var b = 0; b < thePath.subPathItems.length; b++) {

                           theArray[b] = [];

                           for (var c = 0; c < thePath.subPathItems[b].pathPoints.length; c++) {

                                var pointsNumber = thePath.subPathItems[b].pathPoints.length;

                                var theAnchor = thePath.subPathItems[b].pathPoints[c].anchor;

                                theArray[b][c] = theAnchor;

                                };

                           var theClose = thePath.subPathItems[b].closed;

                           theArray = theArray.concat(String(theClose))

                           };

                      app.preferences.rulerUnits = originalRulerUnits;

                      return theArray

                      };

                      • 8. Re: Point coordinates using for loop w/o closure problem?
                        Steven Mathisen Level 1

                        Very true, about the height but I can have a close enough value with the top defining point for that part. Thankfully I know that I'll always be on subpathItem[0] as it is the first subpath created in these files, so it should define the entire segment I need as any intersections are put down afterwards.

                         

                        Thank you so much for the help!!! I'll have to try that code late tonight or tomorrow, but will get back to you then!

                        • 10. Re: Point coordinates using for loop w/o closure problem?
                          Steven Mathisen Level 1

                          Should have time to start testing it late today, but by the architecture I can tell it's what I'm looking for. Passing the anchor values with the count and dealing with the loop's scope proved too much for my knowledge level. Been buried under a bunch of other projects lately, but I should be able to patch this into a log report and investigate the capture reports and get back to you later tonight.

                          • 11. Re: Point coordinates using for loop w/o closure problem?
                            Steven Mathisen Level 1

                            Gave it a test and it works beautifully, but now I'm having another issue with sorting the values. I updated the return statement to breakout the values I needed, while rounding, but I am finding I can't use .sort() as a function on this.

                             


                            rndAnchorX = Math.round(theAnchor[0]*100)/100;

                            rndAnchorY = Math.round(theAnchor[1]*100)/100;

                            log.write("Path: " + b + " Point " + c + " X-Coord: " + rndAnchorX + "\n");

                            log.write("Path: " + b + " Point " + c + " Y-Coord: " + rndAnchorY + "\n");

                             

                             

                            Any suggestions on how I could address this? Ultimately I need to constrain different point ranges to then act upon differently.

                            • 12. Re: Point coordinates using for loop w/o closure problem?
                              c.pfaffenbichler Level 9

                              Why are you trying to use »write«?

                              Can’t you store the rounded points as an Array of Arrays with two numbers?

                              Or you could round the coordinated in the function that collects them right away.

                               

                              And sorry if you explained that already, but what is the ultimate result going to be – a Path, a Layer, a Vector Mask for an existing Layer, …?