Преобразование вершин LWPOLYLINE, записанных в формате DXF

Автор Тема: Преобразование вершин LWPOLYLINE, записанных в формате DXF  (Прочитано 14639 раз)

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

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Доброго времени суток.

Как пересчитать в глобальную систему координат координаты вершин полилинии, которая сохранена в DXF файле как LWPOLYLINE? Из DXF файла можно прочитать координаты вершин и некоторые три числа, по которым и вычисляются глобальные координаты. Как из этих трёх чисел получить матрицу направляющих косинусов, дабы можно было выполнить обозначенное преобразование?

P.S. Преобразование будет выполняться во внешнем приложении, а не в плагине AutoCAD.

Спасибо.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Группа 210 у примитива LWPOLYLINE содержит вектор нормали примитива. По этому вектору используя Arbitrary Axis Algorithm можно получить матрицу преобразования: http://www.autodesk.com/techpubs/autocad/acad2000/dxf/arbitrary_axis_algorithm_dxf_ab.htm
Следует еще учесть возможность того, что у этой полилинии есть уровень (т.е.  группа 38 отлична от 0) - в этом случае потребуется дополнительный сдвиг.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Для нас это чревато, т.к. мы мосты проектируем. Хотелось бы ссылку и для второго варианта.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Объясняю на пальцах:
1) Получаем матрицу преобразования mat ОСК->МСК (алгоритм по ссылке, которую я дал)
2) Создаем вектор v = [0 0 Z], где Z - уровень полилинии (группа 38)
3) Преобразуем вектор v по матрице преобразования mat и получаем вектор v_wcs
4) Преобразуем точку p_ocs (группа 10) полилинии по матрице mat и получаем точку p_wcs
5) Складываем точку p_wcs и вектор v_wcs - это и будет искомая точка.
Как-то так.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Уважаемые коллеги! Можете на моем примере показать, как перевести координаты точки из OCS в WCS? Без использования функций Autocad, простой арифметикой. Мне надо считать узлы полилиний из DXF в стороннем приложении, а в справке по "Arbitrary Axis Algorithm" я мало что понял... Заранее спасибо
Например, для узла LWPOLYLINE:
...
38
500.0
10
-100.0
20
430.0
...
210
-0.216
220
0.976
230
0.0

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

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

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
А так: https://forums.autodesk.com/t5/autocad-r12-r13-r14-archive/dxf-arbitrary-axis-algorithm-in-vb6/td-p/35267 ?
Спасибо, именно так я и пробовал посчитать, но где-то ошибся. Потому и прошу, если есть время и возможность, показать на конкретной точке из моего примера.

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

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

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
вот пример на С, попробовал сделать как описано в http://www.autodesk.com/techpubs/autocad/acad2000/dxf/arbitrary_axis_algorithm_dxf_ab.htm#XREF_24259_DXF_AB


Код - C++ [Выбрать]
  1. struct vector
  2. {
  3.   double x;
  4.   double y;
  5.   double z;
  6. };
  7.  
  8. void cross_product(vector v1,vector v2,vector &result)
  9. {
  10.   result.x = v1.y*v2.z - v1.z*v2.y;
  11.   result.y = v1.z*v2.x - v1.x*v2.z;
  12.   result.z = v1.x*v2.y - v1.y*v2.x;
  13. }
  14.  
  15. void calcOCS2WCS()
  16. {
  17.   vector N;  //Let the given normal vector be called N
  18.   vector Wy;  //Let the world Y axis be called Wy, which is always (0,1,0)
  19.   vector Wz;  //Let the world Z axis be called Wz, which is always (0,0,1)
  20.  
  21.   vector Ax,Ay,Az;
  22.  
  23.   N.x = -0.1525427977445352; //код 210
  24.   N.y = 0.6904568740017512;  //код 220
  25.   N.z = 0.7071067811865475;  //код 230
  26.  
  27.   Wy.x = 0.;
  28.   Wy.y = 1.;
  29.   Wy.z = 0.;
  30.  
  31.   Wz.x = 0.;
  32.   Wz.y = 0.;
  33.   Wz.z = 1.;
  34.  
  35.   if((fabs(N.x)<1/64.)&&(fabs(N.y)<1/64.))
  36.   {
  37.     cross_product(Wy,N,Ax);
  38.   }
  39.   else
  40.   {
  41.     cross_product(Wz,N,Ax);
  42.   }
  43.  
  44.   cross_product(N,Ax,Ay);
  45.  
  46.   Az = N; //N could also be called Az
  47.  
  48.   //Исходная точка в OCS
  49.   double OCS_X = 100.0;
  50.   double OCS_Y = 120.0;
  51.   double OCS_Z = 50.0;
  52.  
  53.   //То что нужно вычислить
  54.   double WCS_X;
  55.   double WCS_Y;
  56.   double WCS_Z;
  57.  
  58.   //Предполагаю, что Ax,Ay,Az представляют матрицу коэффициентов афинных преобразований
  59.   WCS_X = OCS_X*Ax.x + OCS_Y*Ax.y + OCS_Z*Ax.z;
  60.   WCS_Y = OCS_X*Ay.x + OCS_Y*Ay.y + OCS_Z*Ay.z;
  61.   WCS_Z = OCS_X*Az.x + OCS_Y*Az.y + OCS_Z*Az.z;
  62.  
  63. }

« Последнее редактирование: 03-03-2016, 15:05:56 от Александр Ривилис »

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
//Исходная точка в OCS
  double OCS_X = 100.0;
  double OCS_Y = 120.0;
  double OCS_Z = 50.0;
Она у тебя вроде бы была совсем другая:
Цитировать
10
-100.0
20
430.0

Не учтена группа 38. Я выше писал, что с ней нужно делать.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
//Исходная точка в OCS
  double OCS_X = 100.0;
  double OCS_Y = 120.0;
  double OCS_Z = 50.0;
Она у тебя вроде бы была совсем другая:
Цитировать
10
-100.0
20
430.0

Не учтена группа 38. Я выше писал, что с ней нужно делать.

Я взял произвольную точку для примера, пусть группа 38 будет 0.0, тогда ее можно и не учитывать


Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Правильно ли я считаю Ax, Ay, Az? И как правильно их использовать для последующего пересчета координат? Я ради интереса нашел для своего примера коэффициенты афинного преобразования с помощью метода наименьших квадратов, они совсем другие чем Ax,Ay,Az

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я не увидел, чтобы ты у себя в коде нормировал Ax (и Ay и Az). Ты должен разделить их Ax.x, Ax.y, Ax.z на sqrt(Ax.x*Ax.x+Ax.y*Ax.y+Ax.z*Ax.z) (аналогично для Ay и Az). В результате получаешь матрицу преобразования:
| Ax.x  Ay.x  Az.x |
| Ax.y  Ay.y  Az.y |
| Ax.z  Ay.z  Az.z |
Произведение вектора координаты в OCS на эту матрицу даст вектор координаты в WCS
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Спасибо! Правда, уже сам успел разобраться.

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

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

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Да, все получилось. Пришлось немного геометрию вспоминать)

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

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

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Да, конечно, сейчас оформлю и выложу

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Вот пример реализации на С того, что описано в http://www.autodesk.com/techpubs/autocad/acad2000/dxf/arbitrary_axis_algorithm_dxf_ab.htm

Код - C++ [Выбрать]
  1. struct vector_axis
  2. {
  3.   double x;
  4.   double y;
  5.   double z;
  6. };
  7.  
  8. void vector_cross_product(vector_axis v1,vector_axis v2,vector_axis &result)
  9. {
  10.   result.x = v1.y*v2.z - v1.z*v2.y;
  11.   result.y = v1.z*v2.x - v1.x*v2.z;
  12.   result.z = v1.x*v2.y - v1.y*v2.x;
  13. }
  14.  
  15. void calcOCS2WCS()
  16. {
  17.   vector_axis N,Wy,Wz;
  18.   vector_axis Ax,Ay,Az;
  19.  
  20.   //Значения кодов 210,220,230
  21.   N.x = -0.1525427977445352;
  22.   N.y = 0.6904568740017512;
  23.   N.z = 0.7071067811865475;
  24.  
  25.   Wy.x = 0.;
  26.   Wy.y = 1.;
  27.   Wy.z = 0.;
  28.  
  29.   Wz.x = 0.;
  30.   Wz.y = 0.;
  31.   Wz.z = 1.;
  32.  
  33.   if((fabs(N.x)<1/64.)&&(fabs(N.y)<1/64.))
  34.   {
  35.     vector_cross_product(Wy,N,Ax);
  36.   }
  37.   else
  38.   {
  39.     vector_cross_product(Wz,N,Ax);
  40.   }
  41.  
  42.   double mx = sqrt((Ax.x*Ax.x + Ax.y*Ax.y + Ax.z*Ax.z));
  43.   double k = 1./mx;
  44.  
  45.   Ax.x = Ax.x*k;
  46.   Ax.y = Ax.y*k;
  47.   Ax.z = Ax.z*k;
  48.  
  49.   vector_cross_product(N,Ax,Ay);
  50.  
  51.   mx = sqrt((Ay.x*Ay.x + Ay.y*Ay.y + Ay.z*Ay.z));
  52.   k = 1./mx;
  53.  
  54.   Ay.x = Ay.x*k;
  55.   Ay.y = Ay.y*k;
  56.   Ay.z = Ay.z*k;
  57.  
  58.   Az = N;
  59.  
  60.   // Точка в OCS
  61.   double OCS_X = 100.0;
  62.   double OCS_Y = 120.0;
  63.   double OCS_Z = 50.0;
  64.  
  65.   // Точка в WCS
  66.   double WCS_X;
  67.   double WCS_Y;
  68.   double WCS_Z;
  69.  
  70.   WCS_X = OCS_X*Ax.x + OCS_Y*Ay.x + OCS_Z*Az.x; //-86.967351702583287
  71.   WCS_Y = OCS_X*Ax.y + OCS_Y*Ay.y + OCS_Z*Az.y; //-69.904790521388321
  72.   WCS_Z = OCS_X*Ax.z + OCS_Y*Ay.z + OCS_Z*Az.z; //120.20815280171308
  73.  
  74. }
« Последнее редактирование: 04-03-2016, 12:55:58 от bavilla »

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
1. По поводу форматирования кода на форуме прочитай у меня в подписи.
2. Похоже ты забыл, что не только Ax нужно нормировать (делить на длину Ax), но тоже самое нужно сделать и для Ay.
3. Остался пока открытым вопрос с ненулевой группой 38 (уровнем).
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Спасибо за замечания!
По 38 группе - если я правильно понимаю, для LWPOLYLINE она задает Z-координату для всех точек полилинии. В моем примере это OCS_Z

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я из спортивного интереса нарисовал полилинию с двумя вершинами в "хитрой" системе координат:
Цитировать
  0
LWPOLYLINE
  5
24E
330
1F
100
AcDbEntity
  8
0
100
AcDbPolyline
 90
        2
 70
     0
 43
0.0
38
10.0
10
103.3406489926814
 20
96.54382562220856
 10
206.6812979853627
 20
193.0876512444171

210
-0.6446022880805341
220
-0.4835076803238965
230
0.5922062252873951


Координаты вершин в WCS:
Цитировать
Command: ID Specify point:  X = 101.3001374     Y = -53.1972967     Z = 83.7157678
Command:  ID Specify point:  X = 209.0462978     Y = -101.5595166     Z = 161.5094733

Если твоя программа выдаст эти же результаты, то всё в порядке.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Да, считает правильно. Я добавил еще нормирование Ay(подправил в предыдущем сообщении), но для моих данных это ни на что не влияло, т.к. Ay и так получается единичным.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Подтверждаю:

Немного переделал твой код для удобства проверки:
Код - C++ [Выбрать]
  1. #include "stdafx.h"
  2. #include <conio.h>
  3. #include <math.h>
  4.  
  5. struct vector_axis
  6. {
  7.   double x, y, z;
  8. };
  9.  
  10. void vector_cross_product(vector_axis v1,vector_axis v2,vector_axis &result)
  11. {
  12.   result.x = v1.y * v2.z - v1.z * v2.y;
  13.   result.y = v1.z * v2.x - v1.x * v2.z;
  14.   result.z = v1.x * v2.y - v1.y * v2.x;
  15. }
  16.  
  17. void vector_normalize(vector_axis &v)
  18. {
  19.   double k = sqrt((v.x*v.x + v.y*v.y + v.z*v.z));
  20.   v.x /= k; v.y /= k; v.z /= k;
  21. }
  22.  
  23. void GetOCStoWCSMatrix(vector_axis norm, vector_axis &Ax, vector_axis &Ay, vector_axis &Az)
  24. {
  25.   vector_axis Wy,Wz;
  26.  
  27.   Wy.x = 0.;  Wy.y = 1.;  Wy.z = 0.;
  28.   Wz.x = 0.;  Wz.y = 0.;  Wz.z = 1.;
  29.  
  30.   if ((fabs(norm.x)<1/64.) && (fabs(norm.y)<1/64.))
  31.   {
  32.     vector_cross_product(Wy,norm,Ax);
  33.   }
  34.   else
  35.   {
  36.     vector_cross_product(Wz,norm,Ax);
  37.   }
  38.  
  39.   vector_normalize(Ax);
  40.   vector_cross_product(norm,Ax,Ay);
  41.   vector_normalize(Ay);
  42.   Az = norm;
  43. }
  44.  
  45. void TransWithMatrix(vector_axis pIn, vector_axis Ax, vector_axis Ay, vector_axis Az, vector_axis &pOut)
  46. {
  47.   pOut.x = pIn.x * Ax.x + pIn.y * Ay.x + pIn.z * Az.x;
  48.   pOut.y = pIn.x * Ax.y + pIn.y * Ay.y + pIn.z * Az.y;
  49.   pOut.z = pIn.x * Ax.z + pIn.y * Ay.z + pIn.z * Az.z;
  50. }
  51.  
  52. int _tmain(int argc, _TCHAR* argv[])
  53. {
  54.   vector_axis norm, Ax, Ay, Az;
  55.   norm.x = -0.6446022880805341;
  56.   norm.y = -0.4835076803238965;
  57.   norm.z = 0.5922062252873951;
  58.   GetOCStoWCSMatrix(norm,Ax,Ay,Az);
  59.   vector_axis p;
  60.   p.x = 103.3406489926814;  p.y = 96.54382562220856;  p.z = 10;
  61.   TransWithMatrix(p, Ax, Ay, Az, p);
  62.   _tprintf (_T("\nx=%f y=%f z=%f"), p.x, p.y, p.z);
  63.   p.x = 206.6812979853627;  p.y = 193.0876512444171;  p.z = 10;
  64.   TransWithMatrix(p, Ax, Ay, Az, p);
  65.   _tprintf (_T("\nx=%f y=%f z=%f"), p.x, p.y, p.z);
  66.   _getch();
  67.         return 0;
  68. }
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн bavilla

  • ADN OPEN
  • Сообщений: 12
  • Карма: 2
Я специально написал пример максимально близко к описанию в справке, без всякой оптимизации и проверок, чтобы тому, кто захочет воспользоваться, была понятна суть.