Skip to main content
Participating Frequently
August 30, 2024
Answered

Rotate the selected layer according to the layer below

  • August 30, 2024
  • 3 replies
  • 2433 views

First fit the selected layer according to the layer below then rotate the selected layer according to the position the layer below is rotated.

 

// Set ruler units to pixels
var oldPref = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;

// Get active document and layers
var doc = activeDocument;
var iLayer = doc.activeLayer;

// Function to select the layer below
function layerDown() {
var idslct = charIDToTypeID("slct");
var desc2 = new ActionDescriptor();
var idnull = charIDToTypeID("null");
var ref1 = new ActionReference();
var idLyr = charIDToTypeID("Lyr ");
var idOrdn = charIDToTypeID("Ordn");
var idBckw = charIDToTypeID("Bckw");
ref1.putEnumerated(idLyr, idOrdn, idBckw);
desc2.putReference(idnull, ref1);
executeAction(idslct, desc2, DialogModes.NO);
}

// Call the function to select the layer below
layerDown();

// Get the bounds of the layer below
var mLayerB = doc.activeLayer.bounds;

// Fit the selected layer according to the layer below
var scale = Math.max((mLayerB[2] - mLayerB[0]) / (iLayer.bounds[2] - iLayer.bounds[0]), (mLayerB[3] - mLayerB[1]) / (iLayer.bounds[3] - iLayer.bounds[1]));
iLayer.resize(scale * 100, scale * 100);
iLayer.translate((mLayerB[0] + mLayerB[2]) / 2 - (iLayer.bounds[0] + iLayer.bounds[2]) / 2, (mLayerB[1] + mLayerB[3]) / 2 - (iLayer.bounds[1] + iLayer.bounds[3]) / 2);

// Function to get the rotation angle of a layer
function getLayerRotation(layer) {
var idslct = charIDToTypeID("slct");
var desc = new ActionDescriptor();
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
desc.putReference(charIDToTypeID("null"), ref);
var result = executeAction(charIDToTypeID("getd"), desc, DialogModes.NO);

var rotation = 0;
if (result.hasKey(stringIDToTypeID("transform"))) {
var transform = result.getObjectValue(stringIDToTypeID("transform"));
if (transform.hasKey(stringIDToTypeID("rotation"))) {
rotation = transform.getDouble(stringIDToTypeID("rotation"));
}
}
return rotation;
}

// Get the rotation of the layer below
var mLayerRotation = getLayerRotation(doc.activeLayer);

// Function to rotate the layer
function rotateLayer(layer, angle) {
var idtrns = charIDToTypeID("Trnf");
var desc = new ActionDescriptor();
var idnull = charIDToTypeID("null");
var ref = new ActionReference();
ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
desc.putReference(idnull, ref);

var idtarg = charIDToTypeID("TlrP");
var desc2 = new ActionDescriptor();
desc2.putUnitDouble(charIDToTypeID("Angl"), charIDToTypeID("#Ang"), angle);
desc.putObject(idtarg, idtrns, desc2);

executeAction(idtrns, desc, DialogModes.NO);
}

// Rotate the selected layer to match the layer below
rotateLayer(iLayer, mLayerRotation);

// Restore the original ruler units
app.preferences.rulerUnits = oldPref;

This topic has been closed for replies.
Correct answer c.pfaffenbichler

https://youtu.be/QZoYYLSABVs?si=kJf1onjcRinp007W 

Sir this is a common problem. This problem occurs because the layer height size and layer width size are not fixed. Space is left above and below the level. The level does not fit. This space should not be left. The top and bottom layers should fit. It doesn't matter if the left and right sides of the side don't fit.


 

// rotate, scale and move layer according to smart object immediately below;
// 2024, use it at your own risk;
if (app.documents.length > 0) {
var originalRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
// check for background layer;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if (desc.getBoolean(stringIDToTypeID("hasBackgroundLayer")) == true) {var theAdd = -1}
else {var theAdd = 0};
// get the index;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var layerDesc = executeActionGet(ref);
var theIndex = layerDesc.getInteger(stringIDToTypeID('itemIndex'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
// the angles;
var currentAngle = getAngleOfLayer ();
selectLayerByIndex(theIndex + theAdd - 1, false);
var theAngle = getAngleOfLayer ();
selectLayerByIndex(theIndex + theAdd, false);
if (currentAngle != undefined && theAngle != undefined) {
// determine scale:
if (theAngle[3]/theAngle[4] > currentAngle[3]/currentAngle[4]) {
var theScale = theAngle[3]/currentAngle[3]*100
} else {
var theScale = theAngle[4]/currentAngle[4]*100
};
// rotate;
layerDuplicateScaleRotate (theID, false, theAngle[1] - currentAngle[1], theAngle[2] - currentAngle[2], theScale, theScale, theAngle[0] - currentAngle[0]);
};
// reset;
app.preferences.rulerUnits = originalRulerUnits;
};
////////////////////////////////////
////// get angle //////
function getAngleOfLayer () {
try {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var layerDesc = executeActionGet(ref);
var theName = layerDesc.getString(stringIDToTypeID('name'));
var soDesc = layerDesc.getObjectValue(stringIDToTypeID('smartObject'));
var soMoreDesc = layerDesc.getObjectValue(stringIDToTypeID('smartObjectMore'));
var placedDesc = soDesc.getEnumerationValue(stringIDToTypeID('placed'));
var theFileRef = soDesc.getString(stringIDToTypeID('fileReference'));
var theDocID = soDesc.getString(stringIDToTypeID('documentID'));
var size = soMoreDesc.getObjectValue(stringIDToTypeID('size'));
var transform = soMoreDesc.getList(stringIDToTypeID("transform"));
var xx = new Array;
for (var m = 0; m < transform.count; m++) {
xx.push(transform.getDouble(m))
};
var nonAffineTransform = soMoreDesc.getList(stringIDToTypeID("nonAffineTransform"));
var yy = new Array;
for (var n = 0; n < nonAffineTransform.count; n++) {
yy.push(nonAffineTransform.getDouble(n))
};
var theX = yy[0] + (yy[4] - yy[0])/2;
var theY = yy[1] + (yy[5] - yy[1])/2;
var theWidth = getDistance([yy[0], yy[1]], [yy[2], yy[3]]);
var theHeight = getDistance([yy[0], yy[1]], [yy[6], yy[7]]);
return [getAngle([yy[6], yy[7]], [yy[4], yy[5]]), theX, theY, theWidth, theHeight]
} catch (e) {return undefined}
};
////// radians //////
function radiansOf (theAngle) {
return theAngle * Math.PI / 180
};
////// get an angle, 3:00 being 0˚, 6:00 90˚, etc. //////
function getAngle (pointOne, pointTwo) {
// calculate the triangle sides;
var width = pointTwo[0] - pointOne[0];
var height = pointTwo[1] - pointOne[1];
var sideC = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); 
// calculate the angles;
if (width+width > width) {theAngle = Math.asin(height / sideC) * 360 / 2 / Math.PI}
else {theAngle = 180 - (Math.asin(height / sideC) * 360 / 2 / Math.PI)};
if (theAngle < 0) {theAngle = (360 + theAngle)};
//	if (theAngle > 180) {theAngle = (360 - theAngle) * (-1)};
return theAngle
};
// by mike hale, via paul riggott;
function selectLayerByIndex(index,add){ 
try{
add = undefined ? add = false:add 
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("Lyr "), index);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) ); 
desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
//try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message); 
}
};
////// duplicate layer (id, xOffset, yOffset, theXScale, theYScale, theAngle) //////
function layerDuplicateScaleRotate (theID, theDuplicate, xOffset, yOffset, theXScale, theYScale, theAngle) {
// based on code by mike hale, via paul riggott;
var ref = new ActionReference();
ref.putIdentifier(charIDToTypeID("Lyr "), theID);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
desc.putBoolean( charIDToTypeID( "MkVs" ), false ); 
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message); 
};
// =======================================================
var desc23 = new ActionDescriptor();
var idnull = charIDToTypeID( "null" );
var ref2 = new ActionReference();
ref2.putIdentifier ( charIDToTypeID( "Lyr " ), theID );
//        ref2.putEnumerated( charIDToTypeID( "Lyr " ), charIDToTypeID( "Ordn" ), charIDToTypeID( "Trgt" ) );
desc23.putReference( idnull, ref2 );
desc23.putEnumerated( charIDToTypeID( "FTcs" ), charIDToTypeID( "QCSt" ), charIDToTypeID( "Qcsa" ) );
var idOfst = charIDToTypeID( "Ofst" );
var desc24 = new ActionDescriptor();
var idPxl = charIDToTypeID( "#Pxl" );
desc24.putUnitDouble( charIDToTypeID( "Hrzn" ), idPxl, xOffset );
desc24.putUnitDouble( charIDToTypeID( "Vrtc" ), idPxl, yOffset );
var idOfst = charIDToTypeID( "Ofst" );
desc23.putObject( idOfst, idOfst, desc24 );
var idPrc = charIDToTypeID( "#Prc" );
desc23.putUnitDouble( charIDToTypeID( "Wdth" ), idPrc, theXScale );
desc23.putUnitDouble( charIDToTypeID( "Hght" ), idPrc, theYScale );
desc23.putUnitDouble( charIDToTypeID( "Angl" ), charIDToTypeID( "#Ang" ), theAngle );
desc23.putEnumerated( charIDToTypeID( "Intr" ), charIDToTypeID( "Intp" ), stringIDToTypeID( "bicubicAutomatic" ) );
desc23.putBoolean( charIDToTypeID( "Cpy " ), theDuplicate );
executeAction( charIDToTypeID( "Trnf" ), desc23, DialogModes.NO );
};
////// get a distance between two points //////
function getDistance (pointOne, pointTwo) {
// calculate the triangle sides;
var width = pointTwo[0] - pointOne[0];
var height = pointTwo[1] - pointOne[1];
var sideC = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); 
return sideC
};

 

3 replies

c.pfaffenbichler
Community Expert
Community Expert
September 28, 2024

There was a mistake indeed; I updated the code, please try again. 

c.pfaffenbichler
Community Expert
Community Expert
September 24, 2024

And? 

Participating Frequently
September 25, 2024

This Line Error return [getAngle([yy[6], yy[7]], [yy[4], yy[5]]), theX, theY, theWidth, theHeight]

c.pfaffenbichler
Community Expert
Community Expert
September 25, 2024

Please provide the file for testing. 

c.pfaffenbichler
Community Expert
Community Expert
September 1, 2024

Could you please post screenshots with the pertinent Panels (Toolbar, Layers, Options Bar, …) visible? 

 

Is the lower Layer a Smart Object? If it is not, but rather a plain pixel Layer, the concept of »rotation« would not apply because the Bounds define a rectangle with vertical and horicontal sides. 

Participating Frequently
September 2, 2024
JPG.png
c.pfaffenbichler
Community Expert
Community Expert
September 4, 2024

This code can be used to determine the rotation of a selected Smart Object. 

// get keys for smart objects;
// based on code by michael l hale;
// 2024, use it at your own risk;
if (app.documents.length > 0) {
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
var layerDesc = executeActionGet(ref);
var soDesc = layerDesc.getObjectValue(stringIDToTypeID('smartObject'));
var soMoreDesc = layerDesc.getObjectValue(stringIDToTypeID('smartObjectMore'));
var placedDesc = soDesc.getEnumerationValue(stringIDToTypeID('placed'));
var theFileRef = soDesc.getString(stringIDToTypeID('fileReference'));
var theDocID = soDesc.getString(stringIDToTypeID('documentID'));
var size = soMoreDesc.getObjectValue(stringIDToTypeID('size'));
//checkDesc2 (soMoreDesc);
var transform = soMoreDesc.getList(stringIDToTypeID("transform"));
var xx = new Array;
for (var m = 0; m < transform.count; m++) {
xx.push(transform.getDouble(m))
};
//alert ("transform\n"+xx.join("\n\n")+"\n\nangle "+getAngle([xx[0], xx[1]], [xx[2], xx[3]]));
var nonAffineTransform = soMoreDesc.getList(stringIDToTypeID("nonAffineTransform"));
var yy = new Array;
for (var n = 0; n < nonAffineTransform.count; n++) {
yy.push(nonAffineTransform.getDouble(n))
};
alert ("nonaffinetransform\n"+yy.join("\n\n")+"\n\nangle "+getAngle([yy[6], yy[7]], [yy[4], yy[5]]));
};
//////
////// radians //////
function radiansOf (theAngle) {
return theAngle * Math.PI / 180
};
////// get an angle, 3:00 being 0˚, 6:00 90˚, etc. //////
function getAngle (pointOne, pointTwo) {
// calculate the triangle sides;
var width = pointTwo[0] - pointOne[0];
var height = pointTwo[1] - pointOne[1];
var sideC = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)); 
// calculate the angles;
if (width+width > width) {theAngle = Math.asin(height / sideC) * 360 / 2 / Math.PI}
else {theAngle = 180 - (Math.asin(height / sideC) * 360 / 2 / Math.PI)};
if (theAngle < 0) {theAngle = (360 + theAngle)};
//	if (theAngle > 180) {theAngle = (360 - theAngle) * (-1)};
return theAngle
};