Copy link to clipboard
Copied
Hello,
I've had trouble finding how to access the PathPoint positions today.
Apparently, the correct way to do it is by writing something like this: app.activeDocument.pathItems[itemIndex].pathPoints[pointIndex]
Which makes sense (pathPoints is an array) and it works fine and everything. Great.
Now why in the Illustrator Scripting Reference - JavaScript (CC 2015) PDF, page 138, this method is suggested: index(itemKey), type:number, returns:PathPoint, "Gets an element from the collection."?
I've tried using it and the only thing I got is this error message "app.activeDocument.pathItems[0].pathPoints.index is not a function" (with pathPoints.index(0) for example) which leads me to believe that there is no index method in the API... Is this correct or am I simply being very dumb and not using the method properly?
The reason I'm taking the time to write about this is because it seems I'm not the only one having this issue:
https://forums.adobe.com/thread/440700
EDIT:
Also, it seems pathPoints[pointIndex] works, but PathPoints[pointIndex], as it is written in the guide, doesn't.
I don't think that'd work because it's taking an anchor properties and trying to re-destribute them? I think a more manual approach of collecting each of the pathPoints into an array, re-ordering them, and building a new path via setEntirePath out of them.
Copy link to clipboard
Copied
Perhaps the PDF guide is inferior to the OMV, because I do not see the index method when looking at PathPoints in the OMV.
Copy link to clipboard
Copied
I don't see any index method for pathPoints either so I guess this is a mistake in the guide (one which made me lose quite a bit of time unfortunately).
In any case I didn't know about this OMV window. This should be very helpful in the future, thanks.
I'm having another problem/limitation where I would like to append new points to my pathPoints array but I need to be able to choose the position in the array where my [x,y] are inserted.
By default, when I use "var newPoint = pathItem.pathPoints.add();" and then "newPoint.anchor = [xVal, yVal];" the new [x,y] array is always added at the end of the pathPoints array and there is no argument available for this method where I could specify at which index in my array I would like my new point to be inserted.
So I suppose I will have to write a function to move [x,y] from the end of the array to the position I want it to be, which happens after it has already been added to the array, which seems pretty inefficient and time-consuming to me.
Is there a better/cleaner way to this? It would be much easier and logical if there was an argument for the add() method to specify where to insert the new item, no?
Copy link to clipboard
Copied
"doc.pathItems[0].pathPoints.splice is not a function"
So apparently, and even when you can access the points with pathPoints[pointIndex], pathPoints is considered an object, not an array (alert(String(typeof(doc.pathItems[0].pathPoints))); returns "object").
So maybe that's why I can't use the splice method on it, which would mean I can't reorder the pathPoint located in pathPoint at all?
Any tips on that?
Copy link to clipboard
Copied
From what I have gathered so far, the Illustrator (or Adobe) object collections such as layers, pathItems, groupItems, etc., are array-like objects which are actually not arrays, and have to be used custom functions on. I think, sometimes, I am able to perform my array-specific operations (again, only when specific needs are there, not generic) by making an own array and pushing all of the (or specific) members of the Illustrator collection into it.
Also, I learned that you can't use prototypes to add onto the native Illustrator classes. I am not sure if this is true, I would like to know more. It would be nice, for instance in this case, to do something like pathPoints.insertAfter(index).
Copy link to clipboard
Copied
It would be very nice indeed!
On the other hand the length method works very well on pathPoints. This is strange.
And I can't edit it but in my last message, the correct sentence is "I can't reorder the pathPoint located in pathPoints at all".
Anyway, I've tried storing the positions in my own intermediate array like your suggested but I still get a message highlighting lines 15 and 19 and telling me that "undefined is not an object".
Code below:
if ( app.documents.length > 0 ) {
var doc = app.activeDocument;
var line = doc.pathItems.add();
line.stroked = true;
line.setEntirePath( Array( Array(220, -475), Array(375, -300) ) );
var newPoint = doc.pathItems[0].pathPoints.add();
newPoint.anchor = Array(220, -300);
newPoint.leftDirection = newPoint.anchor;
newPoint.rightDirection = newPoint.anchor;
newPoint.pointType = PointType.CORNER;
var myArray = [];
for (i=0; i < doc.pathItems[0].pathPoints.length; i++) {
myArray = doc.pathItems[0].pathPoints.anchor;
}
alert(String(myArray));
myArray = myArray.splice(1, 0, myArray.splice(doc.pathItems[0].pathPoints.length, 1)[0]);
alert(String(myArray));
for (i=0; i < doc.pathItems[0].pathPoints.length; i++) {
doc.pathItems[0].pathPoints.anchor = myArray
}
}
(to avoid mistakes, lines 1 to 11 are an example from the scripting guide)
Copy link to clipboard
Copied
I don't think that'd work because it's taking an anchor properties and trying to re-destribute them? I think a more manual approach of collecting each of the pathPoints into an array, re-ordering them, and building a new path via setEntirePath out of them.
Copy link to clipboard
Copied
OK so I tried collecting pathPoint instead of pathPoint.anchor but this doesn't work with setEntirePath(myArray) ("illegal argument error") since setEntirePath() needs an array of [x, y], and not an array of pathPoint. So I went back to pathPoint.anchor, made a prototype to simplify things up/avoid mistakes and used setEntirePath to re-attribute the points like you suggested, and it works! Thanks a lot Silly-V!
Correct code:
Array.prototype.move = function (from, to) {
this.splice(to, 0, this.splice(from, 1)[0]);
return this;
};
if ( app.documents.length > 0 ) {
var doc = app.activeDocument;
var line = doc.pathItems.add();
line.stroked = true;
line.setEntirePath( Array( Array(220, -475), Array(375, -300) ) );
var newPoint = doc.pathItems[0].pathPoints.add();
newPoint.anchor = Array(220, -300);
newPoint.leftDirection = newPoint.anchor;
newPoint.rightDirection = newPoint.anchor;
newPoint.pointType = PointType.CORNER;
var myArray = [];
for (i=0; i < doc.pathItems[0].pathPoints.length; i++) {
myArray = doc.pathItems[0].pathPoints.anchor;
}
alert(String(myArray[2]));
myArray = myArray.move(2,0);
alert(String(myArray[2]));
doc.pathItems[0].setEntirePath(myArray);
}
}
Now when I include this bit in one of the functions of my script the line 2, where the splice method is called, is highlighted and I get the error "undefined is not an object", which is not the case with the code above, even when prototype is the exact same. What am I missing here?
Here is the function I'm having problems with:
Array.prototype.move = function (from, to) {
this.splice(to, 0, this.splice(from, 1)[0]);
return this;
};
function divideSegment(pathItem, pStart, pEnd, divideBy) {
var xOperator;
var yOperator;
var xDiff = Math.abs(pStart[0] - pEnd[0]);
var yDiff = Math.abs(pStart[1] - pEnd[1]);
if (pStart[0] < pEnd[0]) { xOperator = 1; } else { xOperator = -1; };
if (pStart[1] < pEnd[1]) { yOperator = 1; } else { yOperator = -1; };
for (i = 0 ; i< divideBy-1; i++) {
var fraction = i/(divideBy-1);
var xVal = pStart[0] + xOperator*fraction*xDiff;
var yVal = pStart[1] + yOperator*fraction*yDiff;
var newPoint = pathItem.pathPoints.add();
newPoint.anchor = [xVal, yVal];
newPoint.leftDirection = newPoint.anchor;
newPoint.rightDirection = newPoint.anchor;
newPoint.pointType = PointType.CORNER;
var myArray = [];
for (i=0; i < pathItem.pathPoints.length; i++) {
myArray = pathItem.pathPoints.anchor;
}
myArray = myArray.move(pathItem.pathPoints.length,0);
pathItem.setEntirePath(myArray);
}
}
if (app.documents.length > 0) {
var doc = app.activeDocument;
var ellipseSize = 100.0;
var hex1 = doc.pathItems.polygon(doc.width/2, -doc.height/2, ellipseSize/2, 6);
hex1.rotate(90);
divideSegment(hex1, hex1.pathPoints[0].anchor, hex1.pathPoints[1].anchor, 6);
}
Copy link to clipboard
Copied
Hmm, if you are moving something with an index of pathPoints.length, that index will be higher than possible. For example, you would not be able to move something with index of 11 in an 11-member collection, because the first item is at index 0, and last index is 10.
Try to use pathPoints.length-1 is your from-index.
Copy link to clipboard
Copied
Perhaps you can play with this:
if ( app.documents.length > 0 ) {
var doc = app.activeDocument;
var line = doc.pathItems.add();
line.stroked = true;
line.setEntirePath( Array( Array(220, -475), Array(375, -300) ) );
var newPoint = doc.pathItems[0].pathPoints.add();
newPoint.anchor = Array(220, -300);
newPoint.leftDirection = newPoint.anchor;
newPoint.rightDirection = newPoint.anchor;
newPoint.pointType = PointType.CORNER;
var myArray = [];
var myPType = [];
var myPleft = [];
var myPright = [];
for (i=0; i < doc.pathItems[0].pathPoints.length; i++) {
myArray = doc.pathItems[0].pathPoints.anchor;
myPType = doc.pathItems[0].pathPoints.pointType;
myPleft = doc.pathItems[0].pathPoints.leftDirection;
myPright = doc.pathItems[0].pathPoints.rightDirection;
}
doc.pathItems[0].pathPoints.add();
var myArr = [100,150];
var myTP = PointType.CORNER;
var myTl = myArr;
var myTr = myArr;
myArray.splice(1, 0, myArr);
myPType.splice(1, 0, myTP);
myPleft.splice(1, 0, myTl);
myPright.splice(1, 0, myTr);
for (i=doc.pathItems[0].pathPoints.length-1; i >=0; i--) {
doc.pathItems[0].pathPoints.anchor = myArray;
doc.pathItems[0].pathPoints.pointType = myPType;
doc.pathItems[0].pathPoints.leftDirection = myPleft;
doc.pathItems[0].pathPoints.rightDirection = myPright;
}
}
Copy link to clipboard
Copied
Thanks a lot Silly-V, that was a stupid mistake. My script is now fully completed thanks to you!
pixxxel schubser, thanks this is very heplful! I understand now why I couldn't use splice on the whole pathPoints array/object.
If anyone's interested, here's a reusable function based on pixxxel schubser last message, though setEntirePath works fine too if you don't want to deal with control points:
if (app.documents.length > 0) {
var doc = app.activeDocument;
var line = doc.pathItems.add();
line.stroked = true;
line.filled = false;
line.setEntirePath([[200, -200], [600, -200]]);
var newPAnchor = [400, -400]
insertInPath(doc.pathItems[0], newPAnchor, newPAnchor, newPAnchor, PointType.CORNER, 1, 0);
}
// add a new point in a path at the specified index (or replace a preexisting point if spliceDeleteCount is set to 1)
function insertInPath(pathItem, pAnchor, pCtrlL, pCtrlR, pType, spliceAtIndex, spliceDeleteCount) {
// initialize temporary arrays
var iAnchor = [];
var iCtrlL = [];
var iCtrlR = [];
var iType = [];
// fill temporary arrays so they are equivalent to the current pathItem's arrays
for (i=0; i < pathItem.pathPoints.length; i++) {
iAnchor = pathItem.pathPoints.anchor;
iCtrlL = pathItem.pathPoints.leftDirection;
iCtrlR = pathItem.pathPoints.rightDirection;
iType = pathItem.pathPoints.pointType;
}
// add a point at the end of pathItem's arrays to increase their lenghts by one
pathItem.pathPoints.add();
// insert the point properties at the correct index in the temporary arrays
iAnchor.splice(spliceAtIndex, spliceDeleteCount, pAnchor);
iCtrlL.splice(spliceAtIndex, spliceDeleteCount, pCtrlL);
iCtrlR.splice(spliceAtIndex, spliceDeleteCount, pCtrlR);
iType.splice(spliceAtIndex, spliceDeleteCount, pType);
// replace the values of pathItem's arrays with the values from the temporary arrays
for (i=pathItem.pathPoints.length-1; i >=0; i--) {
pathItem.pathPoints.anchor = iAnchor;
pathItem.pathPoints.leftDirection = iCtrlL;
pathItem.pathPoints.rightDirection = iCtrlR;
pathItem.pathPoints.pointType = iType;
}
}
Copy link to clipboard
Copied
klts wrote: If anyone's interested, here's a reusable function "insertInPath"
Nice job. Just curious, what is it you are creating and / or using this for ?
Copy link to clipboard
Copied
W_J_T schrieb:
… Just curious, what is it you are creating and / or using this for ?
An interesting question.
W_J_T schrieb:
Nice job …
Hmmh?
Really?
A very good feedback.
Yes.
Really I like it, particularly the description.
But a good job? …
… This is the same code, that I've posted before (but only with description, with renamed variables and packed into a function)
And a little bit I miss the source or the origin or the repository (what is the correct word for this?) in the code itself.
Copy link to clipboard
Copied
Edit: Oops!
Sorry, pixxxel schubser I was just glancing through the thread, good job to you.
Speaking of repositories, do you have one? I always love looking at you code / snippets, there is always something good in your posts. Link to your code repository for perusing? 😉
Copy link to clipboard
Copied
Yes, I only renamed and reordered the variables and added comments so it makes more sense (mostly to me) if and when I need to use it later.
Sorry pixxxel schubser, I though saying it was based on your code was enough. For the next time what comment do you think I should put in the function for pointing to the source?
A link to this thread, something like "function by pixxxel schubser", both or something else? I'm still new to scripting so I'm not familiar with these customs.
I can't edit a previous post once somebody has answered to it right?
W_J_T, the script I made is used to generate geometric shapes and patterns by selecting a seed and inputing the number of iterations in a prompt box (possibly thousands of shapes, very time-consuming to do by hand). The objects which paths get subdivided (this is where I needed to reorder vertices) are actually "guide objects" used to generated other shapes and are then discarded afterwards.
I know there is a script named Divide (length) by shspage which does the subdivision and much more, but I did this project mostly to get better at scripting and copying someone else's code doesn't really help much with that. And to be honest, I'm finally taking a look at it now, and even after Silly-V and pixxxel schubser explanations I still can't figure out his for loops in the applyData2Path and applyData2AfterIdx functions. I'll have to take more time to read the entire thing later.
Copy link to clipboard
Copied
Yes that type of script reference is always good, with both.
klts wrote:
W_J_T, the script I made is used to generate geometric shapes and patterns by selecting a seed and inputing the number of iterations in a prompt box (possibly thousands of shapes, very time-consuming to do by hand). The objects which paths get subdivided (this is where I needed to reorder vertices) are actually "guide objects" used to generated other shapes and are then discarded afterwards.
That sounds really interesting, are you planning on posting the final code somewhere? I would love to see the outcome.
Copy link to clipboard
Copied
Yes I would like to release it at some point but not right now. I'm pretty sure there's quite a few things I will be able to do better when I'll have a bit more experience with scripting. Things like a proper UI panel and progress bar (which doesn't update correctly right now), good/useful variable names and comments, there's also a crash when you ask for too many iterations that I haven't find how to fix yet.
But if you can give me some feedback on the code I can send you what I have right now which is functional and achieve its purpose, even though I'd like to add more features and polish things up a bit in the future. I just don't want to post it here as if it was a finished product because it's not.
Copy link to clipboard
Copied
for sake of completeness, indeed the Index() function in Javascript seems to be broken...and the documentation is wrong (surprise).
the good news (sort of) is that this function does work in VB...and it's properly documented (surprise again!)
Copy link to clipboard
Copied
W_J_T schrieb:
… Speaking of repositories, do you have one? I always love looking at you code / snippets, there is always something good in your posts. Link to your code repository for perusing? 😉
Sorry, I only have my own snippet libraries here at home (and the knowledge base in my head ) – but not online. Most of them I wrote here in Forum is based on that.
klts schrieb:
…For the next time what comment do you think I should put in the function for pointing to the source?
A link to this thread, something like "function by pixxxel schubser", both or something else? I'm still new to scripting so I'm not familiar with these customs.
If I use snippets or parts of scripts, written by others (and you cannot find exactly this part „at every corner in the www“) then it's a good way to do something like this.
Show the source:
// https://forums.adobe.com/message/7759845#7759845
// script (or part of script) written by author (no matter if real name or nick name)
Or you can also use a phrase like this:
// ---------------------
// based on function (or on code) by author
… your adapted code
// ---------------------
But don't worry. All is ok
Have fun