Posted on

When we move an element from one location to another location on Inkscape canvas, we can also view it as moving an imaginary coordinate system with it. The element stays at the same location in the imaginary coordinate system. Translate, rotate, and scale are three common transforms in Inkscape.

The translate transform is simply moving an object. The coordinate of a point on
the object (x, y) will change to (x’, y’). The `a`

and `b`

values in the equations
shown below represent the distances along X and Y axes the object has moved. If
we write two equations below in matrix form, we have the third
equation.

The two equations below are for rotation and scale. The rotation angle (alpha) is
clockwise because the y axis increases from top to bottom. The `a`

and `b`

of
the scale equation represent the scale factor along X and Y.

The above rotation equation is for rotating around the origin (0, 0). If we rotate an element around a coordinate (a, b), the equation becomes like this.

The matrix is in this form when those three transforms are combined.

Let’s look at an example to see how transform works in Inkscape. First we draw
a rectangle with top left coordinates (10, 10). It has a width of 60 and height of 40.
The SVG file has these lines for the element. We can ignore the `id`

and `style`

attributes
for this example.

```
<rect
style="fill:none;stroke:#000000;
stroke-width:0.26458333;stop-color:#000000"
id="rect31"
width="60"
height="40"
x="10"
y="10" />
```

We will use the transform dialog (Menu `Object -> Transform`

or shortcut Ctrl + Shift + M)
to see how Inkscape handles a transform. When we move the rectangle 10mm horizontally and 10mm
vertically (with Relative move selected), the SVG element coordinates will change.

```
<rect
width="60"
height="40"
x="20"
y="20" />
```

Next let’s rotate the object 30 degrees clockwise. The element code becomes like this.
It will have a new `transform`

attribute with `rotate(30)`

as its value. The x and y
coordinate values change from (20, 20) to (33.3012, -10.3589). The reason is that
the rotation is not around the origin (0, 0), instead it is around the center of the
rectangle which is (50, 40). How does Inkscape calculate the new coordinates
of the top left corner of the rectangle? It is a little complicated, and this
numpy python script shows the calculation.

```
<rect
width="60"
height="40"
x="33.30127"
y="-10.358984"
transform="rotate(30)" />
```

The `rotate`

function as the value of the `transform`

attribute can also accept two additional
arguments as the rotation center. The xml code shown below represents the same rectangle.

```
<rect
width="60"
height="40"
x="20"
y="20"
transform="rotate(30, 50, 30)" />
```

The SVG specs define other transform functions `translate`

, `scale`

, `skewX`

, `skewY`

, and `matrix`

.
We can also add a transform attribute to a group or a layer.

The `transform.py`

module in the `inkex`

directory has over 1,000 lines of code. But the
system extensions do not use this function very often. Only a few system extensions
set the `transform`

attribute.

Here is a simple extension to test the `transform`

attribute of the rectangle element.

```
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension
xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Transform Element</name>
<id>user.transform</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="Custom"/>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">transform.py</command>
</script>
</inkscape-extension>
```

```
# transform.py
import inkex
from inkex import Rectangle, Transform
class NewElement(inkex.GenerateExtension):
container_label = 'transform'
container_layer = True
def generate(self):
self.style = {'fill' : 'none', 'stroke' : '#000000',
'stroke-width' : self.svg.unittouu('1px')}
rects = self.add_rect()
for r in rects:
yield r
def add_rect(self):
el1 = Rectangle(x='10', y='10', width='60', height='40')
el1.style = self.style
el2 = Rectangle.new(20, 20, 60, 40)
el2.style = self.style
tr = Transform('rotate(30)')
el2.transform = tr
el3 = Rectangle.new(20, 20, 60, 40)
el3.style = self.style
tr = Transform('rotate(30, 50, 40)')
el3.transform = tr
el4 = Rectangle.new(20, 20, 60, 40)
el4.style = self.style
tr = Transform('translate(10, 10) rotate(45)')
el4.transform = tr
el5 = Rectangle.new(20, 20, 60, 40)
el5.style = self.style
tr = Transform('scale(2.0) rotate(60)')
el5.transform = tr
el6 = Rectangle.new(20, 20, 60, 40)
el6.style = self.style
tr = Transform('rotate(60)') * Transform('scale(2.0)')
el6.transform = tr
return el1, el2, el3, el4, el5, el6
if __name__ == '__main__':
NewElement().run()
```

Notice in the above examples, we can combine multiple transforms as
the string argument to the `Transform`

constructor, or multiply multiple
`Transform`

objects. The SVG results are shown below.

```
<rect
x="10"
y="10"
width="60"
height="40"
id="rect1007" />
<rect
x="20"
y="20"
width="60"
height="40"
transform="rotate(30)"
id="rect1009" />
<rect
x="20"
y="20"
width="60"
height="40"
transform="matrix(0.866025 0.5 -0.5 0.866025 26.6987 -19.641)"
id="rect1011" />
<rect
x="20"
y="20"
width="60"
height="40"
transform="matrix(0.707107 0.707107 -0.707107 0.707107 10 10)"
id="rect1013" />
<rect
x="20"
y="20"
width="60"
height="40"
transform="matrix(1 1.73205 -1.73205 1 0 0)"
id="rect1015" />
<rect
x="20"
y="20"
width="60"
height="40"
transform="matrix(1 1.73205 -1.73205 1 0 0)"
id="rect1017" />
```

The `transforms`

module also includes several other classes and functions. The
notable classes are `Vector2d`

, `BoundingBox`

, and `DirectedLineSegment`

. It also
defines two functions `cubic_extrema`

and `quadratic_extrema`

. Those classes
and functions are not necessarily related to `transforms`

.

The `Vector2d`

and `DirectedLineSegment`

classes are very useful when we are working
on mathematical drawings. We can apply vector algebra to calculate coordinates
of points, and draw them as lines or polygons on the canvas.

Anthony J. Pettofrezzo published two math books *Vectors and Their Applications* and
*Matrices And Transformations*. Both books are relevant to the transforms module discussed in this chapter.

The book *Mathematical Illustrations, A Manual Of Geometry and Postscript* by
Bill Casselman is an excellent reference for math drawings. Here is the
link to the book webpage. The pdfs of the book chapters are available on the webpage.

The book *Introduction To Computer Graphics* by James Foley and others has a Chapter
Geometrical Transformations. The transform equations in the book are in the
same format as on this web page.

11. Transforms