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

ADN Club => AutoCAD .NET API => Тема начата: Дмитрий Загорулькин от 12-12-2018, 14:11:42

Название: Резиновая штриховая линия при перемещении ручки.
Отправлено: Дмитрий Загорулькин от 12-12-2018, 14:11:42
Всем привет!
При перемещении стандартной ручки у объекта (Civil 3D, труба на виде профиля) появляется линия, которая визуализирует смещение курсора относительно исходного положения ручки и соответствующее ему смещение самой ручки. Выглядит это так:
(https://i.postimg.cc/k6fb3Zxk/20181212-Grip-Rubber-Line.png) (https://postimg.cc/k6fb3Zxk)
Я уже себе всю голову сломал пытаясь придумать как мне для моих ручек сделать такую же линию.
Может быть, у вас есть какие-нибудь идеи на этот счёт?
Что я уже попробовал:
- в методе GripData.ViewportDraw добавлял отрисовку линий по данным из вектора перемещения ручки с помощью ViewportDraw.Geometry.DeviceContextPolyline. Получается рисовать сплошной линией. Но у неё задать даже толщину не получается с помощью ViewportDraw.SubEntityTraits.LineWeight, не говоря уже о том, чтобы рисовать её прерывистой.
- в том же методе попробовал отрисовывать ряд точек с помощью метода ViewportDraw.Geometry.RowOfDots. Мало того, что он работает как-то через раз, так ещё и точки получаются очень тонкими, не такими, как у оригинальной ручки. И на изменение настроек ViewportDraw.SubEntityTraits.LineWeight они тоже не реагируют.
Пока что это выглядит вот так:
(https://i.postimg.cc/BPDyRFzy/20181212-My-Grip-Rubber-Line.png) (https://postimg.cc/BPDyRFzy)
Есть, конечно, мысль, что чтобы получить толстую линию, надо вычислять размер пикселя в единицах чертежа и рисовать несколько линий друг с другом вплотную. А чтобы получить прерывистую - вычислять массив точек с учётом промежутков и строить кучу маленьких штрих-отрезков вместо одной сплошной линии. Но как-то это очень костыльно, на мой взгляд. Может есть идеи получше?

Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: avc от 12-12-2018, 14:15:37
Похоже на самую обычную линию при вводе точек, которая появляется при установке PromptPointOptions.BasePoint на стартовыю точку
Код - C# [Выбрать]
  1. PromptPointOptions ppo = new PromptPointOptions("Стартовая");
  2.             ppo.AllowNone = false;
  3.             PromptPointResult pr = ed.GetPoint(ppo);
  4.             if (pr.Status != PromptStatus.OK) return;
  5.             Point3d arrowP = pr.Value;
  6.             ppo.Message = "Конечная";
  7.             ppo.UseDashedLine = true;
  8.             ppo.UseBasePoint = true;
  9.             ppo.BasePoint = arrowP;
  10.             pr = ed.GetPoint(ppo);
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Пекшев aka Modis от 12-12-2018, 14:19:22
Та, что на скриншоте?
(https://i.postimg.cc/0bGL2fKv/2018-12-12-14-18-13-Autodesk-Auto-CAD-2019.png) (https://postimg.cc/0bGL2fKv)

Дык ее не надо реализовывать - это же сам автокад делает
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Пекшев aka Modis от 12-12-2018, 14:22:02
Наверное я наврал. Чтобы она была скорее всего надо реализовать OsnapOverrule. Типа того
Код - C# [Выбрать]
  1. namespace mpESKD.Functions.mpBreakLine.Overrules
  2. {
  3.     using System;
  4.     using Autodesk.AutoCAD.DatabaseServices;
  5.     using Autodesk.AutoCAD.Geometry;
  6.     using Autodesk.AutoCAD.Runtime;
  7.     using Base.Helpers;
  8.     using ModPlusAPI.Windows;
  9.     using System.Diagnostics;
  10.     using Base;
  11.  
  12.     public class BreakLineOsnapOverrule : OsnapOverrule
  13.     {
  14.         protected static BreakLineOsnapOverrule _breakLineOsnapOverrule;
  15.         public static BreakLineOsnapOverrule Instance()
  16.         {
  17.             if (_breakLineOsnapOverrule != null) return _breakLineOsnapOverrule;
  18.             _breakLineOsnapOverrule = new BreakLineOsnapOverrule();
  19.             // Фильтр "отлова" примитива по расширенным данным. Работает лучше, чем проверка вручную!
  20.             _breakLineOsnapOverrule.SetXDataFilter(BreakLineDescriptor.Instance.Name);
  21.             return _breakLineOsnapOverrule;
  22.         }
  23.  
  24.         public override void GetObjectSnapPoints(Entity entity, ObjectSnapModes snapMode, IntPtr gsSelectionMark, Point3d pickPoint,
  25.             Point3d lastPoint, Matrix3d viewTransform, Point3dCollection snapPoints, IntegerCollection geometryIds)
  26.         {
  27.             Debug.Print("BreakLineOsnapOverrule");
  28.             if (IsApplicable(entity))
  29.             {
  30.                 try
  31.                 {
  32.                     var breakLine = EntityReaderFactory.Instance.GetFromEntity<BreakLine>(entity);
  33.                     if (breakLine != null)
  34.                     {
  35.                         snapPoints.Add(breakLine.InsertionPoint);
  36.                         snapPoints.Add(breakLine.EndPoint);
  37.                     }
  38.                 }
  39.                 catch (Autodesk.AutoCAD.Runtime.Exception exception)
  40.                 {
  41.                     ExceptionBox.Show(exception);
  42.                 }
  43.             }
  44.             else base.GetObjectSnapPoints(entity, snapMode, gsSelectionMark, pickPoint, lastPoint, viewTransform, snapPoints, geometryIds);
  45.         }
  46.  
  47.         public override bool IsApplicable(RXObject overruledSubject)
  48.         {
  49.             return ExtendedDataHelpers.IsApplicable(overruledSubject, BreakLineDescriptor.Instance.Name);
  50.         }
  51.     }
  52. }

Вот тогда и привязки будут ловится и линия эта строиться. Это предположительно, так как не могу проверить без OsnapOverrule
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Дмитрий Загорулькин от 12-12-2018, 14:36:26
Похоже на самую обычную линию при вводе точек, которая появляется при установке PromptPointOptions.BasePoint на стартовыю точку
Дык ее не надо реализовывать - это же сам автокад делает
Это не та линия. Стандартная линия рисуется из базовой точки к курсору. А мне нужна такая, чтобы рисовалась "углом" - по вертикали до уровня курсора и потом по горизонтали к нему.
Вот тогда и привязки будут ловится и линия эта строиться. Это предположительно, так как не могу проверить без OsnapOverrule
Это линии трассировки - они строятся нормально, с привязками нет проблем. А та линия, про которую я говорю - это именно вспомогательная резиновая линия, с привязками никак не связанная.
Сделал общую картинку для наглядности:
(https://i.postimg.cc/YGZnMxLR/20181212-Grip-All-Rubber-Lines.png) (https://postimg.cc/YGZnMxLR)
Анимашка:
(https://i.postimg.cc/BPqnM2MS/grips.gif) (https://postimg.cc/BPqnM2MS)
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Пекшев aka Modis от 12-12-2018, 15:10:30
Мне кажется, что смотреть нужно в сторону Transient (https://www.keanw.com/2011/03/using-transient-graphics-to-simulate-autocads-move-command-using-net.html). Там вон вижу перечислитель TransientDrawingMode (http://help.autodesk.com/view/OARX/2018/ENU/?guid=OREFNET-Autodesk_AutoCAD_GraphicsInterface_TransientDrawingMode) у которого есть интересное значение Highlight
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Ривилис от 12-12-2018, 15:41:47
А чтобы получить прерывистую - вычислять массив точек с учётом промежутков и строить кучу маленьких штрих-отрезков вместо одной сплошной линии.
Похоже так и придётся. Точнее кучу кружков при помощи Geometry.Circle с небольшим радиусом, зависящим от высоты видового экрана. Во всяком случае я пока не вижу других альтернатив.
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Пекшев aka Modis от 12-12-2018, 15:54:45
А чтобы получить прерывистую - вычислять массив точек с учётом промежутков и строить кучу маленьких штрих-отрезков вместо одной сплошной линии.
Похоже так и придётся. Точнее кучу кружков при помощи Geometry.Circle с небольшим радиусом, зависящим от высоты видового экрана. Во всяком случае я пока не вижу других альтернатив.
Лучше уж тогда просто цветные вспомогательные линии - и понятней и проще. ИМХО

(https://i.postimg.cc/JGK6Y364/2018-12-12-15-52-12-Autodesk-Auto-CAD-2019.png) (https://postimg.cc/JGK6Y364)

Кстати, если во время перемещения ручки выполнить зуммирование колесиком мышки, то столкнетесь с кучей проблем )
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Ривилис от 12-12-2018, 15:58:31
Лучше уж тогда просто цветные вспомогательные линии - и понятней и проще. ИМХО
Дмитрий Загорулькин, как я понимаю, хочет сделать в точности так, как это сделано в Civil 3D. В противном случае какой смысл заморачиваться?
Кстати, если во время перемещения ручки выполнить зуммирование колесиком мышки, то столкнетесь с кучей проблем )
Да. Теоретически понадобится обрабатывать это событие и менять масштаб (и соответственно расстояние между кружками и возможно радиус).
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Дмитрий Загорулькин от 12-12-2018, 18:40:34
Получилось!
Правда, пришлось использовать полилинию, т.к. только у неё удалось задать толщину.
Итоговый вспомогательный метод:
Код - C# [Выбрать]
  1. public static void DrawDashedLine
  2.     (ViewportDraw vd,
  3.     Point3d startModelPt,
  4.     Point3d endModelPt)
  5. {
  6.     Point2d glyphSize
  7.         = vd.Viewport.GetNumPixelsInUnitSquare(startModelPt);
  8.  
  9.     Vector3d
  10.         lineDir3d = startModelPt.GetVectorTo(endModelPt);
  11.  
  12.     Vector2d
  13.         lineDir2d = new Vector2d(lineDir3d.X, lineDir3d.Y),
  14.         lineNormDir2d = lineDir2d.GetNormal();
  15.  
  16.     double
  17.         lineLength = lineDir2d.Length,
  18.         screenSizeFactor = (glyphSize.X + glyphSize.Y) / 2.0,
  19.         step = 5.0 / screenSizeFactor,
  20.         size = 1.0 / screenSizeFactor,
  21.         plineWidth = 0.1 / screenSizeFactor;
  22.  
  23.     Point2d startModelPt2d
  24.         = new Point2d(startModelPt.X, startModelPt.Y);
  25.  
  26.     if (lineLength > 0.0
  27.         && step > 0.0
  28.         && size > 0.0)
  29.     {
  30.         double curDist;
  31.         int i = 0;
  32.         Color color = Color.FromRgb(137, 137, 137);
  33.  
  34.         while ((curDist = ++i * step) <= lineLength)
  35.         {
  36.             Point2d
  37.                 curEndPt = startModelPt2d + lineNormDir2d.MultiplyBy(curDist),
  38.                 curStartPt = curEndPt - lineNormDir2d.MultiplyBy(size);
  39.  
  40.             using (AcDb.Polyline line = new AcDb.Polyline(2))
  41.             {
  42.                 line.AddVertexAt(0, curStartPt, 0, plineWidth, plineWidth);
  43.                 line.AddVertexAt(1, curEndPt, 0, plineWidth, plineWidth);
  44.                 line.ConstantWidth = plineWidth;
  45.                 line.Color = color;
  46.                 vd.Geometry.Draw(line);
  47.             }
  48.         }
  49.     }
  50. }
  51.  
Анимашка:
(https://i.postimg.cc/v12hkQsR/grips-result.gif) (https://postimg.cc/v12hkQsR)
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Пекшев aka Modis от 12-12-2018, 18:55:35
А зуммирование в этот момент проверил?
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Ривилис от 12-12-2018, 18:56:27
А зуммирование в этот момент проверил?
А анимашку смотрел? Выглядит очень даже прилично.
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Пекшев aka Modis от 12-12-2018, 18:57:50
А зуммирование в этот момент проверил?
А анимашку смотрел? Выглядит очень даже прилично.
В анимашке нет зуммирования - вот и спросил
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Ривилис от 12-12-2018, 18:58:53
В анимашке нет зуммирования - вот и спросил
Плохо смотрел. Есть там зуммирование.
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Дмитрий Загорулькин от 12-12-2018, 19:01:40
При зуммировании автоматически внутренними механизмами самого AutoCAD-Civil вызывается метод перерисовки ручки ViewportDraw, в котором вызывается метод отрисовки этой линии. В методе есть определение коэффициента, который учитывает размер экрана. Поэтому, при зуммировании никаких проблем не возникает - геометрия всегда отрисовывается корректно.
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Пекшев aka Modis от 12-12-2018, 19:05:30
Да, не досмотрел анимашку))
Проблема с зуммированием вероятно связана с тем, откуда работает метод - в самой overrule или в методах ручки
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Дмитрий Загорулькин от 12-12-2018, 19:07:17
Возможно. Я не помню, правда, чтобы где-то ловил проблему с зуммированием. Но стало любопытно :) Есть пример?
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Александр Пекшев aka Modis от 12-12-2018, 19:09:19
Возможно. Я не помню, правда, чтобы где-то ловил проблему с зуммированием. Но стало любопытно :) Есть пример?
Да вот в том-то и дело, что нет) Пробовал что-то - не получилось - пошёл другим путём) Может в следующий раз опять наткнусь
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: avc от 12-12-2018, 23:03:45
Мне кажется, что смотреть нужно в сторону Transient.
Неее, туда лучше не cмотреть. Багосборник-фаталогенератор :(
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: Дмитрий Загорулькин от 14-12-2018, 12:21:34
Мне кажется, что смотреть нужно в сторону Transient.
Неее, туда лучше не cмотреть. Багосборник-фаталогенератор :(
Не скажу, что в полный рост и везде использую, но есть у меня один инструмент, в котором для временной отрисовки применена транзиентная графика. Работает стабильно и безглючно. Есть какие-то проблемы с ней? Очень интересно! Мало ли - вдруг проблема есть, а пользователи молчат...
Название: Re: Резиновая штриховая линия при перемещении ручки.
Отправлено: avc от 14-12-2018, 12:29:07
Есть какие-то проблемы с ней?
Да, глюки и фаталы. Вывести блок вообще не могу - фатал стабильно и сразу, даже если сначала сделать Explode. Но даже избегая блоков Автокад вышибает регулярно. Очень может быть, что я просто не знаю как этих кошек готовить... Просто вывести клон Entity мало - он сразу исчезнет при сборке мусора. Приходится хранить ссылку на него в специальном статическом списке до тех пор пока надо будет стереть. Возможно это и приводит к сбоям, черт его знает... Но это все уже не по теме...