How to rotate all items as a group? (In a script, Illustrator)

I have an SVG with a few curved paths. I'd like to create n versions of this, by rotating them around as a group (360 / n degrees apart), around the center of the square-shaped canvas they're in, like this: Then, I'd like to save these into separate SVG files.

Based on some initial research, this should be possible in Illustrator. However, I can't even get it to rotate all objects as a group, I can only rotate each object around its center with:

doc = app.activeDocument;
sel = doc.pageItems;
for (var i = 0; i < sel.length; i++) {
sel[i].rotate(30);
}

How could I do this? (I'm also open to any software alternative.)

• Just group all the items before rotating. See my answer to Rotating a layer around centre and save file (72 times)
– Cai
May 26 '17 at 12:54
• Use matrix manipulation! May 26 '17 at 13:44
• @Cai - So how do you group all items? I failed to find this on Google before and I can't seem to find it in your other answer either. May 26 '17 at 14:34
• You're right actually, I just said in comments of my other answer to group first (I meant in AI itself, not in the script, just select all and cmd/ctrl+G)... Do you need to do this with a number of SVGs or just the one? If it's only one then grouping in AI manually is easy enough
– Cai
May 26 '17 at 14:36

Quick primer into computer graphics programming. Whenever you are trying to do a compound transform it is best to compose the transform onto a matrix operation. Mainly because you can specify a complex transformation in one go.

OK so no we have to compute the bounds. But then you might rotate around a arbitrary point in some case too (this makes it easy).

#target illustrator

var doc = app.activeDocument;
var sel = doc.pageItems;
var bounds = calculate_bounds(sel);
var center = [(bounds+bounds)/2,
(bounds+bounds)/2]

for (var i = 0; i < sel.length; i++) {
rotate_around_global_pos(sel[i], 30, center);
}

/********* Support functions *********/

function rotate_around_global_pos(obj, ang, pos) {
var rot = app.getRotationMatrix(15);
var mov = app.getTranslationMatrix(pos, pos);
var inv = app.invertMatrix(mov);
var mtx = app.concatenateMatrix(inv, rot);
var mtx = concatenateMatrix(mtx, mov);

obj.transform(mtx, 1, 1, 1, 1, 1, Transformation.DOCUMENTORIGIN);
}

function calculate_bounds(sel){
var minX = Number.POSITIVE_INFINITY;
var maxX = Number.NEGATIVE_INFINITY;
var minY = Number.POSITIVE_INFINITY;
var maxY = Number.NEGATIVE_INFINITY;

for (i = 0; i < sel.length; i++){
var item = sel[i];
var bounds = sel[i].controlBounds;

minX = Math.min( minX, bounds, bounds );
maxX = Math.max( maxX, bounds, bounds );
minY = Math.min( minY, bounds, bounds );
maxY = Math.max( maxY, bounds, bounds );
}
return [maxX, maxY, minX, minY];
}
• Thanks! The matrix-based rotation around an arbitrary point is exactly what I needed. I wanted to rotate around the center of the canvas (not the bounding rect of the object group) and export after each rotation, but changing this and combining with Cai's code in the other question yields the perfect result. I'll post my code in a minute. (Also, the first line of the rotate_around_global_pos function should be var rot = app.getRotationMatrix(ang); I think.) Jun 1 '17 at 22:01

You could always record an action on one file (Window > Actions) and then run the rest as a batch using that action...

I did a test creating, saving out the first group and then rotating and saving out 7 copies... and it worked just fine: Here is my action so you can see how I did it: • Thanks! This is probably the best way to do it using Actions. However, the reason I turned to the scripting approach is so that n as a parameter could be changed, and the rotation angle and output filenames would be automatically generated. (If n was changed to 100 instead of 8, you'd need to change the angle and do 92 Transform Again / Save As steps again manually.) May 29 '17 at 17:05

Combining joojaa's matrix manipulation and Cai's SVG exporting loop, I ended up with this script:

#target illustrator

var doc = app.activeDocument;
var docDir = ( doc.path != '' ) ? doc.path : '~';

var n = 20,
iterations = n - 1,
angle = 360 / n,
destFolder = 'rotated'; // output files are saved in this subfolder

rotateAndExport();

function rotateAndExport() {
var pos = [doc.width / 2, doc.height / 2];
var layer = doc.layers;
exportFile(1); // save the original file into the output folder
for ( var r = 0; r < iterations; r++ ) {
for ( var j = 0; j < layer.pageItems.length; j++ ) {
var item = layer.pageItems[j];
rotate_around_global_pos(item, -angle, pos);
}
exportFile(r + 2);
}
}

if (number <= 9) number = "0" + number;
return number;
}

function exportFile( iteration ) {
// create folder if it doesn't exist
var destPath = docDir + '/' + destFolder;
if ( false == Folder( destPath ).exists ) {
new Folder( destPath ).create();
}

// export options
var destFile;
var type;
var exportOptions;

var svgPath = destPath + '/';
destFile = new File( svgPath + '/output_' + pad(iteration) + ".svg");

type = ExportType.SVG;
exportOptions = new ExportOptionsSVG();
exportOptions.preserveEditability   = false;
exportOptions.embedRasterImages     = true;
exportOptions.embedAllFonts         = false;
exportOptions.encoding              = SVGDocumentEncoding.UTF8;
exportOptions.fontType              = SVGFontType.OUTLINEFONT;

doc.exportFile( destFile, type, exportOptions );
}

function rotate_around_global_pos(obj, ang, pos) {
var rot = app.getRotationMatrix(ang);
var mov = app.getTranslationMatrix(pos, pos);
var inv = app.invertMatrix(mov);
var mtx = app.concatenateMatrix(inv, rot);
var mtx = concatenateMatrix(mtx, mov);

obj.transform(mtx, 1, 1, 1, 1, 1, Transformation.DOCUMENTORIGIN);
}

This script creates a subfolder next to the file currently open, and saves n states, each of which are rotated clockwise with the same angle one after another. (The paths don't need to be grouped, and no additional rectangle needs to be added.)

If you are using an SVG file, you can open it in Adobe Illustrator. Then select all of your objects that you wish to rotate. Ctrl + A should do. Then right click and group them. Now, you can easily rotate them as one.

You can ungroup them later as well.

• Thank you for your answer, but I'm afraid you missed the 'script' part of my question. In my case, n > 1 (it's around 20), so I'd like to avoid doing this manually. May 26 '17 at 14:36

In addition to the answer by @Yash Sheth, your question does not need be scripted per se. You can perform it quite efficiently without. Illustrator has the 'transform again' function, (CMD or CTRL + D).

So, you could:

1. Group the items
2. Object --> Transform --> Rotate
3. Choose 360/n degress
4. Press 'Copy' (not APPLY)
5. Now, press CMD+D an n amount of times.

Additionally (though not tested), you could create a series of n equally spaced artboards, place the first 0º copy and the last 360º-360º/n copy on the first and last artboard, and use the 'distribute objects' functionality to place one copy on each artboard.Export each artboard individually.