Shape preserving transformations are much important for the transformation of rigid bodies. Those transformations are exclusively composed by translations and rotations; s. Transformation of coordinates (Projective; Affine; Metric)
Assume, we want to move the blue triangle located at (x1=100, y1=100) to the red location (x2=250, y2=200) and rotate it by a = -30°. To achive this, we have to
transform = "translate(x2, y2) rotate(a) translate(-x1, -y1)"
or transform = "translate(x2-x1, y2-y1) rotate(a, x1, x2)"
for our element's SVG transform attribute.
Thus the following SVG code snippet will reproduce the upper image:
<?xml version="1.0"?>
<svg width="400" height="300" onload="OnLoadEvent(evt)">
<path style="fill:blue;stroke:black;" d="M75,50 125,50 100,100 z"/>
<path style="fill:red; stroke:black;" d="M75,50 125,50 100,100 z"
transform="translate(250 200)
rotate(-30)
translate(-100 -100)"/>
</svg>
Try it
As we solved our problem, we can stop here .. BUT .. I recommend for performance reasons to use transformation matrices whenever possible. Reformulating the concatenation of translations and rotations as matrices, we yield
[ 1 0 x2] [cos(a) -sin(a) 0] [ 1 0 -x1] [cos(a) -sin(a) -x1cos(a) + y1sin(a) + x2] [ 0 1 y2] * [sin(a) cos(a) 0] * [ 0 1 -y1] = [sin(a) cos(a) -x1sin(a) - y1cos(a) + y2] [ 0 0 1 ] [ 0 0 1] [ 0 0 1 ] [ 0 0 1 ]So we can rewrite our element's SVG transform attribute as
transform = "matrix(cos(a), sin(a), -sin(a), cos(a), -x1cos(a)+y1sin(a)+x2, -x1sin(a)-y1cos(a)+y2)"and again reproduce the upper image now via:
<?xml version="1.0"?>
<svg width="400" height="300" onload="OnLoadEvent(evt)">
<path style="fill:blue;stroke:black;" d="M75,50 125,50 100,100 z"/>
<path style="fill:red; stroke:black;" d="M75,50 125,50 100,100 z"
transform="matrix(0.866 -0.5 0.5 0.866 113.4 163.4)"/>
</svg>
Try it
To illustrate the ease of use, we want to create a simple animation of a rolling ball.
<?xml version="1.0"?>
<svg width="400" height="300" onload="OnLoadEvent(evt)">
<rect style="fill:none;stroke:black;" x="0" y="0" width="400" height="300" />
<g id="ball"> <!-- roller -->
<circle style="fill:magenta;stroke:black;" cx="30" cy="140" r="20" />
<path style="fill:none;stroke:black;" d="M25,135 35,145 M35,135 25,145"/>
</g>
<path style="fill:none;stroke:gray;stroke-width:6" d="M5,163 395,163" /> <!-- ground -->
<script><![CDATA[
// === the svg elements ======================================
var ball = null, x1=30, y1=140, r=20, psi=0, xend=370; // globals ..
// --- animation function ------------------------------------
function Animate()
{
var sp = Math.sin(psi), cp = Math.cos(psi),
x2 = x1 + r*psi, y2 = y1,
matrix = "matrix(" + cp +"," + sp + "," + (-sp) + "," + cp + ","
+ (-x1*cp+y1*sp+x2) + ","
+ (-x1*sp-y1*cp+y2) + ")";
ball.setAttribute("transform", matrix);
psi += Math.PI/45;
if (x2 < xend)
window.setTimeout("window.Animate()", 1);
return true;
}
// == event handler ============================================
function OnLoadEvent(event)
{
ball = event.getTarget().getOwnerDocument().getElementById("ball");
window.Animate = Animate;
window.Animate();
}
]]></script>
</svg>
Try it
Now we understand transformations a bit better. We also know that this last animation example can be implemented simpler using SMIL animation.
© 2000
MecXpert