c# - 旋转3D点的两种方式,有什么区别
问题描述
我需要围绕 Y 轴旋转一个 3D 点
我不是数学家,所以我搜索了互联网并找到了这个页面 https://www.siggraph.org/education/materials/HyperGraph/modeling/mod_tran/3drota.htm#Y-Axis%20Rotation
使用此代码
private void RotateAroundY_1()
{
double x = 40.46;
double y = 16.52;
double z = 56.5;
double b = -1* 64.77; // rotation degree (mult with -1 to get the rotation counter clockwise
double B = DegreeToRadian(b); // B
double X = x * Math.Cos(B) + z*Math.Sin(B);
double Y = y;
double Z = z*Math.Cos(B) - x*Math.Sin(B);
Console.WriteLine(string.Format("X: {0} Y: {1} Z: {2}",X,Y,Z));
}
private double DegreeToRadian(double b)
{
return (Math.PI / 180) * b;
}
我得到这个结果
X: -33,8639291270836
Y: 16,52
Z: 60,6835719455922
但是,旋转坐标应该是(根据 3D CAD 程序及其用户)
X: 68.38
Y: 16,52
Z: -12.5
如果我使用此代码
private void RotateAroundY_2()
{
double x = 40.46;
double y = 16.52;
double z = 56.5;
double b = -1* 64.77; // rotation degree (mult with -1 to get the rotation counter clockwise
double curAng = Math.Atan2(z, x);
double X = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(z, 2));
double Y = Math.Cos(DegreeToRadian(b) + curAng) * hyp;
double Z = Math.Sin(DegreeToRadian(b) + curAng) * hyp;
Console.WriteLine(string.Format("X: {0} Y: {1} Z: {2}",X,Y,Z));
}
private double DegreeToRadian(double b)
{
return (Math.PI / 180) * b;
}
我得到这个结果
X: 68,3563218478633
Y: 16,52
Z: -12,5169830003609
所以我将使用 RotateAroundY_2,但我希望我能理解其中的区别以及为什么我应该使用第二个?
ELI5(像我五岁一样解释)
解决方案
你的-
标志错了,它应该在另一个窦......我没有用C#编码,所以所有的代码块都在C++中(需要移植它,但应该足够简单)。
void rotate_y(double &x,double &y,double &z,double ang)
{
double u=x,v=z;
ang*=M_PI/180.0;
x=+u*cos(ang)-v*sin(ang);
z=+u*sin(ang)+v*cos(ang);
}
像这样使用它:
double x=40.46,y=16.52,z=56.5,ang=-64.77;
mm_log->Lines->Add(AnsiString().sprintf("(%03.3f,%03.3f,%03.3f)",x,y,z));
rotate_y(x,y,z,ang);
mm_log->Lines->Add(AnsiString().sprintf("(%03.3f,%03.3f,%03.3f)",x,y,z));
导致此输出:
(40.460,16.520,56.500)
(68.356,16.520,-12.517)
当你得到另一个减号时,sin
你正在以相反的方式旋转,所以将角度乘以-1
也会导致你想要的结果。
void rotate_y(double &x,double &y,double &z,double ang)
{
double u=x,v=z;
ang*=-M_PI/180.0;
x=+u*cos(ang)+v*sin(ang);
z=-u*sin(ang)+v*cos(ang);
}
像这样:
(40.460,16.520,56.500)
(68.356,16.520,-12.517)
您还可以稍微优化旋转:
void rotate_y(double &x,double &y,double &z,double ang)
{
double u=x,v=z,c,s;
ang*=M_PI/180.0;
c=cos(ang);
s=sin(ang);
x=+u*c-v*s;
z=+u*s+v*c;
}
避免多次sin,cos
使用。
您获得的另一个轮换代码非常缓慢且不准确,因为它会中继atan2
(这也有进入子结果的潜在危险NaN
)。它只是将您的点转换为极坐标添加增量角度并转换回笛卡尔。
推荐阅读
- sql-server - 使用 If 语句创建触发器
- c++ - C++ 结构可以在不同的编译时间有不同的对齐方式吗?
- javascript - 在不使用按钮的情况下单击时如何更改标签的文本?
- javascript - 单击项目时使用参数运行脚本
- caching - Drupal - 运行这 4 个步骤是否安全
- sql - 编写具有相同条件但不同列并使用聚合函数的查询
- swift - 如何在 swift 上使用 hsplitview
- react-native - 在抽屉导航器中制作自定义抽屉时“超出最大更新深度”
- node.js - Sequelize 内连接无法获得正确的值
- neo4j - 在一个查询中计算关系的最高和最低出现 [Neo4j]