【问题标题】:SVG Matrix to Rotation DegreesSVG 矩阵到旋转度数
【发布时间】:2013-03-21 11:28:55
【问题描述】:

我正在从具有以下格式矩阵的 SVG 文件中读取矩形的位置和旋转:

<rect transform="matrix(1.02414 -0.133308 0.122628 0.942091 190.767 780.999)" width="122" height="20"/>

现在我正在尝试将这些值解析为 Lua 到 draw with Corona and physics like this,但它们部分出现错误,并且在我目前的半猜测方法中也经常是 NAN。 我需要做什么才能将上述矩阵转换为适当的 Lua 旋转度数?

到目前为止,我所拥有的如下(值数组是按 SVG 顺序排列的矩阵值)。谢谢!

local x = values[5]; local y = values[6]
local rotation = math.acos(values[1])
if values[2] < 0 then rotation = -rotation end
rotation = math.floor( math.deg(rotation) )
rotation = rotation % 360

app.spritesHandler:createBar( math.floor(x), math.floor(y), rotation )

【问题讨论】:

  • 这不是通常的旋转矩阵,因为它包含大于 1 的数字。因此,arccos 失败了。
  • 谢谢,你知道该怎么做吗?
  • 值得注意的是,即使它是一个“0.995136 0.276294 -0.254158 0.91541”的矩阵,cofe 也无法正确转换为度数。

标签: math matrix svg lua coronasdk


【解决方案1】:

首先,我认为您需要索引从 0 到 5,而不是从 1 到 6。

根据the spec,旋转矩阵为:

a  c  e
b  d  f
0  0  1

其中 a-f 是矩阵列表中的 6 个数字。

我们还发现cx,cy 周围的rotate(angle,cx,cy) 等价于

  1. 翻译(cx,cy)
  2. 旋转(角度)
  3. 翻译(-cx,-cy)

应该是:

|1 0 cx|  |cos(t) -sin(t) 0|  |1 0 -cx|
|0 1 cy|  |sin(t)  cos(t) 0|  |0 1 -cy|
|0 0 1 |  |  0       0    1|  |0 0  1 |

  |cos(t)   -sin(t)  cx|  |1 0 -cx|
= |sin(t)    cos(t)  cy|  |0 1 -cy|
  |   0        0      1|  |0 0  1 |

  |cos(t)   -sin(t)  (-cx cos(t) + cy sin(t) + cx) |
= |sin(t)    cos(t)  (-cx sin(t) - cy cos(t) + cy) |
  |  0         0              1                    |

因此这表明角度信息在系数 a、b、c 和 d 中完全独立可用。如果唯一应用的是这个矩阵,那么 a 和 d 应该匹配,b 和 c 应该只是相反的符号。

但是,查看您的数字列表,它们不是,所以我想知道是否还应用了其他一些转换?正如评论者指出的那样,数字大于 1,因此不是对角度进行简单三角操作的结果。

一种可能性是也有缩放。该矩阵是:

| sx 0  0|
|  0 sy 0| 
|  0  0 1|

所以如果先应用,然后旋转,我们会得到:

| sx 0  0| |cos(t)   -sin(t)  (-cx cos(t) + cy sin(t) + cx) |
|  0 sy 0| |sin(t)    cos(t)  (-cx sin(t) - cy cos(t) + cy) |
|  0  0 1| |  0         0              1                    |

  |sx cos(t)   -sx sin(t)   sx (-cx cos(t) + cy sin(t) + cx) |
= |sy sin(t)    sy cos(t)   sy (-cx sin(t) - cy cos(t) + cy) |
  |  0               0                  1                    |

从那个矩阵:

a/c = sx cos(t) / (-sx sin(t))
    = - cos(t) / sin(t)
    = 1/tan(t)
tan(t) = c/a

tan(t) = 0.122628/1.02414
       = 0.119738
    t  = 6.82794 degrees.

我觉得从图片上看是对的。

所以既然我们知道t,我们就可以计算出sx 和sy:

a = sx cos(t) 
sx = a/cos(t) = 1.0315

还有 sy:

d = sy cos(t)
sy = d/cos(t) = 0.94882

cxcy 找到旋转中心只需使用我们已经获得的值进一步代入上述 e 和 f 的方程。

【讨论】:

  • 非常感谢,这看起来很广泛! (顺便说一下,Lua 数组是基于 1 的,因此是 1 到 6。)我不太清楚现在从哪里开始使用 Lua 代码。你能用任何语言解释一下伪代码吗?
  • t、sx 和 sy 的计算是伪代码。您需要 values[1]..values[6] 而不是 a,b,c,d,e,f,并且您需要重新排列 e 和 f 项以获得 cx 和 cy。你还在寻找什么?我假设您可以执行平移和缩放以及旋转。例如,对于 e,您有 sx (-cx cos(t) + cy sin(t) + cx),并且您已经有 sx 和 t,留下了一对来自 e 和 f 的 cx 和 cy 的联立方程。
【解决方案2】:

它似乎是拉伸与旋转相结合,如v[4]/v[1] == -v[3]/v[2]
所以,旋转可以这样计算:

local str = '<rect transform="matrix(1.02414 -0.133308 0.122628 0.942091 190.767 780.999)" width="122" height="20"/>'
local v = {}
str:match'matrix(%b())':gsub('[%d.-]+', function(d) v[#v+1] = tonumber(d) end)
local x, y = unpack(v, 5)
local rotation = math.floor(math.deg(math.atan2(v[3], v[4]))) % 360

【讨论】:

  • 完美运行!杰出的!之后我添加了另一个“旋转 = 360 - 旋转”作为让它工作的最后一步,可能与我的其余代码或 Corona 绘图有关。非常感谢,这对我正在制作的游戏非常有帮助!
  • @PhilippLenssen - 只需将 math.atan2(v[3], v[4]) 替换为 math.atan2(v[2], v[1]) 即可获得相反的旋转。
猜你喜欢
  • 2019-02-08
  • 1970-01-01
  • 1970-01-01
  • 2020-09-04
  • 1970-01-01
  • 2017-02-16
  • 1970-01-01
  • 2020-08-23
  • 1970-01-01
相关资源
最近更新 更多