Трансформация объектов из модели на бумагу

Автор Тема: Трансформация объектов из модели на бумагу  (Прочитано 6080 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн avcАвтор темы

  • ADN Club
  • *****
  • Сообщений: 809
  • Карма: 166
    • Мои плагины к Автокаду
Для пересчета точек из пространства модели на пространство бумаги через вьюпорт, я использую вот такую матрицу трансформации:
Код - C# [Выбрать]
  1.    static Matrix3d ModelToPaper(this Viewport vp)
  2.     {
  3.       if (vp.PerspectiveOn)
  4.         throw new NotSupportedException("Perspective views not supported");
  5.       if (vp.Number == 1)
  6.         throw new NotSupportedException("Viewport.Number == 1");
  7.       // которкий метод - 4 перемножения матриц:
  8.       Point3d center = vp.ViewCenter.To3d();
  9.       return Matrix3d.Displacement(new Vector3d(vp.CenterPoint.X - center.X, vp.CenterPoint.Y - center.Y, 0.0))
  10.          * Matrix3d.Scaling(vp.CustomScale, center)
  11.          * Matrix3d.Rotation(vp.TwistAngle, Vector3d.ZAxis, Point3d.Origin)
  12.          * Matrix3d.WorldToPlane(new Plane(vp.ViewTarget, vp.ViewDirection));
  13.       // альтернативный метод:
  14.       // return vp.DCS2PSDCS() * vp.DCS2WCS().Inverse(); // тут 6 перемножений и инверсия
  15.     }
  16.  
  17.     /// <summary>
  18.     /// Gets the transformation matrix from the specified model space viewport Display Coordinate System (DCS)
  19.     /// to the World Coordinate System (WCS).
  20.     /// </summary>
  21.     /// <param name="vp">The instance to which this method applies.</param>
  22.     /// <returns>The DCS to WDCS transformation matrix.</returns>
  23.     static Matrix3d DCS2WCS(this Viewport vp)
  24.     {
  25.       return
  26.           Matrix3d.Rotation(-vp.TwistAngle, vp.ViewDirection, vp.ViewTarget)
  27.           * Matrix3d.Displacement(vp.ViewTarget - Point3d.Origin)
  28.           * Matrix3d.PlaneToWorld(vp.ViewDirection);
  29.     }
  30.  
  31.     /// <summary>
  32.     /// Gets the transformation matrix from the specified paper space viewport Display Coordinate System (DCS)
  33.     /// to the paper space Display Coordinate System (PSDCS).
  34.     /// </summary>
  35.     /// <param name="vp">The instance to which this method applies.</param>
  36.     /// <returns>The DCS to PSDCS transformation matrix.</returns>
  37.     static Matrix3d DCS2PSDCS(this Viewport vp)
  38.     {
  39.       return
  40.           Matrix3d.Scaling(vp.CustomScale, vp.CenterPoint)
  41.           * Matrix3d.Displacement(vp.CenterPoint.GetAsVector())
  42.           * Matrix3d.Displacement(vp.ViewCenter.To3d().GetAsVector().Negate());
  43.     }
Все эти формулы я конечно где-то нашел тут на форумах, не сам придумал. Возникла пара вопросов. А с матричной арифметикой я на Вы :(

1. После трансформации точки оказываются с не нулевым Z, что бессмысленно на бумаге.  Не сложно сбросить Z на ноль после преобразований, но постоянно забывается. Нельзя ли что-то добавить в матрицу чтоб результат оказывался всегда в плоскости XY ? Попробовал более сложный вариант (помечен в коде как альтернативный) - результат идентичен.

2. Как работать с перспективными видами? Существует-ли такая матрица трансформации, чтоб учесть перспективность?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Нельзя ли что-то добавить в матрицу чтоб результат оказывался всегда в плоскости XY ?
Не мудри. Самый простой и самый быстрый вариант - обнулить Z.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение avc 30-04-2019, 16:31:53

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
2. Как работать с перспективными видами? Существует-ли такая матрица трансформации, чтоб учесть перспективность?
Я не проверял, но посмотри здесь метод ModelToPaper: http://www.theswamp.org/index.php?topic=34590.msg398539#msg398539

На всякий случай дублирую код:
Код - C# [Выбрать]
  1. private static Matrix3d ModelToPaper(Viewport vp)
  2. {
  3.     Vector3d vd = vp.ViewDirection;
  4.     Point3d vc = new Point3d(vp.ViewCenter.X, vp.ViewCenter.Y, 0);
  5.     Point3d vt = vp.ViewTarget;
  6.     Point3d cp = vp.CenterPoint;
  7.     double ta = -vp.TwistAngle;
  8.     double vh = vp.ViewHeight;
  9.     double height = vp.Height;
  10.     double width = vp.Width;
  11.     double scale = vh / height;
  12.     double lensLength = vp.LensLength;
  13.     Vector3d zaxis = vd.GetNormal();
  14.     Vector3d xaxis = Vector3d.ZAxis.CrossProduct(vd);
  15.     Vector3d yaxis;
  16.  
  17.     if (!xaxis.IsZeroLength())
  18.     {
  19.         xaxis = xaxis.GetNormal();
  20.         yaxis = zaxis.CrossProduct(xaxis);
  21.     }
  22.     else if (zaxis.Z < 0)
  23.     {
  24.         xaxis = Vector3d.XAxis * -1;
  25.         yaxis = Vector3d.YAxis;
  26.         zaxis = Vector3d.ZAxis * -1;
  27.     }
  28.     else
  29.     {
  30.         xaxis = Vector3d.XAxis;
  31.         yaxis = Vector3d.YAxis;
  32.         zaxis = Vector3d.ZAxis;
  33.     }
  34.     Matrix3d pcsToDCS = Matrix3d.Displacement(Point3d.Origin - cp);
  35.     pcsToDCS = pcsToDCS * Matrix3d.Scaling(scale, cp);
  36.     Matrix3d dcsToWcs = Matrix3d.Displacement(vc - Point3d.Origin);
  37.     Matrix3d mxCoords = Matrix3d.AlignCoordinateSystem(Point3d.Origin, Vector3d.XAxis, Vector3d.YAxis, Vector3d.ZAxis, Point3d.Origin,
  38.         xaxis, yaxis, zaxis);
  39.     dcsToWcs = mxCoords * dcsToWcs;
  40.     dcsToWcs = Matrix3d.Displacement(vt - Point3d.Origin) * dcsToWcs;
  41.     dcsToWcs = Matrix3d.Rotation(ta, zaxis, vt) * dcsToWcs;
  42.  
  43.     Matrix3d perspectiveMx = Matrix3d.Identity;
  44.     if (vp.PerspectiveOn)
  45.     {
  46.         double vSize = vh;
  47.         double aspectRatio = width / height;
  48.         double adjustFactor = 1.0 / 42.0;
  49.         double adjstLenLgth = vSize * lensLength * Math.Sqrt(1.0 + aspectRatio * aspectRatio) * adjustFactor;
  50.         double iDist = vd.Length;
  51.         double lensDist = iDist - adjstLenLgth;
  52.         double[] dataAry = new double[] {1,0,0,0,0,1,0,0,0,0,
  53.             (adjstLenLgth-lensDist)/adjstLenLgth,lensDist*(iDist-adjstLenLgth)/adjstLenLgth,
  54.             0,0,-1.0/adjstLenLgth,iDist/adjstLenLgth};
  55.  
  56.         perspectiveMx = new Matrix3d(dataAry);              
  57.     }
  58.     Matrix3d finalMx = pcsToDCS.Inverse() * perspectiveMx * dcsToWcs.Inverse();
  59.     return finalMx;
  60.  
  61. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн avcАвтор темы

  • ADN Club
  • *****
  • Сообщений: 809
  • Карма: 166
    • Мои плагины к Автокаду
Не мудри. Самый простой и самый быстрый вариант - обнулить Z.
Так и делаю :) Ну то есть это не ошибка в преобразованиях, так и должно получаться, где то в стороне от плоскости листа, да?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну то есть это не ошибка в преобразованиях, так и должно получаться, где то в стороне от плоскости листа, да?
Да. Так как фактически ты преобразовываешь Point3d в Point2d.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн avcАвтор темы

  • ADN Club
  • *****
  • Сообщений: 809
  • Карма: 166
    • Мои плагины к Автокаду
Спасибо. Проверил. Код рабочий, хоть и полон загадок. Добавил себе такой хелпер:
Код - C# [Выбрать]
  1.     static Matrix3d PerspectiveToPaper(this Viewport vp)
  2.     {
  3.       if (!vp.PerspectiveOn) return Matrix3d.Identity;
  4.       double aspectRatio = vp.Width / vp.Height;
  5.       double adjstLenLgth = vp.ViewHeight * vp.LensLength * Sqrt(1.0 + aspectRatio * aspectRatio) / 42.0;
  6.       double iDist = vp.ViewDirection.Length;
  7.       double lensDist = iDist - adjstLenLgth;
  8.       return new Matrix3d(new double[]
  9.           {1,0,0,0,
  10.            0,1,0,0,
  11.            0,0, (adjstLenLgth-lensDist)/adjstLenLgth, lensDist*(iDist-adjstLenLgth)/adjstLenLgth,
  12.            0,0, -1.0/adjstLenLgth, iDist/adjstLenLgth});
  13.     }
Обратное преобразование тоже работает
Код - C# [Выбрать]
  1.     static Matrix3d PaperToModel(this Viewport vp)
  2.     {
  3.       if (vp.Number == 1)
  4.         throw new NotSupportedException("Viewport.Number == 1");
  5.       return vp.DCS2WCS() * vp.PerspectiveToPaper().Inverse() * vp.DCS2PSDCS().Inverse();
  6.     }

Чтоб добить тему остался еще один вопрос: направление взгляда. Очевидно, что в перспективном виде одним vp.ViewDirection не обойтись. Там должен быть целый веер в зависимости от точки на вьюпорте. А как бы это вычислить?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Чтоб добить тему остался еще один вопрос: направление взгляда. Очевидно, что в перспективном виде одним vp.ViewDirection не обойтись. Там должен быть целый веер в зависимости от точки на вьюпорте. А как бы это вычислить?
Я не очень понимаю физического смысла этого направления, но думаю, что нужно выполнить преобразование двух точек, определяющих направление взгляда в модели по той матрице, которую ты получил. Нормированная разница этих двух точек и даст тебе искомый вектор.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн avcАвтор темы

  • ADN Club
  • *****
  • Сообщений: 809
  • Карма: 166
    • Мои плагины к Автокаду
Точно! Вот она рыба моей мечты:
Код - C# [Выбрать]
  1.     static Vector3d PerspectiveViewDirection(this Viewport vp, Point3d paperPoint)
  2.     {
  3.       if (!vp.PerspectiveOn) return vp.ViewDirection;
  4.       Matrix3d paperToModel = vp.PaperToModel();
  5.       Point3d p1 = paperPoint.TransformBy(paperToModel);
  6.       Point3d p2 = (new Point3d(paperPoint.X, paperPoint.Y, paperPoint.Z+100)).TransformBy(paperToModel); // 100 по Z - строго от балды
  7.       return p2.GetVectorTo(p1);
  8.     }

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
avc,
Код - C# [Выбрать]
  1. Point3d p2 = (paperPoint + Vector3d.ZAxis).TransformBy(paperToModel); // Это вместо "от балды"
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение