给定两个具有相同LocationPoint的家庭实例,如何使实例#1和#2具有相同的方向

时间:2018-09-20 15:23:48

标签: c# revit-api

在Revit API中,我试图用“机械设备”类别的几乎相同版本替换“特殊设备”类别的族实例。到目前为止,我已经能够将新实例与旧实例插入相同的位置,但是我无法匹配相同的方向。 FamilyInstance有一种方法GetTransform,我可以用它来获得旧Transform的{​​{1}},但是没有方法FamilyInstance来设置新的SetTransform。唯一可用于移动新FamilyInstance的工具是FamilyInstance,其功能类似于ElementTransformUtilsMoveElement,但我不确定使用旧的{{1 }}。

如何确保新RotateElement的方向与旧Transform的方向匹配?

2 个答案:

答案 0 :(得分:1)

在Wikipedia中检查how to determine the axis and the angle of rotation后,我能够为此编写代码。我还必须抬头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相同的位置。

答案 1 :(得分: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);
}