Учитывая два семейных экземпляра с одним и тем же LocationPoint, как я могу получить экземпляры № 1 и № 2, имеющие одинаковую ориентацию - PullRequest
0 голосов
/ 20 сентября 2018

В Revit API я пытаюсь заменить семейный экземпляр категории «Специальное оборудование» практически идентичной версией категории «Механическое оборудование».До сих пор я был в состоянии вставить новый экземпляр в том же месте, что и старый, но я не смог соответствовать той же ориентации.У FamilyInstance есть метод GetTransform, который я могу использовать для получения Transform старого FamilyInstance, но нет метода SetTransform для установки преобразования для нового FamilyInstance.Единственными инструментами, доступными для перемещения нового FamilyInstance, являются ElementTransformUtils с такими функциями, как MoveElement и RotateElement, но я не уверен, что передать в них, используя старый Transform.

Какмогу ли я убедиться, что ориентация нового FamilyInstance совпадает с ориентацией старого FamilyInstance?

Ответы [ 2 ]

0 голосов
/ 22 сентября 2018

Я нашел лучшее решение, которое учитывает поворот на 0 или 180 градусов.Мое первое решение не будет работать в этом случае.Я нашел решение и java-версию кода на 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);
}
0 голосов
/ 20 сентября 2018

Я смог написать код для этого после проверки в Википедии на как определить ось и угол поворота .Мне также пришлось посмотреть , как рассчитать трассу , чтобы определить угол.

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, чтобы повернуть * 1009.* # 2 в том же положении, что и FamilyInstance # 1.

...