为啥我的矩阵旋转没有通过我学校的单元测试?

Posted

技术标签:

【中文标题】为啥我的矩阵旋转没有通过我学校的单元测试?【英文标题】:Why does my matrix rotation not pass my school's unit test?为什么我的矩阵旋转没有通过我学校的单元测试? 【发布时间】:2016-05-28 05:08:50 【问题描述】:

基本上,我们被要求为我的大学课程用 C++ 创建一个矩阵调用。

首先,我的类使用列主构造函数,但它把它放在内存行主中:

Matrix2::Matrix2(float R1C1, float R1C2, float R2C1, float R2C2)

    //Row major order.
    //Parameters written as column major (a normal matrix) but entered into memory as row major.
    matrix[0] = R1C1;
    matrix[1] = R2C1;
    matrix[2] = R1C2;
    matrix[3] = R2C2;

我认为这是单元测试所必需的。 如果未指定参数,则矩阵被定义为其单位矩阵。

所以,我用这个代码旋转我的矩阵:

void Matrix2::setRotateZ(float radians)

    (*this) = (*this)*Matrix2(  cosf(radians), -sinf(radians),
                                sinf(radians), cosf(radians));

我在 wikipedia 和我的 uni 讲座幻灯片上找到了此代码。而且它似乎与列主要矩阵一起使用(由于我的构造函数,这就是数据的输入方式)

还请注意,“setRotateZ”实际上应该是“rotateZ”,因为它会在多次调用时累积旋转。

我的乘法重载是这样的:

Matrix2 Matrix2::operator*(Matrix2& o)

    Matrix2 newMatrix(0.0f, 0.0f, 0.0f, 0.0f);

    newMatrix.matrix[0] = matrix[0] * o.matrix[0] + matrix[2] * o.matrix[1];
    newMatrix.matrix[2] = matrix[0] * o.matrix[2] + matrix[2] * o.matrix[3];
    newMatrix.matrix[1] = matrix[1] * o.matrix[0] + matrix[3] * o.matrix[1];
    newMatrix.matrix[3] = matrix[1] * o.matrix[2] + matrix[3] * o.matrix[3];

    return newMatrix;

它只是像普通矩阵一样相乘(假设它是行主要的,0 是 R1C1,1 是 R2C1 等)

差不多了,如果我交换:

-sinf(radians)

sinf(radians)

在我上面的 setRotateZ 函数中,一切正常,矩阵通过了所有测试,包括乘法、旋转和加法。

但是,正如现在所示,矩阵无法旋转。

据我所知,交换符号函数应该只适用于行主矩阵,但因为我在构造函数中交换了它,所以将它作为列主矩阵输入应该可以。

我做错了什么?这让我很烦恼,即使我已经通过交换值让它工作了,我想知道发生了什么。

我几乎是一个矩阵新手,所以我们将不胜感激!

注意:单元测试通过将操作结果与它们应该评估的结果进行比较来工作。

【问题讨论】:

是时候学习如何使用编译器工具集附带的调试器了。 所以这是一个错误,而不是对矩阵如何工作的误解? 所以我认为您从未使用过调试器?调试器允许您单步执行程序以确定它与您计划的方法相悖的地方。 谢谢,我之前已经试过调试了,我会继续努力的。我主要只是不知道我在寻找什么,因为我不完全理解矩阵是如何工作的,这就是为什么我认为这可能是一个概念问题而不是代码问题。我想在这种情况下我不应该在这里发布这个问题。我的课程似乎按照我的预测进行,但我会继续寻找。 【参考方案1】:

首先,我的类使用列主构造函数,但它放置 它在内存行专业

好吧,您发布的代码显示完全相反 (wiki):

Matrix2(float R1C1, float R1C2, float R2C1, float R2C2)
// this ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ is ROW major!

    matrix[0] = R1C1;
    matrix[1] = R2C1;  // <-- this is COLUMN major!
    matrix[2] = R1C2;  // <--
    matrix[3] = R2C2;

此外,为了应用旋转(数学是正确的),您必须在执行相反操作时将旋转矩阵乘以另一个矩阵。

【讨论】:

谢谢。我实际上对我正在做的乘法顺序有疑问。意思是说它之前工作的原因,是因为太多的东西不合适,导致结果是正确的…… 查看我的 uni 进行的单元测试中的代码,我意识到,他们不会将结果与预先计算的值进行比较,而是用预先计算的值创建一个新矩阵- 使用我的矩阵构造函数计算其中的值,这意味着在输入时切换专业以使其更易于阅读,实际上破坏了单元测试......所以这是主要问题。 @killerloader 不客气。很高兴你解决了这个问题。 我才意识到。相乘 (transformation)*(this) 进行全局变换,并且 (this)*(transformation) 相对于矩阵的旋转在局部进行。这是正确的,还是我还有什么倒退的地方? @killerloader 这是 OpenGL 的一个问题(是的,主要的专栏是一个大线索)专家(我不是),但是我能回忆起什么(小),通常是所有的转换(旋转,平移,缩放...)通过以正确的顺序乘以相对矩阵(它们有一堆...)来“预先计算”,然后应用于当前向量。要从某个中心旋转某个角度,您应该平移到原点,旋转然后平移回来。

以上是关于为啥我的矩阵旋转没有通过我学校的单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

为啥即使单元测试全部通过,我的代码覆盖率也为零?

为啥我的单元测试因错误“str”对象没有属性“光标”而失败?

为啥在这个单元测试中没有调用 finalize 函数?

为啥 ApplicationsDocumentsDirectory 为单元测试返回 null?

为啥 Xcode 找不到我的单元测试应用程序?

为啥我的 Django 单元测试不知道安装了 MessageMiddleware?