
1. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Laubender May 6, 2016 11:40 PM (in response to Kasyan Servetsky)Hi Kasyan,
I don't know exactly what you expect with a horizontal translation.
The whole object will be moved by 50 pt in xdirection. As expected.Regardless of the anchor point you are choosing.
Uwe

2. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
tpk1982 May 7, 2016 12:20 AM (in response to Kasyan Servetsky)1 person found this helpful 
3. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Kasyan Servetsky May 8, 2016 8:35 AM (in response to Laubender)@Uwe No, the object is moved to x=50  not by 50 pt in xdirection
Here's an example to illustrate what I mean:
1. The starting point  a rectangle x=0, y=0, w=100, h=50  all measurements are in points.
2. Let's scale it by 50% using topleft anchor point.
main(); function main() { var doc = app.activeDocument; var obj = doc.rectangles[0]; var transMatrix = app.transformationMatrices.add({horizontalScaleFactor: 0.5}); obj.transform(CoordinateSpaces.PASTEBOARD_COORDINATES, AnchorPoint.TOP_LEFT_ANCHOR, transMatrix); }
The rectangle is scaled down relative to the topleft anchor point.
3. Now I change the anchor point to bottomright.
obj.transform(CoordinateSpaces.PASTEBOARD_COORDINATES, AnchorPoint.BOTTOM_RIGHT_ANCHOR, transMatrix);
And this time the rectangle is scaled down relative to the bottomright anchor point.
The change of the anchor point is respected by script.
Now let's play with translation (aka moving).
4. Let's move it horizontally to x = 50 using topleft anchor point.
main(); function main() { var doc = app.activeDocument; var obj = doc.rectangles[0]; var transMatrix = app.transformationMatrices.add({horizontalTranslation: 50}); obj.transform(CoordinateSpaces.PASTEBOARD_COORDINATES, AnchorPoint.TOP_LEFT_ANCHOR, transMatrix); }
So far so good: I get the same result as if I did in inDesign manually.
5. Now I change the anchor point to bottomright.
obj.transform(CoordinateSpaces.PASTEBOARD_COORDINATES, AnchorPoint.BOTTOM_RIGHT_ANCHOR, transMatrix);
However, I get the same result as before for the topleft anchor (the screenshot for step 4 above) no matter whichever anchor point I use. This problem happens only with horizontalTranslation and verticalTranslation.
I expect the result like so:
@tpk1982 I can't use the Marc's function as it is because it moves an object in both directions: X and Y. But I also need to move it only X and only Y. Trying to figure out how to adjust it to my needs but it seems to be beyond my level.
Anyway, thank you both.
Regards,
Kasyan 
4. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Trevorׅ May 8, 2016 11:49 PM (in response to Kasyan Servetsky)Hi Kasyan
The translation is relative to the current position of the object and therefore it's irrelevant which point you refer to.
Here's a quick experiment,
Stand with your heals against a wall. Measure 1 meter from the wall, mark that point and line up your heals to that point. Mark the point where your toes end.
Go back to the same wall. This time measure a meter from your toes. Mark that point and line up your toes with that mark. Mark the point where your heals start.
The 2 sets of 2 marks should line up.
I can't understand why you expect them to be different or whats the different between moving feet or a blue rectangle.
Same point that Uwe made above just a bit more verbose.
Regards
Trevor

5. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Laubender May 9, 2016 12:42 AM (in response to Trevorׅ)Thank you Trevor for chiming in.
After reading Kasyan's last reply I already wrapped my head around an alternative description what a horizontal translation is doing.
Now I came up with a sentence quoted from Wikipedia:
In function graphing, a horizontal translation is a transformation which results in a graph that is equivalent to shifting the base graph left or right in the direction of the xaxis.
That description usually can be seen as an equivalent for the move() method using the byargument.
I suppose it is not exactly the same, because of other factors due to the transformations a spread or a page has been undergone.
The xaxis defined implicitly in the transformation matrix may not be in parallel with the horizontal ruler.For that I have to reread Marc Autret's findings at:
Indiscripts :: Coordinate Spaces & Transformations in InDesign — Chap.13
Kasyan,
in case this is unclear:
1. If you want to change the proxy points in the UI for any reason, do it with the property transformReferencePoint of the layoutWindow.
2. The values for horizontal and vertical transformation in a transformation matrix are always expressed as points.
Regradless of the measurement systems set for the rulers.Uwe

6. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Kasyan Servetsky May 11, 2016 4:24 AM (in response to Trevorׅ)Hi guys,
Thank you for your feedback!
Probably I wasn’t clear enough about what I’m trying to do.
Here’s the script I’m writing.
The main idea is to find frames of a certain object style using a number of “conditions” and apply a number of transformations to them.
A condition may be either an exact value or a range of numbers; it can also be positive or negative – is/is not.
For example, in the screenshots above, I want to find frames with “My style” applied whose X position is 0 and Y is not 1020 and scale them down by 50% both horizontally and vertically using the topleft anchor point.
Now let’s see how I implemented this in code:
function TransformFrame(frame) { var transMatrix = null; try { if (set.cb_widthSet) { // Not implemented yet } if (set.cb_heightSet) { // Not implemented yet } if (set.cb_xSet) { // This doesn't work properly transMatrix = CatenateMatrix(transMatrix, "horizontalTranslation", set.xSet); } if (set.cb_ySet) { // This doesn't work properly transMatrix = CatenateMatrix(transMatrix, "verticalTranslation", set.ySet); } // The following part works as expected if (set.cb_xScaleSet) { transMatrix = CatenateMatrix(transMatrix, "horizontalScaleFactor", set.xScaleSet / 100); } if (set.cb_yScaleSet) { transMatrix = CatenateMatrix(transMatrix, "verticalScaleFactor", set.yScaleSet / 100); } if (set.cb_rotationSet) { transMatrix = CatenateMatrix(transMatrix, "counterclockwiseRotationAngle", set.rotationSet); } if (set.cb_skewSet) { transMatrix = CatenateMatrix(transMatrix, "clockwiseShearAngle", set.skewSet); } frame.transform(CoordinateSpaces.PASTEBOARD_COORDINATES, anchorPoint, transMatrix); } catch(err) { $.writeln(err.message + ", line: " + err.line); } } function CatenateMatrix(transMatrix, property, value) { if (transMatrix == null) { transMatrix = eval("app.transformationMatrices.add({" + property + ":" + value + "});"); } else { transMatrix = transMatrix.catenateMatrix(eval("app.transformationMatrices.add({" + property + ":" + value + "});")); } return transMatrix; }
If a check box is on, a new matrix is created for the parameter and is sent to the CatenateMatrix function which either creates a new matrix, if it doesn't exist yet, or catenates it with already existing one. At the end of the TransformFrame function all the transformations are applied in one go.
Here in the code the Set object gets parameters from the dialog box.
set.cb_xSet  the 'set X' check box is on/off
set.cb_ySet  the 'set Y' check box is on/off
set.xSet  the X coordinate where to move the object (only if the 'set X to' check box is on)
set.ySet  the Y coordinate where to move the object (only if the 'set Y to' check box is on)
and so on.
With horizontalTranslation and verticalTranslation the 2nd 'from' parameter doesn't work: the topleft point is always used. Note: this is a required parameter! And I didn't see that this parameter isn't applicable for hor/ver translation in the reference so I think it's a bug.
In UI if you select a frame and set X, say, to 50pt first using the topleft point and then using the bottomright point, you'll get totally different results:
So the script should work in the same way.
Now I see that I have to write a function for moving X, Y and setting Width, Height on my own to handle all the possible 9 anchor points.
Kasyan,
in case this is unclear:
1. If you want to change the proxy points in the UI for any reason, do it with the property transformReferencePoint of the layoutWindow.
2. The values for horizontal and vertical transformation in a transformation matrix are always expressed as points.
Regradless of the measurement systems set for the rulers.1. I tried this, but it changes the proxy point on the screen only, but transformation is made using topleft point as before (move, transform methods)
2. The script works in points only because my client doesn't use other units.
Regards,
Kasyan 
7. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Laubender May 11, 2016 4:42 AM (in response to Kasyan Servetsky)Hi Kasyan,
I don't know, if you already mentioned this:
What is your version of InDesign you are testing this script with?
Uwe

8. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Kasyan Servetsky May 11, 2016 6:58 AM (in response to Laubender)Hi Uwe,
No, I didn't mention the version. I tested it on Mac in CC 2015.3 and CS3, and on PC in CC 2014: the same problem in all these versions.
Regards.
Kasyan 
9. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Trevorׅ May 11, 2016 7:42 AM (in response to Kasyan Servetsky)1 person found this helpfulHi Kasyan,
It ain't no bug. (I think)
The translateMatrix is relative. Move x distance from and as such doesn't make a diddlysquats difference from which point you reference it. What it looks like you want to do is move to translateMatrix does not do that.
obj.move([30, 50]) will move the object to
obj.move([], [30, 50]) will move the object by
If you really want to use the translateMatrix method then you first have to calculate your position at the desired anchor and work out how much to translate by to get to.
For example you have a horizontal line 50 points wide staring at 100 and ending at 150 and you want to move the line to point 30.
If you want the left side to be at point 30 then you apply a translation of 70 if you want the right side to move to 20 you apply a translation of 130. The anchor points will be irrelevant for the translation but necessary for the calculation.
Or you can use the move method the move method obj.move([30, 50]) with the anchor point set up.
HTH
Trevor

10. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Kasyan Servetsky May 11, 2016 7:58 AM (in response to Trevorׅ)Hi Trevor,
Instead of using transform or move methods, I'm going to write a function which changes the frame's bounding box making the necessary calculations depending on the proxy point selected in the dialog box.
— Kas

11. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Vamitul May 11, 2016 12:03 PM (in response to Kasyan Servetsky)Hi guys,
As it was previously mentioned, transformation matrices are additive. However, I point you to the documentation for the transform method:
undefined transform (in:CoordinateSpaces, from:Varies, withMatrix:Varies, replacingCurrent:Varies, [consideringRulerUnits:Boolean=Boolean])
The interesting parameter, in regards to this discussion is "replacingCurrent":
Transform components to consider; providing this optional parameter causes the target's existing transform components to be replaced with new values. Without this parameter, the given matrix is concatenated onto the target's existing transform combining the effect of the two. Can accept: MatrixContent enumerator, Array of MatrixContent enumerators or Long Integer. (Optional)

12. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Marc Autret May 11, 2016 8:45 PM (in response to Kasyan Servetsky)Hi Kasyan,
There would be a lot to say here but I lack time to explain in depth, so just keep in mind that the from parameter of the transform method is nothing but a temporary location which provides the origin of the transformation to be applied. This origin plays an important role in SCALING and ROTATION effects but it has no impact on the TRANSLATION component.
The purpose of myObj.transform(inSpace, fromOrigin, withMatrix, replacingCurrent) is to change the transformation state of myObj. As the initial state, it considers the matrix mapping of myObj relative to inSpace, M, then it computes something like M×T, where T basically represents the desired transformation (withMatrix) but the actual components are internally adjusted to take into account fromOrigin and replacingCurrent. The flags in replacingCurrent allow to specify whether some components must be treated as either new values or operands. Finally, the affine map of myObj is updated accordingly.
It would be wrong to think that the TRANSLATION components reflect the location of the object in the ruler space. When you need to reach a certain location through a translation, you always have to calculate the [tx,ty] parameters as offsets. This is what is done here Move object by "Reference Point" (as mentioned by tpk1982.)
@
Marc

13. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Kasyan Servetsky May 15, 2016 10:03 AM (in response to Marc Autret)Hello, it's me again, guys.
Thanks a lot for your help. I followed your recommendations and here’s where I’ve got so far:
function TransformFrame(frame) { var x, y, width, height, transMatrix = null, bounds = GetBounds(frame); try { // Set width and/or height if (set.cb_widthSet  set.cb_heightSet) { if (set.cb_widthSet && set.cb_heightSet) { width = set.widthSet; height = set.heightSet; } else if (set.cb_widthSet && !set.cb_heightSet) { width = set.widthSet; height = bounds.height; } else if (!set.cb_widthSet && set.cb_heightSet) { width = bounds.width; height = set.heightSet; } SetWidthHeight(frame, width, height); } // Move X and/or Y if (set.cb_xSet  set.cb_ySet) { if (set.cb_xSet && set.cb_ySet) { x = set.xSet; y = set.ySet; } else if (set.cb_xSet && !set.cb_ySet) { x = set.xSet; if (anchorPoint == AnchorPoint.BOTTOM_LEFT_ANCHOR  anchorPoint == AnchorPoint.BOTTOM_CENTER_ANCHOR  anchorPoint == AnchorPoint.BOTTOM_RIGHT_ANCHOR) { y = bounds.bottom; } else if (anchorPoint == AnchorPoint.LEFT_CENTER_ANCHOR  anchorPoint == AnchorPoint.CENTER_ANCHOR  anchorPoint == AnchorPoint.RIGHT_CENTER_ANCHOR) { y = bounds.halfHeight; } else { y = bounds.top; } } else if (!set.cb_xSet && set.cb_ySet) { y = set.ySet; if (anchorPoint == AnchorPoint.TOP_RIGHT_ANCHOR  anchorPoint == AnchorPoint.RIGHT_CENTER_ANCHOR  anchorPoint == AnchorPoint.BOTTOM_RIGHT_ANCHOR) { x = bounds.right; } else if (anchorPoint == AnchorPoint.TOP_CENTER_ANCHOR  anchorPoint == AnchorPoint.CENTER_ANCHOR  anchorPoint == AnchorPoint.BOTTOM_CENTER_ANCHOR) { x = bounds.halfWidth; } else { x = bounds.left; } } MoveToConsideringAnchor(frame, [x, y]); } if (set.cb_xScaleSet  set.cb_yScaleSet  set.cb_rotationSet  set.cb_skewSet) { if (set.cb_xScaleSet) { transMatrix = CatenateMatrix(transMatrix, "horizontalScaleFactor", set.xScaleSet / 100); } if (set.cb_yScaleSet) { transMatrix = CatenateMatrix(transMatrix, "verticalScaleFactor", set.yScaleSet / 100); } if (set.cb_rotationSet) { transMatrix = CatenateMatrix(transMatrix, "counterclockwiseRotationAngle", set.rotationSet); } if (set.cb_skewSet) { transMatrix = CatenateMatrix(transMatrix, "clockwiseShearAngle", set.skewSet); } frame.transform(CoordinateSpaces.PASTEBOARD_COORDINATES, anchorPoint, transMatrix); } } catch(err) { $.writeln(err.message + ", line: " + err.line); } } // function SetWidthHeight(frame, width, height) { frame.resize(CoordinateSpaces.INNER_COORDINATES, anchorPoint, ResizeMethods.REPLACING_CURRENT_DIMENSIONS_WITH, [width, height, CoordinateSpaces.INNER_COORDINATES]); } // function MoveToConsideringAnchor(obj, xyDest) { var coordinates = CoordinateSpaces.PASTEBOARD_COORDINATES, xy0 = obj.resolve(anchorPoint, coordinates)[0], xy1 = obj.resolve([xyDest, anchorPoint], coordinates, true)[0], dx = xy1[0]  xy0[0], dy = xy1[1]  xy0[1]; obj.transform(coordinates, [0, 0], [1, 0, 0, 1, dx, dy]); } // function CatenateMatrix(transMatrix, property, value) { if (transMatrix == null) { transMatrix = eval("app.transformationMatrices.add({" + property + ":" + value + "});"); } else { transMatrix = transMatrix.catenateMatrix(eval("app.transformationMatrices.add({" + property + ":" + value + "});")); } return transMatrix; }
In fact I used Marc’s functions as a starting point and modified them at my own discretion. They work but I don’t understand how they work. I read, and reread (a few times) Marc’s Coordinate Spaces Transformations in InDesign, but understood almost nothing. The problem is that in my youth I studied at art school where they taught me to draw nude models – a totally useless skill nowadays. Though officially we had math, geometry, etc. lessons, but our teachers considered them a waste of time and used us (students) for all kinds of useful work – moving furniture, hanging curtains, etc. – since the school was in the process of remodeling then.
That’s why I ask so many stupid questions here on the forum; please make allowance for me.
I think I did as you, guys, advised me. However, for some reason, with complex transformations the script brings a different result from the same steps done manually in InDesign.
For example, let’s rotate the rectangle 45° and then skew it 15° using the topleft proxy.
Manually I get this
By script I get this
Do you have any idea why this happens? Maybe I’m missing some parameter?
I tried to do transformations separately, in two steps,  without catenation matrices  but got exactly the same result as with catenation.
Regards,
Kasyan 
14. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Marc Autret May 17, 2016 8:20 AM (in response to Kasyan Servetsky)1 person found this helpfulHi Kasyan,
Matrix product is not commutative, so concatenation order matters. In particular, SHEARthenROTATE is not the same as ROTATEthenSHEAR, as shown below:
var mxID = app.transformationMatrices.add({matrixValues:[1,0,0,1,0,0]}), mxShearRotate = mxID.shearMatrix(15).rotateMatrix(45), // SHEAR x ROTATE mxRotateShear = mxID.rotateMatrix(45).shearMatrix(15); // ROTATE x SHEAR alert( mxRotateShear.matrixValues.toSource()===mxShearRotate.matrixValues.toSource() ); // => false
You can also check than calling transform() with mxShearRotate on one hand, and with mxRotateShear on the other hand, do not lead to the same result:
Now in your code you perform CatenateMatrix(…) in the following order: 1. scaling, 2. rotation, 3. shear (optional resize and translation are done first.)
Unfortunately this is not the "canonical transformation order" which InDesign's GUI relies on. When you transform something straight from the application, matrix parameters are always changed in a way that preserves the implicit SCALING×SHEAR×ROTATION×TRANSLATION order (which I abbreviate S×H×R×T in my PDF.)
As a consequence, even if the user first rotate the object 45°, then skew it 15°, the underlying transformation matrix remains SHEAR×ROTATION (in accordance with the canonical scheme.) Make the test and you will see that there is no difference in InDesign between rotatefirstthenskew and skewfirstthenrotate.
So, if you want to perform transformations with respect to the natural order that the user experiments in the GUI, then you have to compute your matrix in the S×H×R×T order.
@+
Marc

15. Re: Transformation matrix – AnchorPoint doesn’t work with horizontal/verticalTranslation
Kasyan Servetsky May 19, 2016 5:02 AM (in response to Marc Autret)Hi Marc,
Thank you very much for your clarification. I'll adjust the script according to your advice.
Regards,
Kasyan