0

我正在尝试制作一个可以通过四元数将位置(vector3)转换为新位置的xslt。我已经进行了以下设置,但我正在检索NaN接近 0 的非常小的值。如何使用从四元数到右向量计算的值进一步计算?

<xsl:template name="object_markingtape_position">
  <xsl:param name="sign"/> <!-- left or right (-1 or 1) -->
  <xsl:param name="quaternion"/> <!-- quaternion in x,y,z,w -->
  <xsl:variable name="rightvec">
    <xsl:call-template name="QuatToRight">
      <xsl:with-param name="x" select="$quaternion/ns:x"/>
      <xsl:with-param name="y" select="$quaternion/ns:y"/>
      <xsl:with-param name="z" select="$quaternion/ns:z"/>
      <xsl:with-param name="w" select="$quaternion/ns:w"/>
    </xsl:call-template>
  </xsl:variable>

  Right vector y: <xsl:value-of select="number($rightvec/y)"/> <!-- results in a value with 1.5435434E-04 -->
  <xsl:element name="position" namespace="{$ns}">
    <xsl:element name="x" namespace="{$ns}">
      <xsl:value-of select="$sign * 1.5 * $rightvec/x + ns:position/ns:x"/>
    </xsl:element>
    <xsl:element name="y" namespace="{$ns}"> <!-- results into NaN -->
      <xsl:value-of select="$sign * 1.5 * $rightvec/y + ns:position/ns:y"/>
    </xsl:element>
    <xsl:element name="z" namespace="{$ns}">
      <xsl:value-of select="$sign * 1.5 * $rightvec/z + ns:position/ns:z"/>
    </xsl:element>
  </xsl:element>
</xsl:template>

<!-- Functionality for calculating the vectors from a quaternion -->
<!-- From http://nic-gamedev.blogspot.nl/2011/11/quaternion-math-getting-local-axis.html -->
<xsl:template name="QuatToRight">
  <xsl:param name="x"/>
  <xsl:param name="y"/>
  <xsl:param name="z"/>
  <xsl:param name="w"/>
  <xsl:element name="vec3">
    <xsl:element name="x">
      <xsl:value-of select="1 - 2 * ($x * $y - $w * $z)"/>
    </xsl:element>
    <xsl:element name="y">
      <xsl:value-of select="2 * ($x * $y + $w * $z)"/> 
    </xsl:element>
    <xsl:element name="z">
      <xsl:value-of select="2 * ($x * $z - $w * $y)"/>
    </xsl:element>
  </xsl:element>
</xsl:template>

可以输入的 xml 值的示例如下:

<Item>
  <position>
    <x>-106.6172</x>
    <y>0.780673563</y>
    <z>-13.0446815</z>
  </position>
  <rotation> <!-- this is where the quaternion param is filled with -->
    <x>0.0810996</x>
    <y>0.354339659</y>
    <z>-0.207844481</z>
    <w>-0.908111751</w>
  </rotation>
</Item>
4

3 回答 3

0

如果您找不到更好的解决方案,您可能不得不求助于使用扩展功能。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:quat="urn:myExtension" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="quat msxsl" version="1.0">
<xsl:param name="x"/>
<xsl:param name="y"/>
<xsl:param name="z"/>
<xsl:param name="w"/> 

<xsl:template match="*">
    <xsl:value-of select="quat:calcQuat($x, $y, $z, $w)"/>
</xsl:template>

<msxsl:script implements-prefix="quat" language="c#">
    <![CDATA[       
    public string calcQuat(double x, double y, double z, double w)
    {           
        double result = 1 - 2 * (x * y - w * z)
        return Double.ToString(result)
    }      

    ]]>
</msxsl:script>

于 2013-02-01T15:06:15.887 回答
0

我可以看到三个问题:

  • 该变量rightvec包含一个 XML 片段,但随后用作节点集 - 这需要转换才能正常工作(但它取决于 XSLT 处理器)

  • 命名模板object_markingtape_position引用当前上下文中的元素ns:position,因此其结果取决于调用它的位置 - 最好将位置作为参数传递;

  • 命名的 tamplateQuatToRight生成一个vec3包含具有值的子元素的元素,但随后使用其结果,就好像没有vec3中间元素一样。

使用 .NET XSLT 处理器,此 XSLT:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template name="object_markingtape_position">
    <xsl:param name="sign"/> <!-- left or right (-1 or 1) -->
    <xsl:param name="quaternion"/> <!-- quaternion in x,y,z,w -->
    <xsl:param name="position"/> <!-- position in x,y,z -->
    <xsl:variable name="rightvecFragment">
      <xsl:call-template name="QuatToRight">
        <xsl:with-param name="x" select="$quaternion/x"/>
        <xsl:with-param name="y" select="$quaternion/y"/>
        <xsl:with-param name="z" select="$quaternion/z"/>
        <xsl:with-param name="w" select="$quaternion/w"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="rightvec" select="msxsl:node-set($rightvecFragment)"/>

    <xsl:element name="position">
      <xsl:element name="x">
        <xsl:value-of select="$sign * 1.5 * $rightvec/x + $position/x"/>
      </xsl:element>
      <xsl:element name="y">
        <!-- results into NaN -->
        <xsl:value-of select="$sign * 1.5 * $rightvec/y + $position/y"/>
      </xsl:element>
      <xsl:element name="z">
        <xsl:value-of select="$sign * 1.5 * $rightvec/z + $position/z"/>
      </xsl:element>
    </xsl:element>
  </xsl:template>

  <!-- Functionality for calculating the vectors from a quaternion -->
  <!-- From http://nic-gamedev.blogspot.nl/2011/11/quaternion-math-getting-local-axis.html -->
  <xsl:template name="QuatToRight">
    <xsl:param name="x"/>
    <xsl:param name="y"/>
    <xsl:param name="z"/>
    <xsl:param name="w"/>
    <xsl:element name="x">
      <xsl:value-of select="1 - 2 * ($x * $y - $w * $z)"/>
    </xsl:element>
    <xsl:element name="y">
      <xsl:value-of select="2 * ($x * $y + $w * $z)"/>
    </xsl:element>
    <xsl:element name="z">
      <xsl:value-of select="2 * ($x * $z - $w * $y)"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="/*">
    <xsl:call-template name="object_markingtape_position">
      <xsl:with-param name="sign" select="1"/>
      <xsl:with-param name="position" select="position"/>
      <xsl:with-param name="quaternion" select="rotation"/>
    </xsl:call-template>
  </xsl:template>

</xsl:stylesheet>

应用于示例输入会产生:

<position>
  <x>-104.63717236709732</x>
  <y>1.4331220235568977</y>
  <z>-12.129909788264223</z>
</position>
于 2013-02-01T15:14:19.090 回答
0

我通过一些数据丢失解决了这个问题,但这是迄今为止最干净的解决方案。我用过format-number()

<xsl:template name="QuatToRight">
  <xsl:param name="x"/>
  <xsl:param name="y"/>
  <xsl:param name="z"/>
  <xsl:param name="w"/>
  <xsl:element name="vec3">
    <xsl:element name="x">
      <xsl:value-of select="format-number(1 - 2 * ($x * $y - $w * $z),'0.000000')"/>
    </xsl:element>
    <xsl:element name="y">
      <xsl:value-of select="format-number(2 * ($x * $y + $w * $z),'0.000000')"/> 
    </xsl:element>
    <xsl:element name="z">
      <xsl:value-of select="format-number(2 * ($x * $z - $w * $y),'0.000000')"/>
    </xsl:element>
  </xsl:element>
</xsl:template>
于 2013-02-04T10:25:53.063 回答