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

ADN Club => AutoCAD .NET API => Тема начата: simson43 от 15-10-2018, 14:38:47

Название: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 14:38:47
Здравствуйте.
Возможно ли назначить выбор не всего объекта а только сегмента полилинии как это реализовано например в штатной функции "Сопряжение"?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 14:41:19
Ты выбираешь всю полилинию при помощи Editor.GetEntity, а потом по точке указания находишь какой сегмент выбран.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 14:45:47
т е там именно так реализовано?
а подсветить как сегмент этот как делает ctrl + выбор?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 14:49:21
а подсветить как сегмент этот как делает ctrl + выбор?
А подсветить вот так:
http://adn-cis.org/podsvetka-segmenta-polilinii.html
Вместо запроса номера сегмента можно по точке указания самостоятельно определить номер сегмента.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 14:50:24
Понял спасибо! буду пробовать
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 15:43:17
а как получить координату точки выбора? и как каким методом мне соотнести эту точку с сегментом? как достать координаты сегмента?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 15:50:20
а как получить координату точки выбора?
Editor.GetEntity возвращает выбранный примитив и координату точки выбора (в ПСК)
и как каким методом мне соотнести эту точку с сегментом? как достать координаты сегмента?
Посмотреть методы и свойства класса Polyline и найти подходящие.
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 16:22:15
Ближе всего этот код: http://adn-cis.org/forum/index.php?topic=8372.msg31066#msg31066
Но и его нужно "допиливать" для универсальности. Он в частности не учитывает ПСК и направление взгляда.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 16:28:27
только GetEntity возвращает координату?
GetSelection я так понял нет?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 16:29:50
GetSelection я так понял нет?
GetSelection возвращает набор - координаты там нет.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 17:18:05
единственное что нашел подходящее это метод OnSegmentAt(index, pt2d, value)
но не могу понять что значит value
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 19:07:58
но не могу понять что значит value
Для этой цели есть документация - читай её.
P.S.: Я давал ссылку на пример кода, которую ты похоже проигнорировал.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 19:15:16
Я не проигнорировал. Я его не очень понял. У меня получилось с тем методом про который я спросил при value =0.
Я читал везде это называется каким то параметром. Где то написано что то вроде выходной параметр индекса вершины, если дословно. И что же это..
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 19:18:05
Я читал везде это гарантия каким то параметром. Где то написано что то вроде азотной параметр индекса вершины, если дословно. И что же это..
Жуть и полный бред. Это какой из переводчиков так переводит?
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 19:19:36
Яндекс)
прошу прощения.. яндекс + мой т9
на самом деле так: выходной параметр индекса вершины (Output parameter of at vertex index )
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 20:50:04
Жуть и полный бред.
так подскажете что значит этот параметр?
и вот этот метод: GetParameterAtPoint
что за магический параметр он возвращает?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 21:00:42
и вот этот метод: GetParameterAtPoint
что за магический параметр он возвращает?
Если ты не знаком с параметрическими кривыми (вообще, а не только в AutoCAD), то в двух словах я тебе это не объясню - ищи в интернете. В данном случае для полилиний параметр является целым числом в каждой из вершин полилиний. Например, параметр 1.0 - это вторая вершина, а 1.5 это середина третьего сегмента.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 21:03:53
Понял спасибо.
По поводу подсветки: я так понял она подсветится при нажатии лишь. а при наведении? чтоб как при зажатом ctrl можно так?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 21:11:08
По поводу подсветки: я так понял она подсветится при нажатии лишь. а при наведении? чтоб как при зажатом ctrl можно так?
Ну так просто это сделать у тебя не получится. Тебе еще очень долго придётся изучать PointMonitor и Overruling.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 21:21:32
так я ж не против)
хотите сказать пока проще зажать ctrl?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 21:24:15
так я ж не против)
хотите сказать пока проще зажать ctrl?
Ты до сих пор не объяснил что тебе нужно. Как же я могу тебе сказать, что тебе делать? В названии темы стоит - "как выбрать сегмент полилинии". На этот вопрос ответ уже давно дан.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 21:31:00
вот такой скромный код рабочий

Код - C# [Выбрать]
  1.             Document doc = App.DocumentManager.MdiActiveDocument;
  2.             Database db = doc.Database;
  3.             Editor ed = doc.Editor;
  4.  
  5.             PromptEntityOptions peo = new PromptEntityOptions("\nВыберите сегменты полилинии");
  6.             peo.SetRejectMessage("\nДолжна быть выбрана полилиния");
  7.             peo.AddAllowedClass(typeof(Polyline), true);
  8.  
  9.             using (Transaction tr = doc.TransactionManager.StartTransaction())
  10.             {
  11.                 while (true)
  12.                 {
  13.                     PromptEntityResult sel = ed.GetEntity(peo);
  14.                     if (sel.Status == PromptStatus.OK)
  15.                     {
  16.                         if (tr.GetObject(sel.ObjectId, OpenMode.ForWrite) is Polyline pl)
  17.                         {
  18.                             Point3d c = pl.GetClosestPointTo(sel.PickedPoint, false);
  19.                             Point2d p = new Point2d(c[0], c[1]);
  20.                            
  21.                             int n = pl.NumberOfVertices;
  22.                             if (!pl.Closed) n--;
  23.  
  24.                             for (int i = 0; i < n; i++)
  25.                             {
  26.                                 if (pl.OnSegmentAt(i, p, 0))
  27.                                 {
  28.                                     MessageBox.Show((i+1).ToString());
  29.                                 }
  30.                             }
  31.                         }
  32.                     }
  33.                     else break;
  34.                 }
  35.                 tr.Commit();
  36.             }

Так вот вопрос: зачем вот здесь так усложнено получение координаты? или я чего то опять не понимаю?
http://www.acadnetwork.com/index.php?topic=203.0
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 21:35:39
Так вот вопрос: зачем вот здесь так усложнено получение координаты? или я чего то опять не понимаю?
http://www.acadnetwork.com/index.php?topic=203.0
Видимо ты совершенно не понимаешь что такое ПСК (UCS). Кроме того ты видимо ничего не знаешь о внутренней системе координат ОСК (ECS) полилинии, в которой нужно передавать точку в метод OnSegmentAt. Изучай.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 21:39:43
наверное.. но ведь работает..
пошел изучать.
спасибо за наводки
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 21:45:35
наверное.. но ведь работает..
Работает если выполняются два условия:
1. ПСК == МСК
2. Полилиния находится в плоскости X0Y или параллельна ей (т.е. её свойство Normal ==Vector3d.ZAxis)
В любом другом случае работать не будет.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 21:49:10
ну я могу сказать что не припомню случаев когда они у меня не выполняются)
ps: дада я пошел изучать)
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 21:51:11
ну я могу сказать что не припомню случаев когда они у меня не выполняются)
Ты программы пишешь только для себя?
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 21:56:43
стесняюсь сказать что нет)
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 22:06:30
стесняюсь сказать что нет)
А я вот не стесняюсь сказать, что нужно учитывать все возможные варианты. Даже если пишешь для себя, то и в этом случае тебе может достаться чужой чертеж, в котором ПСК != МСК.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 22:22:13
я ж не отказываюсь
ps: дада я пошел изучать)
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 22:55:09
в этом примере кстати в методе OnSegmentAt последний параметр используется 0.
что же он все таки значит?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 23:24:01
в этом примере кстати в методе OnSegmentAt последний параметр используется 0.
что же он все таки значит?
С этим параметром очень интересно. В ObjectARX в методе AcDbPolyline::onSegAt этот параметр передаётся по ссылке:
Код - C++ [Выбрать]
  1. virtual Adesk::Boolean onSegAt(
  2.     unsigned int index,
  3.     const AcGePoint2d& pt2d,
  4.     double& param // передача по ссылке
  5. ) const;
и в случае если переданная точка находится на этом сегменте в этом параметре возвращается параметр точки на полилинии:
Цитировать
If pt2d is on the polyline's segment, then param is set to the location of the point on the segment. param will be in the parametric form of the segment type
В .NET Polyline.OnSegmentAt - это обертка для AcDbPolyline::onSegAt. Но она похоже какая-то неправильная, так как она должна была бы быть такой:
Код - C# [Выбрать]
  1. public virtual bool OnSegmentAt(
  2.     int index,
  3.     Point2d pt2d,
  4.     ref double value // ref - т.е. передача параметра по ссылке, а не по значению
  5. );

Резюме: Я бы не стал пользоваться этим методом вообще, а использовал бы одну из альтернатив.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 15-10-2018, 23:38:22
If pt2d is on the polyline's segment, then param is set to the location of the point on the segment. value will be in the parametric form of the segment type (in other words, linear or arc).
Тут еще в скобочках как это понимать?

А вот эти круговерти с системами координат только для этого метода? Для альтернатив проще?
Попробовал сделать как в примере. Повертел системы координат по всем осям и так и сяк и довертел до того состояния, когда код из примера по ссылке, что я кидал, не работает.
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 15-10-2018, 23:43:52
Тут еще в скобочках как это понимать?
... типа сегмента (другими словами линейного или дугового).
Для альтернатив проще?
Там тоже это следует учитывать.
Попробовал сделать как в примере. Повертел системы координат по всем осям и так и сяк и довертел до того состояния, когда код из примера по ссылке, что я кидал, не работает.
Там тоже не всё чисто в коде. В частности, там вообще не учитывается условие 2.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 08:03:19
Тут еще в скобочках как это понимать?
... типа сегмента (другими словами линейного или дугового).
с переводом я справился. Как параметр связан с типом сегмента?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 09:20:25
Как параметр связан с типом сегмента?
Для дуги и для линейного сегмента параметры считаются по разному. Не вижу смысла углубляться в эту сторону.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 12:11:02
а как узнать OCS полилинии? *убрал чтоб не ругались*
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 12:17:43
а как узнать OCS полилинии?
У Entity (базового класса для Polyline) есть свойство Entity.Ecs - вот им и можно воспользоваться для получения матрицы OCS (или ECS).
мне же к ней нужно точку привести
Тут в каждом слове перл:
1. Точку нельзя провести.
2. К системе координат (матрице) нельзя вообще ничего провести.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 12:20:37
как же просто а я мучаюсь с нормалями всякими
спасибо большое!
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 12:26:30
*убрал чтоб не ругались*
Поздно. Всё уже записано! :-)
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 12:27:56
как же просто а я мучаюсь с нормалями всякими
спасибо большое!
С вероятностью 99% тебе для решения этой задачи не нужна OCS(ECS)
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 12:29:32
я пытаюсь добить метод onsegmentat

Я вот упрощенный метод здесь не очень понимаю. Из текущей в текущую преобразовывают?
http://spiderinnet1.typepad.com/blog/2013/05/autocad-net-transform-picked-point-from-current-ucs-to-wcs.html
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 12:31:03
я пытаюсь добить метод onsegmentat

Я уже высказал своё мнение по этому поводу.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 12:33:47
А какие аналоги? Я что то не приметил подобных методов(
 Да и хотелось все таки разобраться с ocs(ecs) раз уж начал
Я вот упрощенный метод здесь не очень понимаю. Из текущей в текущую преобразовывают?
http://spiderinnet1.typepad.com/blog/2013/05/autocad-net-transform-picked-point-from-current-ucs-to-wcs.html
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 13:17:56
А какие аналоги? Я что то не приметил подобных методов(
Тестируй:
Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.EditorInput;
  7.  
  8. #pragma warning disable 0618
  9.  
  10. [assembly: CommandClass(typeof(Rivilis.SelPolylineSegment))]
  11.  
  12. namespace Rivilis
  13. {
  14.   public class SelPolylineSegment
  15.   {
  16.     [CommandMethod("SelPolySeg")]
  17.     public void SelPolySeg()
  18.     {
  19.       Document doc = Application.DocumentManager.MdiActiveDocument;
  20.       if (doc == null)
  21.         return;
  22.       Editor ed = doc.Editor;
  23.       Database db = doc.Database;
  24.       // Просим пользователя выбрать сегмент полилинии
  25.       PromptEntityOptions prOpt =
  26.         new PromptEntityOptions("\nУкажите сегмент полилинии: ");
  27.       prOpt.SetRejectMessage("Это не полилиния!");
  28.       prOpt.AddAllowedClass(typeof(Polyline), true);
  29.       PromptEntityResult prRes = ed.GetEntity(prOpt);
  30.       if (prRes.Status != PromptStatus.OK)
  31.         return;
  32.       // Получаем точку указания в МСК (WCS)
  33.       Matrix3d ucs2wcs = ed.CurrentUserCoordinateSystem;
  34.       Point3d pWcs = prRes.PickedPoint.TransformBy(ucs2wcs);
  35.       // Получаем вектор взгляда в МСК (WCS)
  36.       Vector3d viewDir =
  37.         ((Point3d)(Application.GetSystemVariable("VIEWDIR")))
  38.         .TransformBy(ucs2wcs).GetAsVector().Negate();
  39.       using (Polyline pline = prRes.ObjectId.Open(OpenMode.ForRead) as Polyline)
  40.       {
  41.         // Находим точку на полилинии ближайшую к указанной
  42.         // с учетом направления взгляда
  43.         Point3d pOnPline = pline.GetClosestPointTo(pWcs, viewDir, false);
  44.         // Получаем параметр полилинии в полученной точке на полилинии
  45.         double param = pline.GetParameterAtPoint(pOnPline);
  46.         // Номер сегмент полилинии определяется её параметром
  47.         int iSeg = (int) param + 1; // Нумеруем сегменты от 1
  48.         // Подсвечиваем сегмент полилинии
  49.         HighlightPolyline(pline, iSeg);
  50.       }
  51.     }
  52.     public void HighlightPolyline(Polyline pline, int segment)
  53.     {
  54.       FullSubentityPath path =
  55.         new FullSubentityPath(
  56.           new ObjectId[] { pline.Id },
  57.           new SubentityId(SubentityType.Edge, new IntPtr(segment))
  58.         );
  59.       // Подсвечиваем сегмент
  60.       pline.Highlight(path, true);
  61.     }
  62.   }
  63. }
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 13:32:04
Вот так вот? Готовый код?(
Вечером уже потестирую
Спасибо
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 13:40:46
Готовый код?(
Ну как минимум будет возможность изучить, разобраться в логике работы, протестировать.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 13:45:08
Да с параметром хорошо получилось.
Моя логика хотя бы была верна в следующем:
Чтоб получить точку в ECS:
Point3d ptEcs = ptWcs.TransformBy(pline.Ecs);
И эту точку уже передавать в метод onsegmentat? Точнее ее х и у
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 13:54:25
Моя логика хотя бы была верна в следующем:
Чтоб получить точку в ECS:
Point3d ptEcs = ptWcs.TransformBy(pline.Ecs);
И эту точку уже передавать в метод onsegmentat? Точнее ее х и у
Всё в точности до наоборот. Читаем документацию. pline.Ecs вернёт матрицу преобразования из ECS в WCS. Т.е. тебе нужна обратная матрица: pline.Ecs.Invert(). Ну и кроме того тебе понадобится еще одно преобразование - UCS в WCS, так как точку ты получаешь от пользователя в UCS. И еще передаваемая точка в метод onsegmentat должна быть в точности на полилинии, а Editor.GetEntity возвращает точку не на полилинии, а рядом в пределах размера pickbox. Поэтому в моём коде и используется нахождение точки на полилинии, ближайшей к указанной (метод GetClosestPointTo).
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 14:26:51
Да я так и сделал. Упустил лишь момент получения обратной матрицы
Спасибо
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 18:37:45
все таки не всегда корректно работает
покрутил начало координат порисовал в разных плоскостях эти полилинии. и в какой то момент он не понимает что где
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 19:29:06
все таки не всегда корректно работает
покрутил начало координат порисовал в разных плоскостях эти полилинии. и в какой то момент он не понимает что где
Чей вариант? Если мой - выкладывай чертеж в котором появляется ошибка. А еще лучше еще и добавь видео (как это делать - у меня в подписи).
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 19:47:45

кажется получилось
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 19:49:14
вот код
Код - C# [Выбрать]
  1. public void Width()
  2.         {
  3.             Document doc = App.DocumentManager.MdiActiveDocument;
  4.             Database db = doc.Database;
  5.             Editor ed = doc.Editor;
  6.            
  7.             PromptEntityOptions peo = new PromptEntityOptions("\nВыберите сегменты полилинии");
  8.             peo.SetRejectMessage("\nЭто не полилиния!");
  9.             peo.AddAllowedClass(typeof(Polyline), true);
  10.  
  11.             PromptDoubleOptions pdo = new PromptDoubleOptions("\nШирина сегмнта полилинии");
  12.             pdo.DefaultValue = def;
  13.             PromptDoubleResult res = ed.GetDouble(pdo);
  14.  
  15.             double width = res.Value;
  16.             def = res.Value;
  17.            
  18.             while (true)
  19.             {
  20.                 PromptEntityResult sel = ed.GetEntity(peo);
  21.                 if (sel.Status == PromptStatus.OK)
  22.                 {
  23.                     using (Transaction tr = doc.TransactionManager.StartTransaction())
  24.                     {
  25.                         if (tr.GetObject(sel.ObjectId, OpenMode.ForWrite) is Polyline pl)
  26.                         {
  27.                             Matrix3d u2w = ed.CurrentUserCoordinateSystem;
  28.                             Vector3d viewDir = ((Point3d)(App.GetSystemVariable("VIEWDIR"))).TransformBy(u2w).GetAsVector().Negate();
  29.                             Point3d pW = pl.GetClosestPointTo(sel.PickedPoint.TransformBy(u2w), viewDir, false);
  30.  
  31.                             int n = (int)pl.GetParameterAtPoint(pW);
  32.  
  33.                             if (pl.GetStartWidthAt(n) != width)
  34.                             {
  35.                                 pl.SetStartWidthAt(n, width);
  36.                                 pl.SetEndWidthAt(n, width);
  37.                             }
  38.                             else
  39.                             {
  40.                                 pl.SetStartWidthAt(n, 0);
  41.                                 pl.SetEndWidthAt(n, 0);
  42.                             }
  43.                         }
  44.                         tr.Commit();
  45.                     }
  46.                 }
  47.                 else break;
  48.             }
  49.         }
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 19:50:45
simson43,
Где чертеж?
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 19:52:25
еще заодно спрошу.
я сначала транзакцию сделал за циклом. показалось так разумнее. но тогда при выборе сегмента он не сразу меняет ширину а по завершению метода что логично.
добавил в конце цикла regen. меняться конечно ширина стала но на больших чертежах это долго.
убрал реген засунул транзакцию в тело цикла. т е она создается каждую итерацию теперь. зато ширина в реальном времени меняется. и на больших чертежах не отнимает много времени.
это рационально?
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 19:53:16
так вот он
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 20:55:11
это рационально?
Это нормально для данного случая.
все таки не всегда корректно работает
Ну вот ты и нарвался на баг в AutoCAD .NET API, с чем тебя и поздравляю. Нужно будет отправить в ADN DevHelp.
В случае если сегмент полилинии имеет ширину отличную от нуля метод public virtual Point3d GetClosestPointTo( Point3d givenPoint,  Vector3d direction, bool extend) работает неправильно, т.е. далеко не всегда правильно находит ближайшую точку. Вместо этого метода применим public virtual Point3d GetClosestPointTo( Point3d givenPoint,  bool extend);
У меня в твоём случае всё нормально работает. Вот код для проверки:
Код - C# [Выбрать]
  1. // (C) Copyright 2018 by  
  2. //
  3. using System;
  4. using Autodesk.AutoCAD.Runtime;
  5. using Autodesk.AutoCAD.ApplicationServices;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7. using Autodesk.AutoCAD.Geometry;
  8. using Autodesk.AutoCAD.EditorInput;
  9. using App = Autodesk.AutoCAD.ApplicationServices.Application;
  10.  
  11. #pragma warning disable 0618
  12.  
  13. // This line is not mandatory, but improves loading performances
  14. [assembly: CommandClass(typeof(ChangeSegmentWidth.MyCommands))]
  15.  
  16. namespace ChangeSegmentWidth
  17. {
  18.  
  19.   public class MyCommands
  20.   {
  21.     static double def = 0.0;
  22.     [CommandMethod("ChgWidth")]
  23.     public void Width()
  24.     {
  25.       Document doc = App.DocumentManager.MdiActiveDocument;
  26.       Database db = doc.Database;
  27.       Editor ed = doc.Editor;
  28.  
  29.       PromptEntityOptions peo = new PromptEntityOptions("\nВыберите сегменты полилинии");
  30.       peo.SetRejectMessage("\nЭто не полилиния!");
  31.       peo.AddAllowedClass(typeof(Polyline), true);
  32.  
  33.       PromptDoubleOptions pdo = new PromptDoubleOptions("\nШирина сегмента полилинии");
  34.       pdo.DefaultValue = def;
  35.       PromptDoubleResult res = ed.GetDouble(pdo);
  36.  
  37.       double width = res.Value;
  38.       def = res.Value;
  39.  
  40.       while (true)
  41.       {
  42.         PromptEntityResult sel = ed.GetEntity(peo);
  43.         if (sel.Status == PromptStatus.OK)
  44.         {
  45.           using (Polyline pl = sel.ObjectId.Open(OpenMode.ForRead) as Polyline)
  46.           {
  47.             Matrix3d u2w = ed.CurrentUserCoordinateSystem;
  48.             Vector3d viewDir = ((Point3d)(App.GetSystemVariable("VIEWDIR")))
  49.               .TransformBy(u2w).GetAsVector().Negate().GetNormal();
  50.             // Какой-то баг у следующего метода
  51.             // Point3d pW = pl.GetClosestPointTo(sel.PickedPoint.TransformBy(u2w), viewDir, false);
  52.             Point3d pW = pl.GetClosestPointTo(sel.PickedPoint.TransformBy(u2w), false);
  53.             int n = (int)(pl.GetParameterAtPoint(pW) + 1e-10);
  54.  
  55.             try
  56.             {
  57.               pl.UpgradeOpen();
  58.               if (pl.GetStartWidthAt(n) > 1e-10)
  59.               {
  60.                 pl.SetStartWidthAt(n, 0.0);
  61.                 pl.SetEndWidthAt(n, 0.0);
  62.               }
  63.               else
  64.               {
  65.                 pl.SetStartWidthAt(n, width);
  66.                 pl.SetEndWidthAt(n, width);
  67.               }
  68.             }
  69.             catch { }
  70.           }
  71.         }
  72.         else break;
  73.       }
  74.     }
  75.   }
  76. }

Кстати, проверять на равенство плавающие числа (double) не следует. Обрати внимание на то, как я сделал.
Проверь как у тебя работает этот код.
 
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 21:03:22
баг это же хорошо. теперь о нем узнают)
Кстати, проверять на равенство плавающие числа (double) не следует.
это вы к тому что машинный ноль не всегда 0?

а про viewDir: я думал вы использовали именно этот метод чтоб он корректно работал при различно повернутых UCS? или как?

pl.SetStartWidthAt(n, 0.0);
это принципиально или просто для наглядности?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 21:06:59
это вы к тому что машинный ноль не всегда 0?
Ты сравниваешь на равенство ширину сегмента полилинии и width на равенство. Так делать не следует.
а про viewDir: я думал вы использовали именно этот метод чтоб он корректно работал при различно повернутых UCS? или как?
Нет. Не путай ПСК и направление взгляда - это разные вещи.
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 21:07:16
это принципиально или просто для наглядности?
Для наглядности.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 21:12:57
Тогда какую роль играет это направление? Какая разница между этими методами
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 21:16:02
И по поводу upgradeopen. Зачем он тут вообще если в любом случае нужно будет взять на запись?
И вечное противостояние open и транзакции..
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 21:18:40
И по поводу upgradeipen. Зачем он тут вообще если в любом случае нужно будет взять на запись?
В данном случае это неважно. Но я в большинстве случаев предпочитаю открывать на запись на минимально короткое время.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 21:20:50
Понял.
Спсибо большое.
Вы снова спасли ситуацию)
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 21:21:04
Тогда какую роль играет это направление? Какая разница между этими методами
Пришлось использовать метод, который не учитывает направление. Но боюсь, что возможны варианты, когда это не будет работать, т.е. будет выбираться не тот сегмент полилинии, т.к. в качестве ближайшей точки будет выбрана не та, которая нам нужна.
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 21:46:23
Ну вот ты и нарвался на баг в AutoCAD .NET API, с чем тебя и поздравляю. Нужно будет отправить в ADN DevHelp.
Похоже в этот раз я не прав и это не баг. Баг в другом - в вычислении направления взгляда.
Протестируй этот код:
Код - C# [Выбрать]
  1. using System;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.ApplicationServices;
  4. using Autodesk.AutoCAD.DatabaseServices;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.EditorInput;
  7. using App = Autodesk.AutoCAD.ApplicationServices.Application;
  8.  
  9. #pragma warning disable 0618
  10.  
  11. // This line is not mandatory, but improves loading performances
  12. [assembly: CommandClass(typeof(ChangeSegmentWidth.MyCommands))]
  13.  
  14. namespace ChangeSegmentWidth
  15. {
  16.  
  17.   public class MyCommands
  18.   {
  19.     static double def = 0.0;
  20.     [CommandMethod("ChgWidth")]
  21.     public void Width()
  22.     {
  23.       Document doc = App.DocumentManager.MdiActiveDocument;
  24.       Database db = doc.Database;
  25.       Editor ed = doc.Editor;
  26.  
  27.       PromptEntityOptions peo = new PromptEntityOptions("\nВыберите сегменты полилинии");
  28.       peo.SetRejectMessage("\nЭто не полилиния!");
  29.       peo.AddAllowedClass(typeof(Polyline), true);
  30.  
  31.       PromptDoubleOptions pdo = new PromptDoubleOptions("\nШирина сегмента полилинии");
  32.       pdo.DefaultValue = def;
  33.       PromptDoubleResult res = ed.GetDouble(pdo);
  34.  
  35.       double width = res.Value;
  36.       def = res.Value;
  37.  
  38.       while (true)
  39.       {
  40.         PromptEntityResult sel = ed.GetEntity(peo);
  41.         if (sel.Status == PromptStatus.OK)
  42.         {
  43.           using (Polyline pl = sel.ObjectId.Open(OpenMode.ForWrite) as Polyline)
  44.           {
  45.             Matrix3d u2w = ed.CurrentUserCoordinateSystem;
  46.             Vector3d viewDir = ed.GetCurrentView().ViewDirection;
  47.             Point3d pW = pl.GetClosestPointTo(sel.PickedPoint.TransformBy(u2w), viewDir, false);
  48.  
  49.             int n = (int)(pl.GetParameterAtPoint(pW) + 1e-10);
  50.  
  51.             if (pl.GetStartWidthAt(n) > 1e-10)
  52.             {
  53.               pl.SetStartWidthAt(n, 0.0); pl.SetEndWidthAt(n, 0.0);
  54.             }
  55.             else
  56.             {
  57.               pl.SetStartWidthAt(n, width); pl.SetEndWidthAt(n, width);
  58.             }
  59.           }
  60.         }
  61.         else break;
  62.       }
  63.     }
  64.   }
  65. }
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 22:01:19
О ДА! этот вариант отрабатывает во всех вариантах
вот эта строчка не очень понятна. вы не доверяете точности метода?
int n = (int)(pl.GetParameterAtPoint(pW) + 1e-10);

и эту строчку
if (pl.GetStartWidthAt(n) > 1e-10)
написал вот так
Код - C# [Выбрать]
  1. if (Math.Abs(pl.GetStartWidthAt(n) - width) > 1e-5)
так если ширина уже какая то установлена то он ее не обнуляет а меняет на актуальную.

еще раз спасибо!
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 22:05:35
НЕАКТУАЛЕН! ПРОТЕСТИРУЮ ИСПРАВЛЮ
Ну да если в других плоскостях то тоже неправильно работает.
а предыдущий вроде бы лучше в пространстве работал. но зато в более простых плоских чертежах со смещенным началом координат шалит.
т.к. у меня обычно плоские и простые так что оставлю последний вариант.
Ничего не понял. Ты про какой вариант пишешь?
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 22:11:24
да я написал это сообщение а потом увидел ваш обновленный код и быстренько добавил примечание что комментарий неактуален. теперь изменил.
это сообщение можно удалить)
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 22:16:14
вот эта строчка не очень понятна. вы не доверяете точности метода?
Цитата: Александр Ривилис от 16-10-2018, 21:46:23

    int n = (int)(pl.GetParameterAtPoint(pW) + 1e-10);

При преобразовании плавающего к целому отбрасываются дробная часть. Поэтому (int)0.99999999999 будет равно 0, а не 1

написал вот так
Код - C# [Выбрать]

    if (Math.Abs(pl.GetStartWidthAt(n) - width) > 1e-5)

так если ширина уже какая то установлена то он ее не обнуляет а меняет на актуальную.
Согласен.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 22:21:02
При преобразовании плавающего к целому отбрасываются дробная часть. Поэтому (int)0.99999999999 будет равно 0, а не 1
это я знаю
но может мы на конец желаемого сегмента нажали.. и получилось 0.9999999999 а программа выберет следующий.. неприятно
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 22:23:51
При преобразовании плавающего к целому отбрасываются дробная часть. Поэтому (int)0.99999999999 будет равно 0, а не 1
это я знаю
но может мы на конец желаемого сегмента нажали.. и получилось 0.9999999999 а программа выберет следующий.. неприятно
1. С такой точностью ты не выберешь конец сегмента.
2. Даже если выберешь конечную точку, то тут спорный вопрос - какой сегмент нужно в этом случае выбирать.
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 22:25:57
ну а как может получиться 0,99999999 при нажатии на начало второго сегмента тогда?
скорее будет 1,000000001?
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 22:28:32
ну а как может получиться 0,99999999 при нажатии на начало второго сегмента тогда?
скорее будет 1,000000001?
Да. А к чему этот вопрос? Это утверждение противоречит чему-то, что я писал?
Название: Re: выбор сегмента полилиниии
Отправлено: simson43 от 16-10-2018, 22:30:11
я к тому что это прибавление 1е-10 , по моему, не играет роли
Название: Re: выбор сегмента полилиниии
Отправлено: Александр Ривилис от 16-10-2018, 23:24:43
я к тому что это прибавление 1е-10 , по моему, не играет роли
Не нравится - не прибавляй.