Перпендикуляр из точки на кривую

Автор Тема: Перпендикуляр из точки на кривую  (Прочитано 11690 раз)

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

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Всем привет. Вроде я находил ответ на этот вопрос, но что-то никак не могу найти. И сам не могу придумать решение (наверно уже устал  ::) )

Задача тривиальная: имеем точку Point3D и имеем кривую Curve. Нужно провести перпендикуляр из точки на кривую

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Re: Перпендикуляр из точки на кривую
« Ответ #1 : 14-01-2016, 08:58:41 »
Код - C# [Выбрать]
  1. Gem.Point3d p = new Db.Line().GetClosestPointTo(new Gem.Point3d(1, 1, 0), false);
Не оно?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Перпендикуляр из точки на кривую
« Ответ #2 : 14-01-2016, 09:38:05 »
Задача тривиальная:
Это тебе так только кажется. А если точка за пределами кривой и опустить перпендикуляр нельзя?
Не оно?
Сработает только если реально можно провести перпендикуляр из точки на отрезок, а не на бесконечную прямую. В противном случае это будет конечная точка отрезка, ближайшая к заданной точке.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Re: Перпендикуляр из точки на кривую
« Ответ #3 : 14-01-2016, 09:52:13 »
Сработает только если реально можно провести перпендикуляр из точки на отрезок, а не на бесконечную прямую. В противном случае это будет конечная точка отрезка, ближайшая к заданной точке.
Угу, я знаю.
Есть другой путь - аналитический.
1. Узнаем какой сегмент кривой ближайший
Код - vb.net [Выбрать]
  1.                 var l = new Db.Line() as Db.Curve;
  2.                 var p1 = l.GetClosestPointTo( new Gem.Point3d(0,0,0),false);
  3.                 var l2 = l.GetParameterAtPoint(p1);
2. Выясняем прямая это или дуга.
3. Для прямой что то типа этого:
Код - vb.net [Выбрать]
  1. ' Где стырил этот код уже не помню.  
  2. Public Function perpendicular(varStart As point3d, varEnd As point3d, varBase As point3d) As point3d
  3.         '                               A                      B               C
  4.                 Dim a As point3d = varStart
  5.                 Dim b As point3d = varEnd
  6.                 Dim c As point3d = varBase
  7.                 Dim d(2) As Double
  8.                 Dim F(2) As Double
  9.                 Dim k2 As Double
  10.                
  11.                
  12.                   On Error GoTo Err_Control
  13.                 F(0) = c.x - (b.y - a.y)
  14.                 F(1) = c.y + (b.x - a.x)
  15.                 k2 = ((c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y)) / ((b.x - a.x) * (F(1) - c.y) - (F(0) - c.x) * (b.y - a.y))
  16.                     d(0) = (F(0) - c.x) * k2 + c.x
  17.                     d(1) = (F(1) - c.y) * k2 + c.y
  18.                   perpendicular = New Point3d(d(0),d(1),0)
  19.                  
  20.                 Exit_here:
  21.                   Exit Function
  22.                 Err_Control:
  23.           'MsgBox Err.Description
  24.         End Function
  25.  
для дуги:
 ищем точку пересечения прямой проведенной через заданную точку и точку центра дуги и собственно дугой, так же не сложно.

ИМХО, как то так.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Перпендикуляр из точки на кривую
« Ответ #4 : 14-01-2016, 09:54:33 »
2. Выясняем прямая это или дуга.
Главный прокол. А кто сказал, что это полилиния, у которой могут быть только прямые или дуговые сегменты??? А если это сплайн или эллипс?
P.S.: Кстати, в своём алгоритме ты забыл про Z.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Владимир Шу

  • ADN Club
  • *****
  • Сообщений: 624
  • Карма: 158
    • ПГСу Бложик
Re: Перпендикуляр из точки на кривую
« Ответ #5 : 14-01-2016, 10:03:17 »
Главный прокол. А кто сказал, что это полилиния, у которой могут быть только прямые или дуговые сегменты???
Никто не сказал, придется преобразовывать к нужному типу кривой, но ИМХО моя задача подсказать путь решения, а не предоставить готовый в продакшен код.
Код - C# [Выбрать]
  1.                 var l3 = new Db.Spline();
  2.                 var l4 = l3.ToPolyline();
P.S.: Кстати, в своём алгоритме ты забыл про Z.
не забыл, я этот код где то стырил, да и не нужна мне была Z координата, а потому она в этом коде обнулена.
По хорошему этот код нужно переписать и с использованием рабочих плоскостей, но он мне настолько давно не нужен был, что если бы не вопрос Александра, то я про него и не вспомнил бы.

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Перпендикуляр из точки на кривую
« Ответ #6 : 14-01-2016, 11:44:16 »
Еще один вариант (перпендикуляр на прямую):
Код - C# [Выбрать]
  1. // pStart - начальная точка отрезка
  2. // pEnd - конечная точка отрезка
  3. // p - точка от которой строится перпендинуляр
  4. Line line = new Line(pStart, pEnd);
  5. Point3d pNearest = line.GetClosestPointTo(p, true);
Хотя вместо Line можно воспользоваться Line3d.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Александр Пекшев aka ModisАвтор темы

  • ADN Club
  • *****
  • Сообщений: 1658
  • Карма: 366
  • Отец modplus.org
    • ModPlus
Re: Перпендикуляр из точки на кривую
« Ответ #7 : 15-01-2016, 06:19:28 »
Да, действительно - назвав задачу тривиальной, я немного перегнул =)

Хотя и надобность в решении у меня отпала, но интерес к вопросу не пропал
Придумал вариант решения. Пока не конечный. т.к. со сплайнами какая-то ерунда. Ну и может кто подкинет свежих идей и замечаний
Задумка в следующем:
1. Имеем кривую и точку. Сколько можно отложить перпендикуляров? Правильно - несколько!
2. Берем кривую и разбиваем ее на сегменты. За основу для разбивки берем Parameter (кстати, толком не пойму  - что это такое?! Хотел бы услышать толковое разъяснение)
3. Получаем ближайшую точку на сегменте к искомой точке методом GetClosestPointTo(Point3d givenPoint, bool extend). Тут-же вопрос - как работает extend? Что и куда продолжается?
4. Проверяем, что если соединить полученную и искомую точку, то образованный отрезок будет перпендикулярен кривой. Для этого используем касательную в точке
Вот код:
Код - C# [Выбрать]
  1. private static IEnumerable<Point3d> GetPerpendicularsFromPointOnCurve(Point3d point, Curve curve)
  2. {
  3.  
  4.     var pts = new List<Point3d>();
  5.     var curveParamPts = new Point3dCollection();
  6.     if (curve is Spline)
  7.     {
  8.         var spline = (Spline) curve;
  9.         for (var cpi = 0; cpi < spline.NumFitPoints; cpi++)
  10.             curveParamPts.Add(spline.GetFitPointAt(cpi));
  11.     }
  12.     else
  13.     {
  14.         for (var p = 0; p < curve.EndParam; p++)
  15.             curveParamPts.Add(curve.GetPointAtParameter(p));
  16.         curveParamPts.Add(curve.GetPointAtParameter(curve.EndParam));
  17.     }
  18.    
  19.     foreach (Curve splitCurve in curve.GetSplitCurves(curveParamPts))
  20.     {
  21.         var closestPoint = splitCurve.GetClosestPointTo(point, false);
  22.         var derInPoint = splitCurve.GetFirstDerivative(closestPoint);
  23.         var angel = (point - closestPoint).GetAngleTo(derInPoint);
  24.         if (Math.Abs(angel - Math.PI / 2) < Tolerance.Global.EqualPoint |
  25.             Math.Abs(angel - Math.PI) < Tolerance.Global.EqualPoint)
  26.             pts.Add(closestPoint);
  27.     }
  28.     return pts;
  29. }

Извините, вам запрещён просмотр содержимого спойлеров.

Хотелось бы послушать замечания и предложения. Особенно касаемо сплайнов (пока вариант работает не совсем корректно)
И еще вопрос: есть Curve.GetFirstDerivative(), а есть Curve.GetSecondDerivative() - В чем различия?

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Перпендикуляр из точки на кривую
« Ответ #8 : 15-01-2016, 21:39:17 »
За основу для разбивки берем Parameter (кстати, толком не пойму  - что это такое?! Хотел бы услышать толковое разъяснение)
Почитай в интернете что такое параметрическая кривая и параметрическая функция.
Для полилиний (кроме сглаженных) в каждой из вершин параметр равен номеру вершины и равномерно распределяется вдоль каждого сегмента (т.е. у середины первого сегмента параметр 0.5).
Для отрезка параметр и расстояние от начала отрезка - это одно и тоже. Т.е. в середине отрезка его параметр равен половине длины отрезка.
Для окружности параметр - это угол из центра в радианах от 0 до 2*PI.
Для дуги - это угол из центра дуги в радианах.
Для эллипса и эллиптической дуги параметр - это тоже угловое значение.
Для сплайна параметр это расстояние вдоль полилинии, соединяющей управляющие точки сплайна.
Для Custom Entity, унаследованного от AcDbCurve это может быть в принципе всё что угодно.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Перпендикуляр из точки на кривую
« Ответ #9 : 15-01-2016, 21:54:46 »
И еще вопрос: есть Curve.GetFirstDerivative(), а есть Curve.GetSecondDerivative() - В чем различия?
Первая производная и вторая производная. Первая производная - это касательная, вторая производная зависит от того, что это за кривая. Для дуги - она направлена к центру дуги. Для отрезков и линейных сегментов полилинии вторая производная - это нуль-вектор. На рисунке красные - первые производные, желтые - вторые.

« Последнее редактирование: 20-01-2016, 19:15:06 от Александр Ривилис »
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение