Сообщество программистов Autodesk в СНГ

ADN Club => ObjectARX => Тема начата: begiz от 30-09-2015, 15:18:51

Название: Проекция полилинии на 3д поверхность
Отправлено: begiz от 30-09-2015, 15:18:51
Проекция полилинии на 3д поверхность

Добрый день,
Вопрос наверно не новый, но ответов не нашел.

в наличии:
1. триангулированая 3д поверхность, созданная по 3д точкам.
2. полилиния над этой поверхностью.

Задача:
получить профиль высот по этой полинии.

Т.е. нужно построить 3д полинию (проекцию полинии на 3д поверхность).

Первая мысль делать луч из точкек( через какой-то шаг) на полинии в сорону -Z и собирать пересечения с 3д поверхностю, из которых потом создать 3д полинию. Потом эту 3д полинию спроектировать на некую плоскость для получения профиля.

Но тут может получится много лишних точек и если шаг будет не правельный есть вероятность непоймать изменение направления поверхности.

Может кто сталкивался и есть идеи/предложения?

Autocad 2012-2015.
Командами, если такие узе есть, ползоваться не хотелось бы.

Спасибо
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Александр Ривилис от 30-09-2015, 16:48:11
в наличии:
1. триангулированая 3д поверхность, созданная по 3д точкам.
2. полилиния над этой поверхностью.
Я правильно понимаю, что у тебя есть массив AcDbFace, каждый элемент которого соответствует одной из граней поверхности (ну или массив структур, содержащих по три точки)? Если да, то задача совсем простая (если её решать в лоб):
Проходишь по всем вершинам полилинии и проецируешь их на плоскости "соответствующих" AcDbFace. "Соответствующий" - этот тот, для которого проекция вершины на плоскость X0Y лежит внутри проекции AcDb3dFace на плоскость X0Y, т.е. точка внутри треугольника. Из полученных точек строишь 3D-полилинию. Для более быстрого поиска "соответствующего" AcDbFace можно использовать дополнительные алгоритмы (всякие там "деревья").
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: begiz от 30-09-2015, 17:14:58
не совсем так.
взял пример и переписал на ObjectARX.
http://through-the-interface.typepad.com/through_the_interface/2009/04/triangulating-an-autocad-polyface-mesh-from-a-set-of-points-using-net.html (http://through-the-interface.typepad.com/through_the_interface/2009/04/triangulating-an-autocad-polyface-mesh-from-a-set-of-points-using-net.html)
Получился AcDbPolyFaceMesh(хотя это наверно не очень важно ибо его можно разбить на AcDbFace).

Так вот, если мы возьмем полилинию из 2 точек например, то проверяя только эти вершины у нас получится прямая (в 3д пространстве),
а на самом деле должна быть ломаная, потому что под линией будут перепады высоты.
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Александр Ривилис от 30-09-2015, 17:57:22
(хотя это наверно не очень важно ибо его можно разбить на AcDbFace
Именно так. Так что считай, что у тебя есть массив AcDbFace.
Так вот, если мы возьмем полилинию из 2 точек например, то проверяя только эти вершины у нас получится прямая (в 3д пространстве),
а на самом деле должна быть ломаная, потому что под линией будут перепады высоты.
Тогда проецируй на плоскость X0Y и саму свою полилинию и все AcDbFace, находи точки пересечения проекции полилинии с проекциями всех AcDbFace и восстанавливай координату Z для этих точек по исходным AcDbFace.
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: begiz от 30-09-2015, 18:11:19
Спасибо,
это наверно самый правильный способ.
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Алексей Кулик от 30-09-2015, 21:20:24
Останется вопрос с дуговыми сегментами, я думаю. Кроме того, еще вариант расположения полилинии (кстати, какой? LWPOLYLINE? 3DPOLYLINE? 2DPOLYLINE? Подозреваю, что LWPOLYLINE) не в мировой системе координат - все становится совсем весело...
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: begiz от 30-09-2015, 22:39:23
Да действительно это будет LWPOLYLINE.
Есть такая функция в Map 3D вроде, "quick profile", которая делает то что мне нужно.
так вот цель как бы сделать тоже самое только в обычном ACAD.

Может все таки по полилинии идти шагом, но тогда все таки нужна какая то идея как отфильтровать лишние вершины в результате.

Хотя даже арка в проекции на треугольную поверхность будет прямой, мне кажется получится правильно.
А пользовательские координаты конечно нужно будет приводить к мировым. 
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Алексей Кулик от 30-09-2015, 23:52:31
По-моему, дуга при проецировании ее на плоскую поверхность (которая не параллельная и не перпендикулярна плоскости дуги) даст в результате как минимум часть эллипса.
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Александр Ривилис от 30-09-2015, 23:56:37
Может все таки по полилинии идти шагом
Ты таким образом можешь пропустить место стыковки двух треугольников, образующих профиль, так что категорически не советую.
А пользовательские координаты конечно нужно будет приводить к мировым. 
Причем здесь пользовательская система координат? Ты имеешь дело с примитивами AutoCAD, так что всё будет в мировой системе координат. А вот если у полилинии будут дуги (маловероятно на профиле), то их нужно аппроксимировать линейными сегментами. Иначе в качестве проекции ты получишь эллиптические дуги, которые потом тоже придётся аппроксимировать.
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Алексей Кулик от 30-09-2015, 23:58:46
Александр, а разве для LWPOLYLINE координаты хранятся в мировой системе, а не в OCS?
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Александр Ривилис от 01-10-2015, 00:02:47
Александр, а разве для LWPOLYLINE координаты хранятся в мировой системе, а не в OCS?
1) OCS (или ECS) - это не UCS (ПСК). Это система координат объекта.
2) В ObjectARX у класса AcDbPolyline (т.е. у примитива LWPOLYLINE) есть метод:
Код - C++ [Выбрать]
  1. Acad::ErrorStatus getPointAt( unsigned int, AcGePoint3d& pt) const;
Он возвращает координаты сразу в WCS (МСК):
Цитировать
This function sets pt to the 3D location of the vertex index in World Coordinates.


Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Александр Ривилис от 01-10-2015, 01:09:30
взял пример и переписал на ObjectARX.
http://through-the-interface.typepad.com/through_the_interface/2009/04/triangulating-an-autocad-polyface-mesh-from-a-set-of-points-using-net.html
Кстати, не слишком удачный алгоритм. Ограничение в 32K вершин чревато последствиями...
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: begiz от 01-10-2015, 06:56:13
Цитировать
Кстати, не слишком удачный алгоритм. Ограничение в 32K вершин чревато последствиями...
Что касается количества вершин, меня это вполне устраивает.
чертежи для построения это топографические планы с пикетами, вряд ли кто-то больше на измеряет.
а вот сам алгоритм взял первый который нашел, т.к. про триангуляцию ничего не знаю.
Может есть варианты по практичней? Данных алгоритм периодически либо не захватывает все предложенные вершины, либо строит модель с пересекающимися ребрами.

Цитировать
По-моему, дуга при проецировании ее на плоскую поверхность (которая не параллельная и не перпендикулярна плоскости дуги) даст в результате как минимум часть эллипса.

полилинии будут представлять собой инженерные коммуникации, которые тоже строятся по точкам, поэтому все отрезки мне кажется будут прямыми участками.

вопрос остается лишь в том что делать в случае поворота полилинии посередине AcDbFace, т.е. вершина линии будет внутри треугольника.   
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Александр Ривилис от 01-10-2015, 10:22:03
Что касается количества вершин, меня это вполне устраивает.
чертежи для построения это топографические планы с пикетами, вряд ли кто-то больше на измеряет.
"Никогда не говори никогда". 32K пикетов - это всего лишь сетка приблизительно 180 x 180.
вопрос остается лишь в том что делать в случае поворота полилинии посередине AcDbFace, т.е. вершина линии будет внутри треугольника. 
Я как-то забыл упомянуть, что кроме пересечений проекции полилинии со всеми гранями проекций AcDbFace необходимо добавить еще все вершины проекции полилинии. Думал что это само-собой разумеется.
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Николай Горлов от 01-10-2015, 10:24:49
господи, а накрутили то ))). вот на пальцах, как это делается на практике:
1. апроксимировать дуговые сегменты в исходной полилинии -> на выходе массив точек, упорядоченный по увеличению длинны полилинии от начала до конца (включает в себя узловые точки и точки, добавленные в результате аппроксимации договых сегментов)
2. находим точки пересечения полилинии и сторон треугольников (без использования Z, только XY)
2.1. если по простому, то создаем полилинию [например, AcDbPolyline] из точек пункта 1 (можно без добавления в БД)
2.2. запускаем цикл на выдирание двух точек из треугольника (можно сразу сформировать три линии, чтоб было проще). это будут отрезки[AcDbLine] (так же создаем без добавления в БД), с которыми нужно проверить пересечение без удлинений объектов [intersectWith] из 2.1. если оно есть, полученную точку вставляем согласно длины до точки от начала в массив точек из пункта 1. и вставляем только в том случае, если еще нет точки с приблизительно такими координатами (при пересечении внутри сетки будет как минимум 2 одинаковых точки пересечения, т.к. два соседних треугольника имеют общую грань, так что перед вставкой проверяем, нет ли уже в массиве точки с длиной +/-погрешность).
3. всё, у нас есть в 2D полный набор точек, которым просто пользуясь базовыми знаниями геометрии нужно прицепить координату Z (в илдеале, пишется функция, где на вход XY точка и сетка, на выход координата Z)

PS: да, чтоб не заниматься постоянной ерундой с поиском длины от начала для выбранной точки - сделай это на первом этапе и запихни длину в координату Z. и еще. всё, что мы там насоздавали без добавления в БД нужно за собой поудалять.

Цитировать
чертежи для построения это топографические планы с пикетами, вряд ли кто-то больше на измеряет.
не хочется огорчать, но если человеку на спину повесить GPS ранец и отправить гулять на пару часиков по карьеру для съемки бровок ))), то точек будет значительно больше чем 32К.
Цитировать
Данных алгоритм периодически либо не захватывает все предложенные вершины, либо строит модель с пересекающимися ребрами.
значит в помощь википендия ))) там есть основные алгоритмы, правда нет реализации ))). хотя скорей всего просто что-то недопереводил с C#, т.к. там реализация простейшего алгоритма, который плохо работает только при большом перепаде Z. в любом случае реализаций триангуляций куча в сети и на разных языках.
Цитировать
а вот сам алгоритм взял первый который нашел, т.к. про триангуляцию ничего не знаю.
:o а вот это уже настораживает. как можно найти правильное решение в вопросе, о котором ничего не знаешь? если в задаче стоит построить сетку и найти путь по ней используя плановую проекцию, то "что такое триангуляция" - придется выучить. правда, если сетку дают уже готовую, то голову можно и не забивать.
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Александр Ривилис от 01-10-2015, 13:03:03
а вот сам алгоритм взял первый который нашел, т.к. про триангуляцию ничего не знаю.
Может есть варианты по практичней? Данных алгоритм периодически либо не захватывает все предложенные вершины, либо строит модель с пересекающимися ребрами.
Я когда-то использовал этот алгоритм: http://paulbourke.net/papers/triangulate/cpp.zip
И вообще можешь глянуть сюда: http://paulbourke.net/papers/triangulate/
Название: Re: Проекция полилинии на 3д поверхность
Отправлено: Николай Горлов от 01-10-2015, 14:13:03
вот, поковырялся у себя в тестовых функциях, думаю пригодится )))
Код - C++ [Выбрать]
  1. Acad::ErrorStatus FindTrianglePt(AcGePoint3d vertex1, AcGePoint3d vertex2, AcGePoint3d vertex3, AcGePoint3d &resPt)
  2. {
  3.         Acad::ErrorStatus es = Acad::eAmbiguousInput;
  4.         double minZ = vertex1.z, maxZ = vertex1.z;
  5.         if (minZ > vertex2.z) minZ = vertex2.z;
  6.         if (minZ > vertex3.z) minZ = vertex3.z;
  7.         if (maxZ < vertex2.z) maxZ = vertex2.z;
  8.         if (maxZ < vertex3.z) maxZ = vertex3.z;
  9.  
  10.         AcGeVector3d vecU(vertex2.asVector()-vertex1.asVector());
  11.         AcGeVector3d vecV(vertex3.asVector()-vertex1.asVector());
  12.         AcGePlane plane(vertex1, vecU, vecV); // плоскость по трем точкам треугольника
  13.         AcGeLineSeg3d line (AcGePoint3d(resPt.x,resPt.y,minZ), AcGePoint3d(resPt.x,resPt.y,maxZ));//линия для поиска пересечений с плоскостью
  14.         AcGePoint3d resultPoint;//временная точка, чтоб не поганить основную, если ничего не нужно
  15.         if (plane.intersectWith(line, resultPoint) == Adesk::kTrue)
  16.         {
  17.                 resPt = resultPoint;
  18.                 es = Acad::eOk;
  19.         }
  20.         return es;
  21. }
  22.  
в коде проверок нет, так что перед вызовом нужно убедиться на 100%, что точка лежит внутри или на границах треугольника, т.к. работа идет не с ограниченным рамками треугольником, а с бесконечной плоскостью.
vertex1, vertex2, vertex3 - это точки треугольника в 3D, resPt - это точка для которой нужно найти Z. то, что там лежит в Z на момент запуска - игнорируется.
ну и пример для тестирования функции
Код - C++ [Выбрать]
  1. AcDbObjectId eId;
  2. AcDbFace* pFace;
  3. AcDbPoint* pPoint;
  4. AcGePoint3d resPt;
  5. ads_name entcont;
  6.  
  7. if ( RTNORM != acedEntSel(_T("\nУкажите 3DFace: "),entcont,asDblArray(resPt)) ) return;
  8. acdbGetObjectId(eId,entcont);
  9. if(acdbOpenObject(pFace, eId, AcDb::kForRead)!= Acad::eOk) return;
  10. if (pFace == NULL) return;
  11.  
  12. if ( RTNORM != acedEntSel(_T("\nУкажите точку: "),entcont,asDblArray(resPt)) ) return;
  13. acdbGetObjectId(eId,entcont);
  14. if(acdbOpenObject(pPoint, eId, AcDb::kForRead)!= Acad::eOk) return;
  15. if (pPoint == NULL) return;
  16.  
  17. AcGePoint3d vertex1, vertex2, vertex3; // тут три точки треугольника в пространстве
  18. pFace->getVertexAt(0, vertex1);
  19. pFace->getVertexAt(1, vertex2);
  20. pFace->getVertexAt(2, vertex3);
  21. resPt = pPoint->position(); // отсюда нужна только плановая проекция (Z игнорируется)
  22. pPoint->close();
  23. pFace->close();
  24.  
  25. if (Acad::eOk == FindTrianglePt(vertex1, vertex2, vertex3, resPt))
  26.         addPoint(false,resPt,1,_T("0"),ACDB_MODEL_SPACE); // это нарисует примитив "точка" в автокаде. функция не ObjectARX, так что работать не будет )))
  27.