Тема: Как найти угол отрезка полилинии?
Как найти угол отрезка полилинии?
Выбираю полилинию командой ThisDrawing.Utility.GetEntity obj, point, "Select edge:"
Далее требуется определить угол отрезка полилинии, который был указан.
Информационный портал для профессионалов в области САПР
Вы не вошли. Пожалуйста, войдите или зарегистрируйтесь.
Форумы CADUser → Программирование → VBA → Как найти угол отрезка полилинии?
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Как найти угол отрезка полилинии?
Выбираю полилинию командой ThisDrawing.Utility.GetEntity obj, point, "Select edge:"
Далее требуется определить угол отрезка полилинии, который был указан.
Нужно определить между какими вершинами полилинии находится данная точка, ну а там уже чистая математика. Я бы для такой задачи воспользовался лиспом, на котором в отличии от VBA без труда можно определить угол наклона любой кривой или ломаной в любой точке, включая кривые и дуговые сегменты. Например так:
(defun c:seang(/ uPnt sSet sCurve Dr) (vl-load-com) (if (and (setq uPnt(getpoint "\nSelect point at curve -> ")) (setq sSet(ssget uPnt '((0 . "*LINE,ARC,ELLIPSE,CIRCLE") (-4 . "<NOT")(0 . "MLINE")(-4 . "NOT>")))) (setq sCurve(vlax-ename->vla-object(ssname sSet 0))) (setq Dr(vlax-curve-getFirstDeriv sCurve (vlax-curve-getParamAtPoint sCurve uPnt))) ); end and (princ (strcat "\nAngle = " (angtos (-(/ pi 2)(atan(/(car dr)(cadr dr)))))"°")) ); end if (princ) ); end of c:seang
Нужно определить между какими вершинами полилинии находится данная точка.
Т. е составить уравнения прямых проходящих через точки полилинии, проверить пренадлежность указанной точки соответствующей прямой и по координатам концов отрезка определить угол наклона.
> {Smirnoff}
Ваш код срабатыват только на, прошу прощения, curve.
А вот как изящно можно решить эту задачу в VBA:
Поместите приведенный код в модуль ThisDrawind,запустите макрос Segment_Angle, и он начнет добросовестно показывать углы ВСЕХ сегментов выбранной полилинии в радианах, начиная с указанного.
Sub Segment_Angle() ThisDrawing.SendCommand " _explode " End Sub Private Sub AcadDocument_ObjectModified(ByVal Object As Object) If (TypeOf Object Is AcadLine) Then MsgBox (Object.Angle & " rad") End If End Sub
Ну, а если серьезно, то в задании многовато неизвестных - с какой целью вам это надо, и следовательно, в каком контексте следует решать задачу?
> LeonidSN
Мой код рабатет, на линии, любые сегменты полилиний, окружности, эллипсы, дуги и сплайны и вычисляет угол наклона в заданной точке. Возможно вы не включили привязки в т. ч. Nearest, о чем я не предупредил и не сделал в этой короткой демке.
Это вы считаете изяществом ? >
ThisDrawing.SendCommand " _explode "
Да, согласен, для линии все очень просто. Но разблокировать полилинию не очень хочется.
А если через уравнения прямых - у меня точка, когда я указываю полилинию, может и не попасть на прямую?
И метод на VBA перечисляет углы всех получившихся линий, а мне надо угол только того отрезка, который был указан.
На самом деле так поступать можно. Однако не с помощью SendCommand а:
1. Использовать метод GetEntity для получения объекта полилинии и точки указания.
2. Создать копию полилинию с помощью метода Copy.
3. Взорвать копию объекта с помощью метода Explode при этом получив массив из объектов получившихся после расчленения.
4. Использовать метод SelectAtPoint для повтороного выбора именно примитива прямой.
5. Собственно измерить угол наклона сегмента.
6. Удалить все объекты получившиеся после "взрыва" методом Delete.
При всём при этом надо начиная с пункта 2. разблокировать слой (если заблокирован) на котором лежит расчленяемая полилиния, а в конце операции "Барбароса" воссановить его состояние.
Можно поступить и по другому. Вызвать простую ЛИСП-программу, которая сделает всё без этих лишних манипуляций и передать значение в среду VBA через пользовательский словарь или на худой случай переменную USERRXX.
Спасибо всем за подсказку.
На данный момент реализовал через нахождение, принадлежит ли точка прямой.
Единственный минус: командой ThisDrawing.Utility.GetEntity трудно указать точку на прямой, поэтому приходиться делать поправку на погрешность.
На данный момент реализовал через нахождение, принадлежит ли точка прямой.
И это правильно.
Единственный минус: командой ThisDrawing.Utility.GetEntity трудно указать точку на прямой, поэтому приходиться делать поправку на погрешность.
Да вроде GetEntity корректирует возвращаемую точку так чтобы она пренадлежала выббранному объекту. Во всяком аналогиченая лисповская функция ENTSEL поступает именно так. Однако погрешность всё равно учитывать надо поскольку производятся вычисления и погрешность накапливается сама собой.
> {Smirnoff}
На самом деле пункт 2 вашего описания алгоритма лишний. Т. к. метод
object.Explode
Реально не разбивает обььект , а лиш возврашхает массив с его(обььекта) составными частями
На самом деле пункт 2 вашего описания алгоритма лишний. Т. к. метод
object.Explode
Реально не разбивает объект , а лиш возвращает массив с его(объекта) составными частями
А если разок попробывать?
Sub plExplode() Dim obj As AcadObject Dim pt As Variant Dim exArr As Variant ThisDrawing.Utility.GetEntity obj, pt, "Разбей эту полилинию >" exArr = obj.Explode MsgBox "Получилось линий: " & UBound(exArr) - LBound(exArr) + 1 End Sub
> {Smirnoff}
Вот и попробуите. Полилиния obj
вашего примера останется целая и не вредимая. Зато добавятся поверх нее ешхе и осколки.
> Gogi
Да однако вы правы, я не замечал этого раньше. Это наверное потому что практически ничего не эксплодил, всегда "забираясь" внутрь объекта. Спасибо.
> {Smirnoff}
Действительно, с привязкой nearest функция seang прекрасно работает. Я добавил в ее начало строчку -
(setvar "OSMODE" 512)
и при случае ею воспользуюсь. Спасибо.
Вероятно из практических соображений, в данном случае удобнее всего использовать AutoLISP, поскольку в нем представлен целый набор подходящих встроенных функций.
Однако задание было помещено в разделе VBA, что предполагает наличие молчаливого условия. И мне показалось интересным продемонстрировать характерное развитие ситуации при выполнении заказа, в данном случае - программы. Заказчик выдает задание, Исполнитель его выполняет. Когда Заказчик знакомится с результатами работы, то понимает, что чего-то не досказал и выдвигает дополнительные условия. Исполнитель переделывает работу, и цикл повторяется.
Итак, вот программка переработанная в соответствие с дополнительными условиями:
Sub Segment_Angle() Dim plineObj As AcadLWPolyline Dim PickedPoint As Variant ThisDrawing.Utility.GetEntity plineObj, PickedPoint, "Select segment of polyline:" Dim explodedObjects As Variant explodedObjects = plineObj.Explode Dim ln As AcadLine Dim i As Integer On Error Resume Next For i = 0 To UBound(explodedObjects) Set ln = explodedObjects(i) If (BelongingCheck(PickedPoint, ln)) Then MsgBox (ln.Angle & " rad") GoTo Label End If Next i Label: For i = 0 To UBound(explodedObjects) explodedObjects(i).Delete Next End Sub Private Function BelongingCheck(PickedPoint As Variant, ln As AcadLine) As Boolean 'проверка на принадлежность PickedPoint точки отрезку ln: BelongingCheck = False Dim a As Double Dim b As Double a = Abs(ln.Delta(0) / ln.Delta(1)) b = Abs((ln.StartPoint(0) - PickedPoint(0)) / (ln.StartPoint(1) - PickedPoint(1))) a = Round(a) b = Round(b) If (a = b) Then BelongingCheck = True End If End Function
Что же касается разговоров об изящном, то мне кажется, что вы слишком уж серьезно отнеслись к моему заявлению. Хотя, с другой стороны, почему бы и не воспользоваться самым коротким путем к цели...
А позвольте усложнить вопрос.
Если выделяемый отрезок полилинии является дугой. Тут уже не обойтись только вычислением принадлежности точки прямой.
Не позволю!
Это уже новая работа, которая должна выполняться за отдельную плату.
В задании было сказано:"Как найти угол отрезка полилинии?", а не - угол в точке
> LeonidSN
Я бы всё таки воспользовался математикой и вычислил бы принадлежность точки отрезку с помощью параметрического уравнения прямой проходящей через две точки ограничив парметр условием 0<=p<=1, естественно с учётом допуска. К сожалению у меня неправильно копируется русский текст (имею ввиду пояснения к функции), но я думаю что аргументы функции понятны их названий. Единственное аргумент Segment если равен True то определяется принадлежность точки отрезку, если False то прямой.
Public Function Asmi_Is_Point_On_Line( _ ByVal X1 As Double, ByVal Y1 As Double, _ ByVal X2 As Double, ByVal Y2 As Double, _ ByVal Xp As Double, ByVal Yp As Double, _ Precision As Double, Segment As Boolean) As Boolean Dim Tx, Ty As Double If X2 <> X1 Then Tx = (Xp - X1) / (X2 - X1) End If If Y2 <> Y1 Then Ty = (Yp - Y1) / (Y2 - Y1) End If If X1 = X2 And _ (X1 - Precision <= Xp) And (Xp <= X1 + Precision) Then Tx = Ty End If If Y1 = Y2 And _ (Y1 - Precision <= Yp) And (Yp <= Y1 + Precision) Then Ty = Tx End If If (Ty - Precision <= Tx) And (Tx <= Ty + Precision) _ And (0 - Precision <= Tx) And (Tx <= 1 + Precision) Then Asmi_Is_Point_On_Line = True ElseIf (Ty - Precision <= Tx) And (Tx <= Ty + Precision) _ And Segment = False Then Asmi_Is_Point_On_Line = True Else Asmi_Is_Point_On_Line = False End If End Function
Вот кстати ещё SEANG дополненый включением-отключением привязки и обработчиком ошибок:
(defun c:seang(/ *error* oldOsm uPnt sSet sCurve Dr) (vl-load-com) (defun *error*(msg) (setvar "OSMODE" oldOsm) (princ) ); end of *error* (setq oldOsm(getvar "OSMODE")) (setvar "OSMODE" 512) (if (and (setq uPnt(getpoint "\nSelect point at curve -> ")) (setq sSet(ssget uPnt '((0 . "*LINE,ARC,ELLIPSE,CIRCLE") (-4 . "<NOT")(0 . "MLINE")(-4 . "NOT>")))) (setq sCurve(vlax-ename->vla-object(ssname sSet 0))) (setq Dr(vlax-curve-getFirstDeriv sCurve (vlax-curve-getParamAtPoint sCurve uPnt))) ); end and (princ (strcat "\nAngle = " (angtos (-(/ pi 2)(atan(/(car dr)(cadr dr)))))"°")) ); end if (setvar "OSMODE" oldOsm) (princ) ); end of c:seang
Что же касается разговоров об изящном, то мне кажется, что вы слишком уж серьезно отнеслись к моему заявлению.
Я тоже потом подумал что вы это не совсем серьёзно. Да и где время найти чтобы совсем серьёзно:(
> Alexshd
Вначале хочу сказать что был неправ когда сказал что при применении метода GetEntity координаты точки корректируются так чтобы она была на выбираемом объекте. Так происходит в ЛИСПе, при применении родственной методу GetEntity функции ENTSEL, а в VBA оказывается не так :( В следствии этого приходится применять достаточно большой допуск. Думаю что для большей точности можно воспользоваться методом GetPoint с включенной объектной привязкой, а после выбора точки воспользоваться методом SelectAtPoint для выбора полилинии. Как это выглядит можете посмотреть запустив SEANG (см. в предыдущем постинге), там выбор происходит аналогично- точка, потом примитив проходящий через точку.
А позвольте усложнить вопрос.
Если выделяемый отрезок полилинии является дугой. Тут уже не обойтись только вычислением принадлежности точки прямой.
Ну что тут сделаешь? Либо опять включать математику (исходных в свойствах дуги достаточно). Или воспользоваться ЛИСП-функциями с префиксом vlax-curve- через которые можно получить полный спектр информации о любых параметрах кривых в любой точке. Т. е. то о чём я с самого начала говорил.
И вообще какой угол у дуги вы хотите узнать? Угол наклона в выбранной точке (вычисляется через первую производную в данной точке) или угол наклона хорды соединяющей концы дуги или что либо другое?
> {Smirnoff}
Знаете, по поводу наших с вами выступлений на этой скромной ветке возникает целый ряд соображений, но я не уверен, что... мой настрой разделит большинство.
Однако, попробуем.
Форум есть место обсуждения проблем, а не обязательно вечер вопросов и ответов. Есть, например, общая проблема - взаимоотношения Заказчика и Исполнителя, проблема взаимной ответственности и компетентности. От ее нерешенности страдают многие. Однако, мы предпочитаем ее не замечать!
Конечно, для меня и, возможно, для вас проще всего написать код и таким образом отреагировать на вызовы внешнего мира. Но проблема же не исчезает, Заказчик продолжает считать себя вправе ломать без конца задание на проектирование и относиться наплевательски к работе Исполнителя. Это МЫ позволяем ему так вести себя. Так может быть следует что-то предпринять, чтобы изменить ситуацию? Для начала - обратить на нее внимание.
Возможно, мы недостаточно внимательны друг к другу - вы пишите "> LeonidSN (2006-02-08 23:06:08)
Я бы всё таки воспользовался математикой и вычислил бы принадлежность точки отрезку "
- но это именно то, что сделано в моем предыдущем посте.
Полагаю, что мы все склонны зацикливаться на собственном коде - отсюда, проблемы вызванные ограниченностью. Например, проблема точности вычислений геометрических характеристик. Я с этим сталкивался и убежден, что здесь надо привлекать специалистов по вычислительной математике, но мы продолжаем вариться в собственном соку и кустарничать.
Одним словом, я - за плодотворное обсуждение, а результат придет.
Знаете, по поводу наших с вами выступлений на этой скромной ветке возникает целый ряд соображений, но я не уверен, что... мой настрой разделит большинство.
Однако, попробуем.
Форум есть место обсуждения проблем, а не обязательно вечер вопросов и ответов. Есть, например, общая проблема — взаимоотношения Заказчика и Исполнителя, проблема взаимной ответственности и компетентности. От ее нерешенности страдают многие. Однако, мы предпочитаем ее не замечать!
Конечно, для меня и, возможно, для вас проще всего написать код и таким образом отреагировать на вызовы внешнего мира. Но проблема же не исчезает, Заказчик продолжает считать себя вправе ломать без конца задание на проектирование и относиться наплевательски к работе Исполнителя. Это МЫ позволяем ему так вести себя. Так может быть следует что-то предпринять, чтобы изменить ситуацию? Для начала — обратить на нее внимание.
Ну это очень комплексная проблемма. Тут и психология и юридические проблеммы и денежные отношения. И такое положение будет в той или иной мере будет существовать всегда, вопрос только в том насколько это затрагивает вас лично. Это явно не тема ветки Программирвание VBA, но если есть желание куча таких тем "за жизнь" поднималось на www.dwg.ru где я являюсь скромным модератором. Думаю вы и сейчас можете открыть там подобную ветку (или продолжить одну из старых) и желающих обсудить будет много. Но увы не я...
Возможно, мы недостаточно внимательны друг к другу — вы пишите "> LeonidSN (2006-02-08 23:06:08)
Я бы всё таки воспользовался математикой и вычислил бы принадлежность точки отрезку "
- но это именно то, что сделано в моем предыдущем посте.
Я внимательно посмотрел ваш код и запустил его. Однако я имел ввиду другое - то что возможно вычислить принадлежность точки соответствующему сегменту полилинии не расчленяя её. А просто обработав массив точек из свойства Coordinates вышеприведённой функцией.
Я с этим сталкивался и убежден, что здесь надо привлекать специалистов по вычислительной математике, но мы продолжаем вариться в собственном соку и кустарничать.
Это конечно здорово. Однако кто будет платить этим специалистам? Надо чётко разделять собственное кустарничество (в своё удовольствие) и работу профи которые могут и готовы платить за необходимым специалистам, покупать библиотеки и т. д. Я к примеру никакой не программист, а инженер, пишу в собственное удовольствие для оптимизации работы и для друзей.
Круто вы с Alexshd прямо как с Заказчиком...
> Alexshd
Можете обращатся, с дуговым сегментом на VBA не помогу, а вот как запустить соответствующий ЛИСП и передать данные обратно в VBA могу посодействовать.
Можете обращатся, с дуговым сегментом на VBA не помогу, а вот как запустить соответствующий ЛИСП и передать данные обратно в VBA могу посодействовать.
Спасибо большое. Но на данный момент мне хочется реализовать задачу своими силами на VBA.
Я остановился на математическом способе. Дугу буду вычислять через GetBulge.
-----
Мне очень помогли Ваши советы.
И в свете последних обсуждений "клиент-исполнитель" я не прошу выкладывать горы кода. Мне интересно знать, какими методами я могу решить задачу, какими инструментами VBA позволит мне это сделать.
> Alexshd
... в свете последних обсуждений "клиент-исполнитель"...
Я воспринял ваши посты как участие в этой небольшой игре. Так что спасибо и Вам, что подыграли.
И тему мы, конечно, закрыли, и мои телодвижения выглядят несколько суетливо, но... не надуманная это проблема, вот наткнулся на солидарные настроения:
https://www.caduser.ru/forum/topic15897.html
Посмотрите тут. https://www.caduser.ru/forum/topic22264.html
Это чтобы понять как можно "красиво" и "легко" работать с точкой на полилинии. задача решённая там сложнее вашей. Упростить предлагаю самостоятельно.
Страницы 1
Чтобы отправить ответ, вы должны войти или зарегистрироваться
Форумы CADUser → Программирование → VBA → Как найти угол отрезка полилинии?
Форум работает на PunBB, при поддержке Informer Technologies, Inc