- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
如何将Wintracker II设备的四元数方向输出仅转换为Euler Angles输出。因为Wintracker II设备输出欧拉角和四元数方向。我只想输出欧拉角。
最佳答案
我已经实现了本文描述的算法,并且效果很好:
http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/quat_2_euler_paper_ver2-1.pdf
答案1中列出的Wikipedia文章的问题在于,它仅提供X-Y-Z旋转的公式。此处引用的论文给出了适用于12个序列中任何一个序列的通用算法。您可能需要阅读几次,并且一定可以通过示例工作。这不是最简单的方法,但是我已经对它进行了单元测试,而且非常安全。
根据第一条评论,这是我代码的主要组成部分。应该足以让您前进:
第一类是“ AxisType”。我使用的主要功能是其上的“ getNextCircular()”。这也使我的代码轻松转换为Vector。
public enum AxisType {
X("X"),
Y("Y"),
Z("Z");
String label;
AxisType(final String label) {
this.label = label;
}
/**
* Converts an axis type to a vector.
*
* @return
*/
public Vector3D toVector3D() {
if (equals(AxisType.X)) {
return new Vector3D(1,0,0);
} else if (equals(AxisType.Y)) {
return new Vector3D(0,1,0);
} else {
return new Vector3D(0,0,1);
}
}
/**
* gets the next circular axis from this one circular: </br> <code>
* X --> Y
* </br>
* Y --> Z
* </br>
* Z --> X
* </code>
*
* @return
*/
public AxisType nextCircular() {
if (equals(AxisType.X)) {
return AxisType.Y;
} else if (equals(AxisType.Y)) {
return AxisType.Z;
} else {
return AxisType.X;
}
}
@Override
public String toString() {
return label;
}
}
public class EulerOrder
{
private final AxisType[] axisOrder;
/**
* generic constructor
*
* @param first
* @param second
* @param third
*/
public EulerOrder(
final AxisType first,
final AxisType second,
final AxisType third )
{
axisOrder = new AxisType[] {
first,
second,
third
};
}
/**
* @return the cartesian axis that represent this sequence
*/
public Vector3D[] orderedAxis()
{
return new Vector3D[] {
axisOrder[0].toVector3D(),
axisOrder[1].toVector3D(),
axisOrder[2].toVector3D()
};
}
public AxisType getAxisType(
final int index )
{
if ((index > 2) || (index < 0))
{
throw new ArrayIndexOutOfBoundsException(
"EulerOrder[index] called with an invalid index");
}
return axisOrder[index];
}
/**
* <code>
* X->Y->*
* </br>
* Y->Z->*
* </br>
* Z->X->*
* </code>
*
* @return true if the first two rotations are in a circular order
*/
public boolean isCircular()
{
// true if the first 2 roations are in one of these orders
// X-Y
// Y-Z
// Z-X
return axisOrder[0].nextCircular().equals(
axisOrder[1]);
}
/**
* <code>
* X->*->X
* </br>
* Y->*->Y
* </br>
* Z->*->Z
* </code>
*
* @return true if the first and last axis are the same
*/
public boolean isRepeating()
{
// returns true if the first and last axis are the same
// X->*->X
// Y->*->Y
// Z->*->Z
return axisOrder[0] == axisOrder[2];
}
@Override
public String toString()
{
final StringBuffer buffer = new StringBuffer();
buffer.append(axisOrder[0].toString());
buffer.append(axisOrder[1].toString());
buffer.append(axisOrder[2].toString());
return buffer.toString();
}
/* STATIC CONSTRUCTORS FOR THE 12 POSSIBLE EULER SEQUENCES */
public static EulerOrder XYZ()
{
return new EulerOrder(
AxisType.X,
AxisType.Y,
AxisType.Z);
}
public static EulerOrder YZX()
{
return new EulerOrder(
AxisType.Y,
AxisType.Z,
AxisType.X);
}
public static EulerOrder ZXY()
{
return new EulerOrder(
AxisType.Z,
AxisType.X,
AxisType.Y);
}
public static EulerOrder ZYX()
{
return new EulerOrder(
AxisType.Z,
AxisType.Y,
AxisType.X);
}
public static EulerOrder YXZ()
{
return new EulerOrder(
AxisType.Y,
AxisType.X,
AxisType.Z);
}
public static EulerOrder XZY()
{
return new EulerOrder(
AxisType.X,
AxisType.Z,
AxisType.Y);
}
public static EulerOrder XYX()
{
return new EulerOrder(
AxisType.X,
AxisType.Y,
AxisType.X);
}
public static EulerOrder XZX()
{
return new EulerOrder(
AxisType.X,
AxisType.Z,
AxisType.X);
}
public static EulerOrder YZY()
{
return new EulerOrder(
AxisType.Y,
AxisType.Z,
AxisType.Y);
}
public static EulerOrder YXY()
{
return new EulerOrder(
AxisType.Y,
AxisType.X,
AxisType.Y);
}
public static EulerOrder ZXZ()
{
return new EulerOrder(
AxisType.Z,
AxisType.X,
AxisType.Z);
}
public static EulerOrder ZYZ()
{
return new EulerOrder(
AxisType.Z,
AxisType.Y,
AxisType.Z);
}
public static EulerOrder parse(String eulerOrder)
{
if(eulerOrder.equals("XYZ")) return XYZ();
if(eulerOrder.equals("XZY")) return XZY();
if(eulerOrder.equals("YZX")) return YZX();
if(eulerOrder.equals("YXZ")) return YXZ();
if(eulerOrder.equals("ZYX")) return ZYX();
if(eulerOrder.equals("ZXY")) return ZXY();
if(eulerOrder.equals("XYX")) return XYX();
if(eulerOrder.equals("XZX")) return XZX();
if(eulerOrder.equals("YZY")) return YZY();
if(eulerOrder.equals("YXY")) return YXY();
if(eulerOrder.equals("ZYZ")) return ZYZ();
if(eulerOrder.equals("ZXZ")) return ZXZ();
return null;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
EulerOrder that = (EulerOrder) o;
if (!Arrays.equals(axisOrder, that.axisOrder)) return false;
return true;
}
@Override
public int hashCode() {
return axisOrder != null ? Arrays.hashCode(axisOrder) : 0;
}
}
/**
* This class is a direct implementation of the algorithm described in the
* paper: "Quaternion to Euler Angle Conversion for Arbitrary Rotation Sequence
* Using Geometric Methods" by Noel H Hughes
*
* All variables are named using the names that the author uses in the paper to
* ensure tracability with the original document
*
* The general algorithm for this is really quite simple: Given a unit
* quaternion and a desired sequence, decompose that quaternion into a sequence
* of 3 rotations about the principle axis in the correct sequence.
*
* This involves 2 steps: step 1: take the last axis of rotation and rotate it
* through the quaternion. From this, you can determine (with some clever trig
* and the knowledge of the order of the first two rotations) what the first two
* angles are step 2: construct a quaternion from the first 2 rotations, and run
* the next circular axis after the last axis (ie, if the last axis of rotation
* is 'X', then use 'Y') through the original quaternion and the new 2-step one.
* The included angle between these two vectors must be your third Euler angle.
* Using some clever cross product tests you can determine the sign and you're
* done!
*
* Note - This has been tested extensively to make sure that the angles that are
* returned produce an equivalent rotation using the same sequence as the
* original. This does not, in fact, quarantee that you will get the same
* angles! There is a 'short way' and a 'long way' to get from here to there,
* and as of yet I haven't figured out how to force one over the other
*/
public class EulerAngleDecomposer
{
private static EulerAngleDecomposer instance = null;
// made the constructor private because this is a singleton
private EulerAngleDecomposer()
{
}
public static EulerAngleDecomposer getInstance()
{
if(instance == null)
instance = new EulerAngleDecomposer();
return instance;
}
private class IndexData
{
// for all of these indices:
// 0 = X
// 1 = Y
// 2 = Z
private final AxisType m_i1; // zero based index of first euler rotation
private final AxisType m_i1n; // next circular index following i1
private final AxisType m_i1nn; // next circular index following i1n
private final AxisType m_i2; // zero based index of second euler rotation
private final AxisType m_i2n; // next circular index following i2
private final AxisType m_i2nn; // next circular index following i2n
private final AxisType m_i3; // zero based index of third euler rotation
private final AxisType m_i3n; // next circular index following i3
private final AxisType m_i3nn; // next circular index following i3n
// m_unitAxis[0] = first euler rotation axis
// m_unitAxis[1] = second euler rotation axis
// m_unitAxis[2] = third euler rotation axis
private final Vector3D[] m_unitAxis;
// create from a EulerOrder
public IndexData(
final EulerOrder order )
{
m_i1 = order.getAxisType(0);
m_i2 = order.getAxisType(1);
m_i3 = order.getAxisType(2);
// now populate m_ixn, ans ixnn's
m_i1n = m_i1.nextCircular();
m_i1nn = m_i1n.nextCircular();
m_i2n = m_i2.nextCircular();
m_i2nn = m_i2n.nextCircular();
m_i3n = m_i3.nextCircular();
m_i3nn = m_i3n.nextCircular();
m_unitAxis = order.orderedAxis();
}
// first axis of rotation
public Vector3D V1()
{
return m_unitAxis[0];
}
// second axis of rotation
public Vector3D V2()
{
return m_unitAxis[1];
}
// third axis of rotation
public Vector3D V3()
{
return m_unitAxis[2];
}
// next axis after V3 (circular)
// a little table:
// V3() --> V3n()
// X --> Y
// Y --> Z
// Z --> X
public Vector3D V3n()
{
return m_i3n.toVector3D();
}
// first rotation axis
public AxisType i1()
{
return m_i1;
}
// next circular axis folowing i1()
// not to be confused with the second axis of rotation (i2)
public AxisType i1n()
{
return m_i1n;
}
// next circular axis following i1n()
// not to be confused with the third axis of rotation (i3)
public AxisType i1nn()
{
return m_i1nn;
}
}
public RotationSequence DecomposeFromQuaternion(
final Quaternion q,
final EulerOrder order )
{
// crappy variable name, I know
// it's used a lot, so I wanted a one letter
// one!
final IndexData d = new IndexData(
order);
final Vector3D v3Rot = q.Rotate(
d.V3()).unit(); // q->GetRotatedVector(d.V3()).unit();
// recall:
// i1; // zero based index of first euler rotation
// i1n; // next circular index following i1
// i1nn; // next circular index following i1n
Angle theta1 = Angle.Zero();
Angle theta2 = Angle.Zero();
Angle theta3 = Angle.Zero();
if (order.isRepeating())
{
if (order.isCircular())
{
// circular, repeating
//theta1 = atan2( v3Rot[d.i1n()], -v3Rot[d.i1nn()]);
theta1 = Angle.fromRadians(org.apache.commons.math3.util.FastMath.atan2(
v3Rot.at(d.i1n()),
-v3Rot.at(d.i1nn())));
theta2 = Angle.fromRadians(-org.apache.commons.math3.util.FastMath.acos(v3Rot.at(d.i1())));
}
else
{
// non circular, repeating
theta1 = Angle.fromRadians(org.apache.commons.math3.util.FastMath.atan2(
v3Rot.at(d.i1nn()),
v3Rot.at(d.i1n())));
theta2 = Angle.fromRadians(org.apache.commons.math3.util.FastMath.acos(v3Rot.at(d.i1())));
}
// By convention, repeating sequences restrict theta2 to 0-->180
if (theta2.radians() < 0)
{
// need to resolve the ambiguity restrict theta2 to 0 --> 180
theta2 = theta2.negate();
//theta1 = theta1 - pi;
}
// special case where theta2 is zero, which is somewhat nonsense
// for a repeating sequence
// in this case, put all the entire angle into theta3
if ((theta2.radians() == 0) || (theta2.radians() == Math.PI))
{
theta1 = Angle.Zero();
}
}
else
// non-repeating sequence
{
if (order.isCircular())
{
// circular, non-repeating
theta1 = Angle.fromRadians(org.apache.commons.math3.util.FastMath.atan2(
-v3Rot.at(d.i1n()),
v3Rot.at(d.i1nn())));
theta2 = Angle.fromRadians(-org.apache.commons.math3.util.FastMath.asin(-v3Rot.at(d.i1())));
}
else
{
// non circular, non repeating
theta1 = Angle.fromRadians(org.apache.commons.math3.util.FastMath.atan2(
v3Rot.at(d.i1nn()),
v3Rot.at(d.i1n())));
theta2 = Angle.fromRadians(-org.apache.commons.math3.util.FastMath.asin(v3Rot.at(d.i1())));
}
}
// Create the Q12 quaternion using the first two axis and angles
final Quaternion Q1 = Quaternion.createFromAxisAngle(
d.V1(),
theta1);
final Quaternion Q2 = Quaternion.createFromAxisAngle(
d.V2(),
theta2);
final Quaternion Q12 = Q1.times(Q2);
/* Q12 = Q1 * Q2 */
// get the next circular vector after V3
final Vector3D V3n = d.V3n();
// rotate V3n through Q12 and q
final Vector3D V3n12 = Q12.Rotate(V3n);
final Vector3D V3nG = q.Rotate(V3n);
// get the angle between them - theta3
theta3 = Vector3D.angleBetween(
V3n12,
V3nG);
// use a cross product to determine the direction of the angle
final Vector3D Vc = Vector3D.crossProduct(
V3n12,
V3nG);
final double m = Vector3D.dotProduct(
Vc,
v3Rot);
final double sign = m > 0 ? 1.0 : -1.0;
theta3 = Angle.fromRadians(sign * org.apache.commons.math3.util.FastMath.abs(theta3.radians()));
return new RotationSequence(
order,
theta1,
theta2,
theta3);
}
}
关于math - 欧拉角和四元数取向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2274007/
这个问题在这里已经有了答案: Converting result of Math.sin(x) into a result for degrees in java (4 个答案) 关闭 5 年前。
我在学习 Kotlin 并在数学课上遇到了这个问题: java.lang.Math 和 kotlin.math 不兼容。这对我来说有点尴尬和困惑,因为 Kotlin 声称它与 Java 100% 兼容
我在其他问题中读到,例如由于浮点表示,sin(2π) 不为零,但非常接近。这个非常小的错误在我的代码中不是问题,因为例如我可以四舍五入 5 位小数。 但是当2π乘以一个非常大的数时,误差就会放大很多。
我正在用 C# 编写一个计算器。 textBoxResult 是我显示数字的文本框 recount 是一个以度为单位的角度并以弧度为单位返回的函数 我从 texBoxInput 获取角度 public
首先,让我们从我的数学背景开始。我已经学习了微积分 I - IV 和微分方程。我参加了第一学期的计算机图形类(class),在该类(class)中我们实现了几乎我们自己的图形管道,包括使用 Phong
早上好! 我只是想磨练我的数学能力,我特别有一些关于 Cocos2D 的问题。由于 Cocos2D 想要“简化”事物,所有 Sprite 都有一个旋转属性,范围从 0-360(359?)CW。这迫使你
是否有人对Intel Math Kernel Library和AMD Math Core Library都有编程经验?我正在建立一台用于高性能统计计算的个人计算机,并对正在购买的组件进行辩论。 AMD
函数的反函数是什么 math.atan2 我在 Lua 中使用它,我可以通过 math.tan 获得 math.atan 的逆。 但我在这里迷路了。 编辑 好的,让我向您提供更多详细信息。 我需要计算
我有一道等轴测投影的数学题。我读了一篇文章:Axonometric projections - a technical overview .对于等距投影部分,它给出了将 x 部分的 3D 点转换为 2
在 MySQL (5.1) 数据库表中,有数据表示: 用户执行任务需要多长时间 用户在任务中处理了多少项目。 MySQL 是否支持关联数据,还是我需要使用 PHP/C# 来计算? 我在哪里可以找到计算
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 9 年前。 Improv
我正在尝试使用这两种方法在 C# 中解决这个问题: public double NormalPowerMethod(double x, double toPower) { return Mat
如何分配: var randomNumber = Math.random()*50 + Math.random()*20; 比较: var randomNumber = Math.random()*7
我正在查看我的代码,希望提高它的性能,然后我看到了这个: int sqrt = (int) Math.floor(Math.sqrt(n)); 哦,好的,我真的不需要调用 Math.floor,因为转
尝试调用 math.h 中的函数时, 我收到如下链接错误 undefined reference to sqrt 但我正在做一个 #include 我正在使用 gcc 并编译如下: gcc -Wall
祝大家有个愉快的一天,我有话要问你,为了更好地理解这里是我的代码: {math equation=((($order_total-$commission)+$discount+$delivery_ch
我尝试学习一些Clojure,因为该语言看起来不错。 但是似乎没有关于如何安装/使用库的信息,例如clojure.math.numeric-tower。 现在,我通过在Linux shell中键入以下
As Math.sign() 接受数字参数或数字作为字符串,如 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Gl
如何将scala.math.BigDecimal转换为java.math.BigDecimal? 最佳答案 无需在字符串之间进行双重转换。 val sb = scala.math.BigDecimal
为什么下面的 JavaScript 会这样 Math instanceof Math 抛出错误 TypeError: Expecting a function in instanceof check,
我是一名优秀的程序员,十分优秀!