给定两个具有相同 LocationPoint 的系列实例,如何让实例 #1 和 #2 具有相同的方向

Given two family instances with the same LocationPoint how can I get instance #1 and #2 to have the same orientation

在 Revit API 中,我试图用几乎相同版本的类别 "Mechanical Equipment" 替换 "Specialty Equipment" 类别的系列实例。到目前为止,我已经能够将新实例插入到与旧实例相同的位置,但我无法匹配相同的方向。 FamilyInstance 有一个方法 GetTransform,我可以用它来获取旧 FamilyInstanceTransform,但是没有方法 SetTransform 来设置转换新 FamilyInstance。唯一可用于移动新 FamilyInstance 的工具是具有 MoveElementRotateElement 等功能的 ElementTransformUtils 但我不确定使用旧的 [=12 将什么传递给它们=].

如何确保新 FamilyInstance 的方向与旧 FamilyInstance 的方向一致?

在查看维基百科 how to determine the axis and the angle of rotation. I also had to look up how to calculate the trace 以确定角度后,我能够为此编写代码。

private static Line GetRotationAxisFromTransform(Transform transform)
{
  double x = transform.BasisY.Z - transform.BasisZ.Y;
  double y = transform.BasisZ.X - transform.BasisX.Z;
  double z = transform.BasisX.Y - transform.BasisY.X;

  return Line.CreateUnbound(transform.Origin, new XYZ(x, y, z));
}

private static double GetRotationAngleFromTransform(Transform transform)
{
  double x = transform.BasisX.X;
  double y = transform.BasisY.Y;
  double z = transform.BasisZ.Z;

  double trace = x + y + z;

  return Math.Acos((trace - 1) / 2.0);
}

然后我将这些传递给 ElementTransformUtils.RotateElement 方法,以便将 FamilyInstance #2 旋转到与 FamilyInstance #1 相同的位置。

我找到了一个更好的解决方案,可以解决 0 度或 180 度旋转问题。我的第一个解决方案在这种情况下不起作用。我在 euclideanspace.com.

找到了解决方案和代码的 java 版本

这是我的代码,从 Transform 获取矩阵,然后调用函数获取轴和角度。

double[][] matrix = new double[][]
{
    new double[]{ oldTransform.BasisX.X, oldTransform.BasisY.X, oldTransform.BasisZ.X },
    new double[]{ oldTransform.BasisX.Y, oldTransform.BasisY.Y, oldTransform.BasisZ.Y },
    new double[]{ oldTransform.BasisX.Z, oldTransform.BasisY.Z, oldTransform.BasisZ.Z }
};


GetAxisAngleFromMatrix(matrix, out double angleOfRotation, out XYZ axisOfRotation);

Line rotationLine = Line.CreateUnbound(oldTransform.Origin, axisOfRotation);

这是数学函数

public void GetAxisAngleFromMatrix(double[][] m, out double angleOfRotation, out XYZ axisOfRotation)
{
  double angle, x, y, z; // variables for result
  double epsilon = 0.01; // margin to allow for rounding errors
  double epsilon2 = 0.1; // margin to distinguish between 0 and 180 degrees
                         // optional check that input is pure rotation, 'isRotationMatrix' is defined at:
                         // https://www.euclideanspace.com/maths/algebra/matrix/orthogonal/rotation/

  if ((Math.Abs(m[0][1] - m[1][0]) < epsilon)
    && (Math.Abs(m[0][2] - m[2][0]) < epsilon)
    && (Math.Abs(m[1][2] - m[2][1]) < epsilon))
  {
    // singularity found
    // first check for identity matrix which must have +1 for all terms
    //  in leading diagonaland zero in other terms
    if ((Math.Abs(m[0][1] + m[1][0]) < epsilon2)
      && (Math.Abs(m[0][2] + m[2][0]) < epsilon2)
      && (Math.Abs(m[1][2] + m[2][1]) < epsilon2)
      && (Math.Abs(m[0][0] + m[1][1] + m[2][2] - 3) < epsilon2))
    {
      // this singularity is identity matrix so angle = 0
      angleOfRotation = 0;
      axisOfRotation = new XYZ(1, 0, 0);

      return;
    }

    // otherwise this singularity is angle = 180
    angle = Math.PI;
    double xx = (m[0][0] + 1) / 2;
    double yy = (m[1][1] + 1) / 2;
    double zz = (m[2][2] + 1) / 2;
    double xy = (m[0][1] + m[1][0]) / 4;
    double xz = (m[0][2] + m[2][0]) / 4;
    double yz = (m[1][2] + m[2][1]) / 4;
    if ((xx > yy) && (xx > zz))
    { // m[0][0] is the largest diagonal term
      if (xx < epsilon)
      {
        x = 0;
        y = 0.7071;
        z = 0.7071;
      }
      else
      {
        x = Math.Sqrt(xx);
        y = xy / x;
        z = xz / x;
      }
    }
    else if (yy > zz)
    { // m[1][1] is the largest diagonal term
      if (yy < epsilon)
      {
        x = 0.7071;
        y = 0;
        z = 0.7071;
      }
      else
      {
        y = Math.Sqrt(yy);
        x = xy / y;
        z = yz / y;
      }
    }
    else
    { // m[2][2] is the largest diagonal term so base result on this
      if (zz < epsilon)
      {
        x = 0.7071;
        y = 0.7071;
        z = 0;
      }
      else
      {
        z = Math.Sqrt(zz);
        x = xz / z;
        y = yz / z;
      }
    }

    angleOfRotation = angle;
    axisOfRotation = new XYZ(x, y, z); // return 180 deg rotation

    return;
  }
  // as we have reached here there are no singularities so we can handle normally
  double s = Math.Sqrt((m[2][1] - m[1][2]) * (m[2][1] - m[1][2])
    + (m[0][2] - m[2][0]) * (m[0][2] - m[2][0])
    + (m[1][0] - m[0][1]) * (m[1][0] - m[0][1])); // used to normalise
  if (Math.Abs(s) < 0.001) s = 1;
  // prevent divide by zero, should not happen if matrix is orthogonal and should be
  // caught by singularity test above, but I've left it in just in case
  angle = Math.Acos((m[0][0] + m[1][1] + m[2][2] - 1) / 2);
  x = (m[2][1] - m[1][2]) / s;
  y = (m[0][2] - m[2][0]) / s;
  z = (m[1][0] - m[0][1]) / s;

  angleOfRotation = angle;
  axisOfRotation = new XYZ(x, y, z);
}