text object rotation & position coordinates (x and y values)
Hi, all. I am trying to use a script to edit inkscape SVG code, and mostly succeeding, except with coordinate values. Specifically, with text objects, there seems to be some tricky function generating the "x" and "y" values (object coordinates). The function seems to be tied to the transform values. With no transformation in effect (theoretically, with the matrix being (1,0,0,1,0,0)  i say theoretically because the line is absent when these are the (implied) values), the "x" and "y" values are what one would expect, when one drags the object left and right, up and down. The x and y values change in the expected manner. However, when the text object gets transformed, as in the example below: transform="matrix(0.42584538,0.90479595,0.90479595,0.42584538,0,0)">
transform="matrix(0.42584538,0.90479595,0.90479595,0.42584538,0,0)"
the x and y values become severely strange... Dragging the text object vertically affects the x value (as well as the y value), and horizontal drag affects both as well. The values become negative in an unexpected way. And visually, the objects are not where the script attempts to place them.
Could someone please clue me in about the function (the math of it)?
thanks in advance
Hi Bric,
Yes, you're correct. The x/y values are being translated, scaled, rotated, and/or sheared by the transform matrix. These pages on Wikipedia should help you to get started: http://en.wikipedia.org/wiki/Transformation_(geometry) and http://en.wikipedia.org/wiki/Transformation_matrix
Also, it's not just the transform matrix on the object itself that you need to think about. If the text object is part of a group or a layer, then if there's a transform matrix on any of its parent groups or layers, they'll affect the object cumulatively.
I've written Python code to handle all these scenarios in the Pixelsnap extension. Have a look at the code for that if you want.
 Bryan
On Sun, Jan 9, 2011 at 17:15, Bric <bric@...2538...> wrote:
Hi, all.
I am trying to use a script to edit inkscape SVG code, and mostly succeeding, except with coordinate values.
Specifically, with text objects, there seems to be some tricky function generating the "x" and "y" values (object coordinates). The function seems to be tied to the transform values. With no transformation in effect (theoretically, with the matrix being (1,0,0,1,0,0)  i say theoretically because the line is absent when these are the (implied) values), the "x" and "y" values are what one would expect, when one drags the object left and right, up and down. The x and y values change in the expected manner. However, when the text object gets transformed, as in the example below:
transform="matrix(0.42584538,0.90479595,0.90479595,0.42584538,0,0)">
transform="matrix(0.42584538,0.90479595,0.90479595,0.42584538,0,0)"
the x and y values become severely strange... Dragging the text object vertically affects the x value (as well as the y value), and horizontal drag affects both as well. The values become negative in an unexpected way. And visually, the objects are not where the script attempts to place them.
Could someone please clue me in about the function (the math of it)?
thanks in advance
Gaining the trust of online customers is vital for the success of any company that requires sensitive data to be transmitted over the Web. Learn how to best implement a security strategy that keeps consumers' information secure and instills the confidence they need to proceed with transactions. http://p.sf.net/sfu/oraclesfdevnl _______________________________________________ Inkscapedevel mailing list Inkscapedevel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/inkscapedevel
On January 9, 2011 at 2:21 PM Bryan Hoyt  Brush Technology <bryan@...2542.....> wrote:
Hi Bric,
Yes, you're correct. The x/y values are being translated, scaled, rotated, and/or sheared by the transform matrix. These pages on Wikipedia should help you to get started: http://en.wikipedia.org/wiki/Transformation_(geometry) and http://en.wikipedia.org/wiki/Transformation_matrix
Yes, I am using the (cos, sin, sin, cos) rotation matrix in my script, and inkscape seems to visualize my rotation angle the way i intend. But, as is the issue, not the x/y position of my intent. OK. Thanks for this info. At this point I can only vaguely understand how (and why) inkscape would store transformed values in the SVG file, instead of storing the original coordinates and then subjecting those to whatever transformation the applies, during render time. I'll have to get back to this later.
Also, it's not just the transform matrix on the object itself that you need
to think about. If the text object is part of a group or a layer, then if there's a transform matrix on any of its parent groups or layers, they'll affect the object cumulatively.
thanks.
I've written Python code to handle all these scenarios in the Pixelsnap
extension. Have a look at the code for that if you want.
I skimmed through your code, and see that you are computing offsets based on transformation. Still, it looks complex for me right now; will have to return to it later when I have more time. I can't wrap my mind around how exactly to apply the transformation to the x y position. I'll tinker with this later. thanks again
Briefly, to get the x,y position of a point after it's transformed, use a function like this (in Python):
def transform_point(transform, x, y): x = transform[0][0]*x + transform[0][1]*y + transform[0][2] y = transform[1][0]*x + transform[1][1]*y + transform[1][2] return x,y
If you need to modify the x,y position, it gets slightly more complicated, but only a little. 1) transform the point as above, to get the original values if you need them for anything 2) calculate the new values you need. 3) Transform them back to the original x,y space by using the matrix inverse: http://en.wikipedia.org/wiki/Matrix_inverse
In pseudocode:
orig_x, orig_y = however_you_got_the_values_in_the_first_place() t_x, t_y = transform_point(transform, orig_x, orig_y) new_x_t, new_y_t = calculate_some_new_values(t_x, t_y) new_x, new_y = transform_point(invert_transform(transform), new_x_t,
new_y_t)
To get the matrix inverse isn't 100% straightforward, mathematically. It's easy in python, though. Here's the function I use (pretty much just a wrapper around numpy.matrix.I):
import numpy def invert_transform(transform): transform = transform[:] # duplicate list to avoid modifying it transform += [[0, 0, 1]] inverse = numpy.matrix(transform).I.tolist() inverse.pop() return inverse
 Bryan
On Mon, Jan 10, 2011 at 09:26, Bric <bric@...2538...> wrote:
On January 9, 2011 at 2:21 PM Bryan Hoyt  Brush Technology < bryan@...2310...> wrote:
Hi Bric,
Yes, you're correct. The x/y values are being translated, scaled,
rotated,
and/or sheared by the transform matrix. These pages on Wikipedia should
help
you to get started:
http://en.wikipedia.org/wiki/Transformation_(geometry)
Yes, I am using the (cos, sin, sin, cos) rotation matrix in my script, and inkscape seems to visualize my rotation angle the way i intend. But, as is the issue, not the x/y position of my intent.
OK. Thanks for this info. At this point I can only vaguely understand how (and why) inkscape would store transformed values in the SVG file, instead of storing the original coordinates and then subjecting those to whatever transformation the applies, during render time. I'll have to get back to this later.
Also, it's not just the transform matrix on the object itself that you
need
to think about. If the text object is part of a group or a layer, then if there's a transform matrix on any of its parent groups or layers, they'll affect the object cumulatively.
thanks.
I've written Python code to handle all these scenarios in the Pixelsnap
extension. Have a look at the code for that if you want.
I skimmed through your code, and see that you are computing offsets based on transformation. Still, it looks complex for me right now; will have to return to it later when I have more time.
I can't wrap my mind around how exactly to apply the transformation to the x y position. I'll tinker with this later.
thanks again
On January 9, 2011 at 4:03 PM Bryan Hoyt  Brush Technology <bryan@...2542.....> wrote:
Briefly, to get the x,y position of a point after it's transformed, use a function like this (in Python):
def transform_point(transform, x, y): x = transform[0][0]*x + transform[0][1]*y + transform[0][2] y = transform[1][0]*x + transform[1][1]*y + transform[1][2] return x,y
Sorry, as much as i've tried (given time constraints), I can't figure out where you got the above 2x3 matrix instead of a 2x2. Or is it a 2x3 python array, whose (top)left 2x2 elements are the rotation transformation? In that case, where do you get transform[0][2] and transform[1][2] from?
If you need to modify the x,y position, it gets slightly more complicated,
but only a little. 1) transform the point as above, to get the original values if you need them for anything 2) calculate the new values you need. 3) Transform them back to the original x,y space by using the matrix inverse: http://en.wikipedia.org/wiki/Matrix_inverse
You mean, given a certain nonorigin position, multiplying by the inverse would give me that position. (note, I am saying "ORIGIN" (0,0), not "original" :))
In pseudocode:
orig_x, orig_y = however_you_got_the_values_in_the_first_place() t_x, t_y = transform_point(transform, orig_x, orig_y) new_x_t, new_y_t = calculate_some_new_values(t_x, t_y) new_x, new_y = transform_point(invert_transform(transform), new_x_t,
new_y_t)
To get the matrix inverse isn't 100% straightforward, mathematically. It's easy in python, though. Here's the function I use (pretty much just a wrapper around numpy.matrix.I):
you are making me think back years ago to linear algebra class... yes, I suspected from the getgo I might need the inverse at some point. thanks again
import numpy
def invert_transform(transform): transform = transform[:] # duplicate list to avoid modifying it transform += [[0, 0, 1]] inverse = numpy.matrix(transform).I.tolist() inverse.pop() return inverse
 Bryan
On Mon, Jan 10, 2011 at 09:26, Bric <bric@...2538...> wrote:
On January 9, 2011 at 2:21 PM Bryan Hoyt  Brush Technology < bryan@...2310...> wrote:
Hi Bric,
Yes, you're correct. The x/y values are being translated, scaled,
rotated,
and/or sheared by the transform matrix. These pages on Wikipedia should
help
you to get started:
http://en.wikipedia.org/wiki/Transformation_(geometry)
Yes, I am using the (cos, sin, sin, cos) rotation matrix in my script, and inkscape seems to visualize my rotation angle the way i intend. But, as is the issue, not the x/y position of my intent.
OK. Thanks for this info. At this point I can only vaguely understand how (and why) inkscape would store transformed values in the SVG file, instead of storing the original coordinates and then subjecting those to whatever transformation the applies, during render time. I'll have to get back to this later.
Also, it's not just the transform matrix on the object itself that you
need
to think about. If the text object is part of a group or a layer, then if there's a transform matrix on any of its parent groups or layers, they'll affect the object cumulatively.
thanks.
I've written Python code to handle all these scenarios in the Pixelsnap
extension. Have a look at the code for that if you want.
I skimmed through your code, and see that you are computing offsets based on transformation. Still, it looks complex for me right now; will have to return to it later when I have more time.
I can't wrap my mind around how exactly to apply the transformation to the x y position. I'll tinker with this later.
thanks again
 PS. Check out the Brush newsletter: *Subscribe or read our previous newsletters* http://brush.co.nz/newsletters
Bryan Hoyt, *Web Development Manager*  Brush Technology *Ph:* +64 3 741 1204 *Mobile:* +64 21 238 7955 *Web:* brush.co.nz
Hi Bric,
Sorry, as much as i've tried (given time constraints), I can't figure out
where you got the above 2x3 matrix instead of a 2x2.
Or is it a 2x3 python array, whose (top)left 2x2 elements are the rotation transformation? In that case, where do you get transform[0][2] and transform[1][2] from?
Yes, it's just a 2x3 python array, whose topleft 2x2 elements are the rotation+scale+shear transformation (it's more than just rotation). In some cases, it may be 3x3 matrix, depending on what is passed in  but the 3rd row is completely ignored either way. I'll explain about the 3rd row soon.
First, what's the 3rd column all about (i.e. transform[_][2])? It's the translation vector, and it serves a rather different purpose than the 2x2. After the rotation+scale+shear is performed, the entire point is translated by the x,y value stored in the 3rd column. This is done by simple arithemetic addition.
The extra column has the very nice property of just being part of the matrix, and "doing the right thing" with common matrix operations (including multiplication/composition & inverse, the most common). So you can represent a complex transform as a single 2x3 (or 3x3) matrix.
The 3rd row: this is primarily to make the matrix square (#rows == #columns), because only square matrices are Invertible ( http://en.wikipedia.org/wiki/Invertible_matrix). Matrix Inversion is necessary to undo the effect of a matrix  see below. The 3rd row is (virtually) always set to [0, 0, 1], unless you're really trying hard to get tricky with the maths. I've explicitly added this 3rd row in my invert_transform() function.
If you need to modify the x,y position, it gets slightly more
complicated,
but only a little. 1) transform the point as above, to get the original values if you need them for anything 2) calculate the new values you
need.
 Transform them back to the original x,y space by using the matrix
You mean, given a certain nonorigin position, multiplying by the inverse would give me that position.
Yes, roughly, I think, if I understand you correctly, except I don't think it's relevant whether the point is (0,0) or otherwise  a transform matrix will affect all points in the same way (and furthermore, except for translation, (0,0) will always be (0,0) after transform  a rotated/scaled/sheared origin is still the origin).
I'll try to say it less ambiguously:
A) If you multiply a point (let's call it P) by a transform matrix (let's call it T), then you get a new point (call it P'), shear/scaled/rotated/translated according to the transform matrix: P * T = P B) If you then multiply the new point P' by the inverse of T (call that T'), then you get the original point P: P' * T' = P In other words, the inverse of a matrix performs the exact reverse transformation that the original matrix performed.
So, if a point is specified (eg in the SVG file) in one particular "coordinate space", but a transform is applied (the transform= attribute of the path) in Inkscape before displaying it, then before you can do anything very meaningful with that point, you have to apply the same transform to it's coordinates. That's step 1 in my previous email above.
Then, after doing something meaningful with the point (which is step 2 above), you have to "untransform" the point before you can write it back to the SVG file (step 3, applying the matrix inverse).
you are making me think back years ago to linear algebra class... yes, I suspected from the getgo I might need the inverse at some point.
Yes, you can't get by without it ;)
Hope that helps!
participants (2)

Bric

Bryan Hoyt  Brush Technology