如何发现旋转/缩放的值?例如,在我发出以下命令后:
90 rotate
当前旋转设置为 90。如何发现旋转设置为?
旋转(也包括缩放和剪切)没有单独的值。所有此类转换都汇总到当前转换矩阵 (CTM) 中。
您可以在 PostScript 语言参考手册中找到对 CTM 和转换的出色描述,尤其是第 4.3.1 到 4.3.3 节。它是 PostScript 理解的一个重要领域,因为 CTM 支持所有绘图操作。我认为在这个论坛上解释它真的太复杂了。
简短的回答是没有简单的解决方案,您必须做一些矩阵代数才能找出点映射到的位置。一个常见的技巧是通过 CTM(点 0,0 和 1,1)传递单位正方形的坐标,然后查看变换后的点在哪里结束。
如果你真的只做旋转、平移和统一缩放,那么你可以将仿射变换矩阵 (3x2) 分解为平移向量 (1x2) 和线性变换矩阵 (2x2)。然后,一个小三角实际上可以给你旋转。
所以这是在后记中做到这一点的一种方法。它做了一些矩阵操作,不是对 CTM 进行操作,而是对一个矩阵进行操作,如果乘以默认矩阵,则该矩阵将产生 CTM。它按顺序返回旋转角度、缩放因子和平移偏移量。将运算符序列translate scale rotate
应用于这些值(如果默认矩阵有效)将生成当前矩阵。
我有点得意忘形,试图让它优雅地拒绝使用 PS 错误机制无法处理的矩阵(在解释器之间没有完全标准化,因为它在标准中基本上没有记录)。为了测试它,我从其他地方引入了一些随机种子代码。但隐藏在中间的是一个相对简单的公式b a atan
,它产生角度(其中[a b c d e f]
是矩阵值的名称,a == d,b == -c)。
%!
%make Adobe-style interpreters mimic ghostscript's error call
/.error where { pop /signalerror {.error} def } if
%"Safe" seed randomizer
{ 0 4{ 8 bitshift (/dev/random)(r)file read pop add }repeat srand } stopped
{ usertime 10 { %can't open file, chop some vegetables
save 128 string 99 2 getinterval 1 vmreclaim pop restore
} repeat usertime 8 bitshift add srand } if
%translate, scale, rotate
% extracts rotation, scaling and translation parameters
% from the CTM (assuming it's "easy" to do)
%
%eg.
% PS> rand 100 mod %get random number 0..99
% PS> { 1 rotate } repeat %rotate
% PS> tsr 4 pop = %print rotation angle
%
% - tsr theta Sx Sy Tx Ty
/tsr { {
6 dict begin
matrix currentmatrix % get CTM
matrix defaultmatrix % get Default
matrix invertmatrix % get the "undo" of the Default
matrix concatmatrix % CTM * Default^-1 = Default-->CTM
aload pop % dump the matrix components
{/ty/tx/d/c/b/a}{exch def}forall % name the components
a d ne
b neg c ne or %ie. not "Jacobian", not "conformal"
{ [ a b c d tx ty ] /tsr cvx /undefinedresult signalerror } if
b a atan % theta
a a mul b b mul add sqrt dup % Sx Sy (uniform scaling factors)
tx ty % translation
end
exit } loop } def
%1 2 scale resolve %test error trigger
rand 100 mod
{ 1 rotate } repeat
rand 100 mod
{ rand 3 mod .5 add dup scale } repeat
tsr pstack
一种可能的方法是重载rotate
,以便它以方便的形式跟踪值。
/oldrotate /rotate load def
/rotate { dup oldrotate
/currentrotation dup load 3 2 roll add 360 mod store
}
/currentrotation 0 def
setmatrix
不幸的是,如果您使用的是or ,这还不够gsave ... grestore
。