【问题标题】:Given two family instances with the same LocationPoint how can I get instance #1 and #2 to have the same orientation给定两个具有相同 LocationPoint 的家庭实例,我如何让实例 #1 和 #2 具有相同的方向
【发布时间】:2019-02-16 13:41:44
【问题描述】:

在 Revit API 中,我尝试将“特种设备”类别的族实例替换为“机械设备”类别的几乎相同版本。到目前为止,我已经能够将新实例插入与旧实例相同的位置,但我无法匹配相同的方向。 FamilyInstance 有一个方法GetTransform,我可以使用它来获取旧FamilyInstanceTransform,但是没有方法SetTransform 来设置新FamilyInstance 的转换。可用于移动新 FamilyInstance 的唯一工具是具有 MoveElementRotateElement 等功能的 ElementTransformUtils,但我不确定使用旧的 Transform 传递什么。

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

【问题讨论】:

    标签: c# revit-api


    【解决方案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 相同的位置。

    【讨论】:

      【解决方案2】:

      我找到了一个更好的解决方案,可以解决 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);
      }
      

      【讨论】:

        猜你喜欢
        • 2012-09-24
        • 1970-01-01
        • 2012-02-20
        • 2018-09-15
        • 1970-01-01
        • 2020-02-24
        • 1970-01-01
        • 2014-01-26
        • 1970-01-01
        相关资源
        最近更新 更多