GripOverrule в C3D

Автор Тема: GripOverrule в C3D  (Прочитано 21589 раз)

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

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: GripOverrule в C3D
« Ответ #60 : 26-12-2017, 18:37:11 »
Я еще раз пересмотрел код этого метода и понял, что был неправ и сделал поспешный вывод. Такая таблица вида [указатель на примитив, коллекция  grips] создаётся для каждого GripOverrule. Так что исключение может возникнуть только при повторном вызове AcMgGripOverrule.getGripPoints для того же самого GripOverrule и Entity.
Я так понимаю, потому что в этой строке
Код - C# [Выбрать]
  1. <Module>.gcroot<Autodesk::AutoCAD::DatabaseServices::GripOverrule ^>..PE$AAVGripOverrule@DatabaseServices@AutoCAD@Autodesk@@(ptr2).EntityMap.Add(key, gripDataCollection.GetNewItems());
есть (ptr2)? :)
В этой абракадабре очень легко что-то не заметить...
Но возможностей у второй пары значительно меньше.
Я посмотрел документацию, если ей верить, то обе IntegterCollection в параметрах метода GetGripPoints не используются (not currently in use). Получается, для задания ручек остаётся только Point3dCollection gripPoints. То есть, можно только указать, где будет новая ручка? И потом по её расположению в этой коллекции, в методе MoveGripPointsAt задавать действие? В принципе, если не нужно собственное отображение ручки, тогда это можно использовать. Если, конечно, я правильно понял принцип использования.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: GripOverrule в C3D
« Ответ #61 : 26-12-2017, 19:00:48 »
А вот этот второй метод исключений не вызывает! Но! Он довольно криво работает. Как это проявляется: при первом перемещении ручки - всё ок. Но если не снимая выделения с объекта снова переместить ручку, то перемещение удваивается. Вот именно так ведут себя ручки меток трубопроводной сети в Civil 3D 2018 и я уже не первый месяц жду, когда же они это исправят. Теперь понятно, откуда ноги растут у такого поведения.
Вот код:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.Geometry;
  3. using Autodesk.AutoCAD.Runtime;
  4. using System.Collections.Generic;
  5.  
  6. namespace AcadTest
  7. {
  8.     public class ImplementClass1
  9.     {
  10.         [CommandMethod("TestGripOverrule1")]
  11.         public void AddOverrule()
  12.         {
  13.             ObjectOverrule.AddOverrule(RXClass.GetClass(typeof(Line)), LineGripOverruleClass1.Instance, true);
  14.         }
  15.     }
  16.  
  17.     public class LineGripOverruleClass1 : GripOverrule
  18.     {
  19.         static LineGripOverruleClass1 _instance = new LineGripOverruleClass1();
  20.  
  21.         public static LineGripOverruleClass1 Instance => _instance;
  22.  
  23.         LineGripOverruleClass1() { }
  24.  
  25.         public override void GetGripPoints(Entity entity, Point3dCollection gripPoints, IntegerCollection snapModes, IntegerCollection geometryIds)
  26.         {
  27.             if (entity is Line line)
  28.             {
  29.                 gripPoints.Add(line.StartPoint);
  30.                 gripPoints.Add(line.EndPoint);
  31.             }
  32.         }
  33.  
  34.         public override void MoveGripPointsAt(Entity entity, IntegerCollection indices, Vector3d offset)
  35.         {
  36.             if (entity is Line line)
  37.             {
  38.                 foreach (int ind in indices)
  39.                 {
  40.                     if (ind == 0)
  41.                     {
  42.                         line.StartPoint += offset;
  43.                     }
  44.                     else if (ind == 1)
  45.                     {
  46.                         line.EndPoint += offset;
  47.                     }
  48.                 }
  49.             }
  50.             else
  51.             {
  52.                 base.MoveGripPointsAt(entity, indices, offset);
  53.             }
  54.         }      
  55.     }    
  56. }
Видео этого безобразия:
« Последнее редактирование: 26-12-2017, 19:48:07 от Дмитрий Загорулькин »

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: GripOverrule в C3D
« Ответ #62 : 26-12-2017, 21:06:41 »
Довольно интересно работает этот метод:
Код - C# [Выбрать]
  1.         public override void GetGripPoints(Entity entity, Point3dCollection gripPoints, IntegerCollection snapModes, IntegerCollection geometryIds)
  2.         {
  3.             Polyline pline = (Polyline)entity;
  4.  
  5.             Point3d p1 = new Point3d(pline.StartPoint.X + 2, pline.StartPoint.Y, 0);
  6.             Point3d p2 = new Point3d(pline.StartPoint.X - 2, pline.StartPoint.Y, 0);
  7.  
  8.             gripPoints.Add(p1);
  9.             gripPoints.Add(p2);
  10.  
  11.             geometryIds.Add(0);
  12.             geometryIds.Add(1);
  13.  
  14.             //base.GetGripPoints(entity, gripPoints, snapModes, geometryIds);
  15.         }

Метод MoveGripPointsAt я не переопределял.


Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: GripOverrule в C3D
« Ответ #63 : 26-12-2017, 21:10:45 »
Хех, на одну ручку повесил растяжение, а на другую перемещение. Интересно, а если верхнюю точку перекинуть зеркально на другую сторону по вертикали/горизонтали, поведение ручек поменяется?

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: GripOverrule в C3D
« Ответ #64 : 26-12-2017, 21:21:16 »
а если верхнюю точку перекинуть зеркально на другую сторону по вертикали/горизонтали, поведение ручек поменяется?
Не понял...

Эти ручки привязываются конкретно к начальной вершине, как бы ты не менял саму полилинию.

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: GripOverrule в C3D
« Ответ #65 : 26-12-2017, 21:29:52 »
Если по красной или по жёлтой стрелочке сместить конец полилинии а потом включить переопределение ручек, поменяются ли у ручек действия местами?

Просто как идея, может быть там что-то типа алгоритма: если перпендикуляр можно опустить на полилинию - растяжение, если нельзя - перемещение.

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: GripOverrule в C3D
« Ответ #66 : 26-12-2017, 21:42:44 »
Если по красной или по жёлтой стрелочке сместить конец полилинии а потом включить переопределение ручек, поменяются ли у ручек действия местами?
Нет - точка растяжения всегда остается справа, как ни крути - pline.StartPoint.X + 2

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: GripOverrule в C3D
« Ответ #67 : 26-12-2017, 21:46:47 »
Тогда другая гипотеза: по умолчанию первой точке назначается растяжение, второй - перемещение, третьей - поворот, четвёртой - масштабирование ... и т.д.

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: GripOverrule в C3D
« Ответ #68 : 26-12-2017, 21:50:31 »
Тогда другая гипотеза: по умолчанию первой точке назначается растяжение, второй - перемещение, третьей - поворот, четвёртой - масштабирование ... и т.д.
Я думаю, что все гораздо проще:
Код - C# [Выбрать]
  1. gripPoints.Add(p1);
  2. gripPoints.Add(p2);
  3.  
  4. geometryIds.Add(0);
  5. geometryIds.Add(1);

Первой ручке присваивается geometryId=0, что означает, что это точка растяжения.

Я был неправ - эти индексы не влияют на ручки. Скорее всего дело в последовательности добавления, но тогда возникает еще больше вопросов...

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: GripOverrule в C3D
« Ответ #69 : 27-12-2017, 13:21:18 »
Всё гораздо проще. Действия назначаются в базовом методе полилинии MoveGripPointsAt(Entity, IntegerCollection, Vector3d). В нём прописано, что первая ручка - растяжение начальной точки, вторая ручка - перемещение средней точки первого сегмента полилинии, третья точка - растяжение следующей вершины ну и так для всех сегментов полилинии... В конце - ручка с индексом = кол-во вершин*2 - растяжение конечной точки. Все последующие ручки игнорируются.

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: GripOverrule в C3D
« Ответ #70 : 27-12-2017, 13:46:45 »
Все последующие ручки игнорируются.
Если не переопределять метод MoveGripPointsAt.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Отмечено как Решение Александр Ривилис 24-01-2018, 16:16:16

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: GripOverrule в C3D
« Ответ #71 : 27-12-2017, 16:34:28 »
Такая таблица вида [указатель на примитив, коллекция  grips] создаётся для каждого GripOverrule. Так что исключение может возникнуть только при повторном вызове AcMgGripOverrule.getGripPoints для того же самого GripOverrule и Entity.
Александр Наумович, Вы натолкнули меня на одну шикарную идею, которую удалось реализовать! В таком виде код не привязывается ни к версии, ни к Civil (смотрите строки 37-51):
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.DatabaseServices;
  2. using Autodesk.AutoCAD.Geometry;
  3. using Autodesk.AutoCAD.GraphicsInterface;
  4. using Autodesk.AutoCAD.Runtime;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Reflection;
  8.  
  9. namespace AcadTest
  10. {
  11.     public class ImplementClass
  12.     {
  13.         [CommandMethod("TestAddGripOverrule")]
  14.         public void AddOverrule()
  15.         {
  16.             Overrule.AddOverrule
  17.                 (RXClass.GetClass(typeof(Line)),
  18.                 LineGripOverrule.Instance, true);
  19.         }        
  20.     }
  21.  
  22.     public class LineGripOverrule: GripOverrule
  23.     {
  24.         static LineGripOverrule m_instance = new LineGripOverrule();
  25.        
  26.         public static LineGripOverrule Instance => m_instance;
  27.  
  28.         LineGripOverrule() { }
  29.  
  30.         public override void GetGripPoints
  31.             (Entity entity, GripDataCollection grips,
  32.             double curViewUnitSize, int gripSize,
  33.             Vector3d curViewDir, GetGripPointsFlags bitFlags)
  34.         {
  35.             if (entity is Line line)
  36.             {
  37.                 PropertyInfo entMapPropInfo =
  38.                     GetType().GetProperty
  39.                     ("EntityMap",
  40.                     BindingFlags.Instance
  41.                     | BindingFlags.NonPublic);
  42.  
  43.                 if (entMapPropInfo != null)
  44.                 {
  45.                     var entityMap = entMapPropInfo.GetValue(this)
  46.                         as Dictionary<IntPtr, List<GripData>>;                    
  47.                     if (entityMap.ContainsKey(line.UnmanagedObject))
  48.                     {
  49.                         entityMap.Remove(line.UnmanagedObject);
  50.                     }
  51.                 }
  52.  
  53.                 Point3d pnt1 = line.StartPoint;
  54.                 MoveGripData grip1 = new MoveGripData(pnt1, PointType.Start);
  55.                 grips.Add(grip1);
  56.  
  57.                 Point3d pnt2 = line.EndPoint;
  58.                 MoveGripData grip2 = new MoveGripData(pnt2, PointType.End);
  59.                 grips.Add(grip2);
  60.             }
  61.         }
  62.  
  63.         public override void MoveGripPointsAt
  64.             (Entity entity, GripDataCollection grips,
  65.             Vector3d offset, MoveGripPointsFlags bitFlags)
  66.         {
  67.             if (entity is Line line)
  68.             {
  69.                 foreach (GripData grip in grips)
  70.                 {
  71.                     if (grip is MoveGripData myGrip)
  72.                     {
  73.                         Point3d newPos3d = myGrip.GripPoint + offset;
  74.                         switch (myGrip.Type)
  75.                         {
  76.                             case PointType.Start:
  77.                                 line.StartPoint = newPos3d;
  78.                                 break;
  79.                             case PointType.End:
  80.                                 line.EndPoint = newPos3d;
  81.                                 break;
  82.                         }
  83.                     }
  84.                 }
  85.             }
  86.         }
  87.     }
  88.  
  89.     public class MoveGripData: GripData
  90.     {
  91.         public PointType Type;
  92.  
  93.         public MoveGripData(Point3d _point, PointType ptType) : base()
  94.         {
  95.             GripPoint = _point;
  96.             Type = ptType;
  97.         }
  98.  
  99.         public override bool ViewportDraw
  100.             (ViewportDraw worldDraw, ObjectId entityId,
  101.             GripData.DrawType type, Point3d? imageGripPoint,
  102.             int gripSizeInPixels)
  103.         {
  104.             // Calculate the size of the glyph in WCS
  105.             Point2d glyphSize = worldDraw.Viewport
  106.                 .GetNumPixelsInUnitSquare(this.GripPoint);
  107.             double glyphHeight = (gripSizeInPixels / glyphSize.Y);
  108.             double glyphWeight = (gripSizeInPixels / glyphSize.X);
  109.  
  110.             Matrix3d mx3d = worldDraw.Viewport.ModelToEyeTransform;
  111.             Point3d pt = this.GripPoint.TransformBy(mx3d);
  112.  
  113.             // Draw a glyph
  114.             Point3dCollection pnts = new Point3dCollection();
  115.  
  116.             // rectangle
  117.             pnts.Add(new Point3d(pt.X - glyphWeight, pt.Y - glyphHeight, pt.Z));
  118.             pnts.Add(new Point3d(pt.X + glyphWeight, pt.Y - glyphHeight, pt.Z));
  119.             pnts.Add(new Point3d(pt.X + glyphWeight, pt.Y + glyphHeight, pt.Z));
  120.             pnts.Add(new Point3d(pt.X - glyphWeight, pt.Y + glyphHeight, pt.Z));
  121.             pnts.Add(new Point3d(pt.X - glyphWeight, pt.Y - glyphHeight, pt.Z));
  122.  
  123.             worldDraw.Geometry.PolygonEye(pnts);
  124.  
  125.             return base.ViewportDraw
  126.                 (worldDraw, entityId, type, imageGripPoint, gripSizeInPixels);
  127.         }
  128.     }
  129.  
  130.     public enum PointType
  131.     {
  132.         Start,
  133.         End,
  134.     }
  135. }

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

  • Administrator
  • *****
  • Сообщений: 13830
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: GripOverrule в C3D
« Ответ #72 : 27-12-2017, 16:40:48 »
Дмитрий Загорулькин
Очень-очень-очень красивый workaround! Люблю я такие вещи!!!
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Re: GripOverrule в C3D
« Ответ #73 : 27-12-2017, 16:49:29 »
Да, не говорите! Мне тоже такое решение гораздо больше нравится, чем предыдущее! И главное - практически на поверхности было после Вашего сообщения о причинах сбоя!
Проверил в Civil 3D 2017: условие в 47 строке всегда возвращает false. Похоже, что эту коллекцию какие-то внутренние методы чистят, но почему-то не делают этого в 2018 версии.

Оффлайн Алексей ТерноАвтор темы

  • ADN Club
  • ****
  • Сообщений: 381
  • Карма: 33
    • C3D Extensions
  • Skype: alexeyterno
Re: GripOverrule в C3D
« Ответ #74 : 27-12-2017, 17:01:23 »
Круто!!!