You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
shape foo {
bar [ x 1 y 2 rot 30 s 2 0.5 skew 10 0 flip 45 ]
}
and in the text below it explained that in this case the adjustment order is to translate first, then rotate, and so on.
I was a bit confused by the text, because if we translate bar first to (1, 2), a rotation would move it around the origin, not (1, 2). The same logic goes to sizing, where it would move to (2, 1).
Fundamentally, the confusion is on the order of applying the affine transformation. If the affine matrix for the translate operation is T, and the R for rotate, then the behavior of CF suggests T * R (shape), while the text says R * T(shape).
I dug around the source code to see how this behavior is implemented. The ASTmodification::makeCanonical function in astexpression.cpp would sort all transformations in canonical order, while ASTmodTerm::evaluate would then apply those transformations. The code would call m.m_transform.premultiply(T) where I believe m is the existing affine transformation and T is the shape transformation. When combined with the canonical order, I believe we are concatenating the transformation matrix as
M * T * R * S * S * F (shape)
where M is the existing/external transformation.
While the order of concatenating the shape transformations is indeed TRSSF, when we do it step by step, we do need to apply the transformations in the reverse order, i.e. F S S R T.
I constructed the following example to illustrate the behavior.
startshape board
m = 5
shape board {
grid []
// marks the origin
SQUARE [b 0.6]
// If the applying order is TRSSF, then the R here would be no-op on SQUARE
// However the r is applied to turn a 3x1 bar to 1x3.
// Indicating R is applied after S.
SQUARE[x 2 1 s 3 1 r 90]
}
// Draw a horizontal line y = k
path yline(number k)
{
MOVETO(-m, k)
LINETO(m, k)
STROKE(0.01)[]
}
// Draw a vertical line x = k
path xline(number k)
{
MOVETO(k, -m)
LINETO(k, m)
STROKE(0.01)[]
}
shape grid
{
loop i = -5, 6, 1 [] xline(i) []
loop i = -5, 6, 1 [] yline(i) []
}
Would like to use your help to clarify if my understanding is correct.
I am happy to send over a small PR to update the wiki.
The text was updated successfully, but these errors were encountered:
In the wiki doc on shape adjustment, the doc showed an example
and in the text below it explained that in this case the adjustment order is to translate first, then rotate, and so on.
I was a bit confused by the text, because if we translate
bar
first to(1, 2)
, a rotation would move it around the origin, not(1, 2)
. The same logic goes to sizing, where it would move to(2, 1)
.Fundamentally, the confusion is on the order of applying the affine transformation. If the affine matrix for the translate operation is T, and the R for rotate, then the behavior of CF suggests
T * R (shape)
, while the text saysR * T(shape)
.I dug around the source code to see how this behavior is implemented. The
ASTmodification::makeCanonical
function inastexpression.cpp
would sort all transformations in canonical order, whileASTmodTerm::evaluate
would then apply those transformations. The code would callm.m_transform.premultiply(T)
where I believem
is the existing affine transformation andT
is the shape transformation. When combined with the canonical order, I believe we are concatenating the transformation matrix aswhere
M
is the existing/external transformation.While the order of concatenating the shape transformations is indeed TRSSF, when we do it step by step, we do need to apply the transformations in the reverse order, i.e.
F S S R T
.I constructed the following example to illustrate the behavior.
Would like to use your help to clarify if my understanding is correct.
I am happy to send over a small PR to update the wiki.
The text was updated successfully, but these errors were encountered: