代码之家  ›  专栏  ›  技术社区  ›  skeletank

给定两个具有相同位置点的族实例,如何使实例#1和#2具有相同的方向

  •  0
  • skeletank  · 技术社区  · 7 年前

    在Revit API中,我尝试将“专用设备”类别的族实例替换为“机械设备”类别的几乎相同版本。到目前为止,我已经能够将新实例插入到与旧实例相同的位置,但无法匹配相同的方向。A FamilyInstance GetTransform 我可以用来得到 Transform 古老的 但是没有办法 SetTransform 为新对象设置变换 家庭立场 ElementTransformUtils 功能如下 MoveElement RotateElement 但我不确定用旧的 变换 .

    我怎样才能确保 家庭立场 和以前的一样 ?

    2 回复  |  直到 7 年前
        1
  •  1
  •   skeletank    7 年前

    我在维基百科上查了一下 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到相同的位置 家庭立场

        2
  •  1
  •   skeletank    7 年前

    euclideanspace.com .

    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);
    }