Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?

Автор Тема: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?  (Прочитано 9628 раз)

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

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Начало этой темы тут: https://adn-cis.org/forum/index.php?topic=9653.0
Так как проблема уже выходит за рамки AutoCAD API, то разумнее продолжить тут.
В процессе поиска причин вылетов и исключений выяснилось, что проблема возникает при расчленении меток, которые содержат блоки. Написал такую тестовую команду:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using Autodesk.Civil.DatabaseServices;
  6. using Autodesk.Civil.DatabaseServices.Styles;
  7. using System;
  8. using System.Collections.Generic;
  9. using AcEntity = Autodesk.AutoCAD.DatabaseServices.Entity;
  10.  
  11. namespace C3dTest
  12. {
  13.     public class ExplodeLabelTest
  14.     {
  15.         [CommandMethod("ExplodeLabelWithBlockTest")]
  16.         public void Run()
  17.         {
  18.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  19.             Editor ed = adoc.Editor;
  20.             Database db = adoc.Database;
  21.  
  22.             PromptEntityOptions entityOptions
  23.                 = new PromptEntityOptions("\nSelect a label with a block component: ");
  24.  
  25.             entityOptions.SetRejectMessage("\nIt's not a label!");
  26.  
  27.             entityOptions.AddAllowedClass(typeof(FeatureLabel), false);
  28.            
  29.             ObjectId selObjId = default;
  30.  
  31.             while (!selObjId.IsValid)
  32.             {
  33.                 PromptEntityResult result = ed.GetEntity(entityOptions);
  34.  
  35.                 if (result.Status != PromptStatus.OK) break;                
  36.  
  37. #pragma warning disable CS0618 // Type or member is obsolete
  38.                 using (FeatureLabel label = result.ObjectId.Open(OpenMode.ForRead) as FeatureLabel)
  39.                 using (LabelStyle style = label.StyleId.Open(OpenMode.ForRead) as LabelStyle)
  40. #pragma warning restore CS0618 // Type or member is obsolete
  41.                 {
  42.                     ObjectIdCollection blkCompCol
  43.                         = style.GetComponents(LabelStyleComponentType.Block);
  44.                     if (blkCompCol.Count > 0)
  45.                     {
  46.                         selObjId = result.ObjectId;
  47.                     }
  48.                     else
  49.                     {
  50.                         ed.WriteMessage("\nThe label does not have a block component!");
  51.                     }
  52.                 }                
  53.             }
  54.  
  55.             if (!selObjId.IsValid) return;
  56.  
  57.             for (int i = 0; i < 300; i++)
  58.             {
  59.                 ObjectId[] firstExplodeObjIds;
  60.  
  61.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  62.                 {
  63.                     FeatureLabel label = tr.GetObject(selObjId, OpenMode.ForRead) as FeatureLabel;
  64.  
  65.                     firstExplodeObjIds = ExplodeObject(label, tr);
  66.  
  67.                     tr.Commit();
  68.                 }
  69.  
  70.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  71.                 {
  72.                     foreach (ObjectId id in firstExplodeObjIds)
  73.                     {
  74.                         AcEntity ent = tr.GetObject(id, OpenMode.ForWrite) as AcEntity;
  75.                         if (ent is BlockReference blkRef
  76.                             && blkRef.Name.StartsWith("*U", StringComparison.OrdinalIgnoreCase))
  77.                         {
  78.                             ExplodeObject(ent, tr);
  79.                             ent.Erase(true);
  80.                         }
  81.                     }
  82.                     tr.Commit();
  83.                 }
  84.             }
  85.         }
  86.  
  87.         static ObjectId[] ExplodeObject(AcEntity ent, Transaction tr)
  88.         {
  89.             Database db = ent.Database;
  90.  
  91.             List<ObjectId> objIds = new List<ObjectId>();
  92.  
  93.             DBObjectCollection objCol = new DBObjectCollection();
  94.             ent.Explode(objCol);
  95.  
  96.             BlockTableRecord cSpace = tr.GetObject
  97.                 (db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  98.  
  99.             foreach (AcEntity dBObject in objCol)
  100.             {
  101.                 ObjectId newObjId = cSpace.AppendEntity(dBObject);
  102.                 objIds.Add(newObjId);
  103.                 tr.AddNewlyCreatedDBObject(dBObject, true);
  104.             }
  105.  
  106.             return objIds.ToArray();
  107.         }
  108.     }
  109. }
  110.  
Суть такая: выбирается метка с блоком в чертеже и взрывается 300 раз. Если получается анонимный блок, то он снова взрывается. Полученные после взрыва объекты сохраняются в чертеже.
Опыты показали, что если расчленять метки этой командой в "чистом" Civil 3D, то всё проходит гладко. Без вылетов и исключений.
Но если загрузить в Civil 3D моё основное приложение (в котором есть обработки событий и Overrule), при выполнении этой команды в том же самом чертеже Civil падает с вероятностью 99%.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
...Опыты показали, что если расчленять метки этой командой в "чистом" Civil 3D, то всё проходит гладко. Без вылетов и исключений.
Но если загрузить в Civil 3D моё основное приложение (в котором есть обработки событий и Overrule), при выполнении этой команды в том же самом чертеже Civil падает с вероятностью 99%.
Ну тут ты вроде сам даёшь ответ на свой вопрос - нужно более детально разбираться с твоими обработчиками событий и Overrule.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Да. Это сейчас наподобие "Здравствуй мой дорогой дневничок..."  :)
Чтобы самому не забыть ничего и как некий путевой лист для тех, кто в будущем с этим может столкнуться.
Дальнейшие опыты показали, что при отключении всех Overrule для меток проблема пропадает. Модифицировал код, чтобы исследовать поведение DrawableOverrule и TransformOverrule:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.GraphicsInterface;
  5. using Autodesk.AutoCAD.Runtime;
  6. using Autodesk.Civil.DatabaseServices;
  7. using Autodesk.Civil.DatabaseServices.Styles;
  8. using System;
  9. using System.Collections.Generic;
  10. using AcEntity = Autodesk.AutoCAD.DatabaseServices.Entity;
  11.  
  12. namespace C3dTest
  13. {
  14.     public class ExplodeLabelTest : IExtensionApplication
  15.     {
  16.         public void Initialize()
  17.         {
  18.             Overrule.AddOverrule
  19.                 (RXClass.GetClass(typeof(FeatureLabel)),
  20.                 FeatureLabelDaravableOverrule.Instance,
  21.                 true);
  22.  
  23.             Overrule.AddOverrule
  24.                 (RXClass.GetClass(typeof(FeatureLabel)),
  25.                 FeatureLabelTransformOverrule.Instance,
  26.                 true);
  27.         }
  28.  
  29.         public void Terminate()
  30.         {
  31.         }
  32.  
  33.         [CommandMethod("ExplodeLabelWithBlockTest")]
  34.         public void Run()
  35.         {
  36.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  37.             Editor ed = adoc.Editor;
  38.             Database db = adoc.Database;
  39.  
  40.             PromptEntityOptions entityOptions
  41.                 = new PromptEntityOptions("\nSelect a label with a block component: ");
  42.  
  43.             entityOptions.SetRejectMessage("\nIt's not a label!");
  44.  
  45.             entityOptions.AddAllowedClass(typeof(FeatureLabel), false);
  46.            
  47.             ObjectId selObjId = default;
  48.  
  49.             while (!selObjId.IsValid)
  50.             {
  51.                 PromptEntityResult result = ed.GetEntity(entityOptions);
  52.  
  53.                 if (result.Status != PromptStatus.OK) break;                
  54.  
  55. #pragma warning disable CS0618 // Type or member is obsolete
  56.                 using (FeatureLabel label = result.ObjectId.Open(OpenMode.ForRead) as FeatureLabel)
  57.                 using (LabelStyle style = label.StyleId.Open(OpenMode.ForRead) as LabelStyle)
  58. #pragma warning restore CS0618 // Type or member is obsolete
  59.                 {
  60.                     ObjectIdCollection blkCompCol
  61.                         = style.GetComponents(LabelStyleComponentType.Block);
  62.                     if (blkCompCol.Count > 0)
  63.                     {
  64.                         selObjId = result.ObjectId;
  65.                     }
  66.                     else
  67.                     {
  68.                         ed.WriteMessage("\nThe label does not have a block component!");
  69.                     }
  70.                 }                
  71.             }
  72.  
  73.             if (!selObjId.IsValid) return;
  74.  
  75.             PromptIntegerOptions integerOptions = new PromptIntegerOptions("\nNumber of repeats: ");
  76.             integerOptions.AllowNegative = false;
  77.             integerOptions.AllowZero = false;
  78.             integerOptions.DefaultValue = 300;
  79.             integerOptions.UseDefaultValue = true;
  80.             PromptIntegerResult intResult = ed.GetInteger(integerOptions);
  81.             if (intResult.Status != PromptStatus.OK) return;
  82.  
  83.             FeatureLabelDaravableOverrule.Counter = 0;
  84.             FeatureLabelTransformOverrule.Counter = 0;
  85.  
  86.             for (int i = 0; i < intResult.Value; i++)
  87.             {
  88.                 ObjectId[] firstExplodeObjIds;
  89.  
  90.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  91.                 {
  92.                     FeatureLabel label = tr.GetObject(selObjId, OpenMode.ForRead) as FeatureLabel;
  93.  
  94.                     firstExplodeObjIds = ExplodeObject(label, tr);
  95.  
  96.                     tr.Commit();
  97.                 }
  98.  
  99.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  100.                 {
  101.                     foreach (ObjectId id in firstExplodeObjIds)
  102.                     {
  103.                         AcEntity ent = tr.GetObject(id, OpenMode.ForWrite) as AcEntity;
  104.                         if (ent is BlockReference blkRef
  105.                             && blkRef.Name.StartsWith("*U", StringComparison.OrdinalIgnoreCase))
  106.                         {
  107.                             ExplodeObject(ent, tr);
  108.                             ent.Erase(true);
  109.                         }
  110.                     }
  111.                     tr.Commit();
  112.                 }
  113.             }
  114.  
  115.             Application.ShowAlertDialog
  116.                 ($"Number of explodes: {intResult.Value}\n" +
  117.                 $"Drawable hits: {FeatureLabelDaravableOverrule.Counter}.\n" +
  118.                 $"Transform hits: {FeatureLabelTransformOverrule.Counter}.");
  119.         }
  120.  
  121.         static ObjectId[] ExplodeObject(AcEntity ent, Transaction tr)
  122.         {
  123.             Database db = ent.Database;
  124.  
  125.             List<ObjectId> objIds = new List<ObjectId>();
  126.  
  127.             DBObjectCollection objCol = new DBObjectCollection();
  128.             ent.Explode(objCol);
  129.  
  130.             BlockTableRecord cSpace = tr.GetObject
  131.                 (db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  132.  
  133.             foreach (AcEntity dBObject in objCol)
  134.             {
  135.                 ObjectId newObjId = cSpace.AppendEntity(dBObject);
  136.                 objIds.Add(newObjId);
  137.                 tr.AddNewlyCreatedDBObject(dBObject, true);
  138.             }
  139.  
  140.             return objIds.ToArray();
  141.         }
  142.     }
  143.  
  144.     public class FeatureLabelTransformOverrule : TransformOverrule
  145.     {
  146.         public static int Counter = 0;
  147.  
  148.         static FeatureLabelTransformOverrule _instance;
  149.  
  150.         public static FeatureLabelTransformOverrule Instance
  151.         {
  152.             get
  153.             {
  154.                 if (_instance is null)
  155.                 {
  156.                     _instance = new FeatureLabelTransformOverrule();
  157.                 }
  158.                 return _instance;
  159.             }
  160.         }
  161.  
  162.         private FeatureLabelTransformOverrule() { }
  163.  
  164.         public override void Explode(AcEntity entity, DBObjectCollection entitySet)
  165.         {
  166.             Counter++;
  167.             base.Explode(entity, entitySet);
  168.         }
  169.     }
  170.  
  171.     public class FeatureLabelDaravableOverrule : DrawableOverrule
  172.     {
  173.         public static int Counter = 0;
  174.  
  175.         static FeatureLabelDaravableOverrule _instance;
  176.  
  177.         public static FeatureLabelDaravableOverrule Instance
  178.         {
  179.             get
  180.             {
  181.                 if (_instance is null)
  182.                 {
  183.                     _instance = new FeatureLabelDaravableOverrule();
  184.                 }
  185.                 return _instance;
  186.             }
  187.         }
  188.  
  189.         private FeatureLabelDaravableOverrule() { }
  190.  
  191.         public override void ViewportDraw(Drawable drawable, ViewportDraw vd)
  192.         {
  193.             Counter++;
  194.             base.ViewportDraw(drawable, vd);
  195.         }
  196.     }
  197. }
  198.  
То есть, как результат выводятся данные о том, сколько раз вызывались методы Overrule при заданном количестве взрывов объекта.
Тест показал, что на каждое расчленение метки 22 (!) раза вызывается её перерисовка! Как считаете, это нормально?

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Тест показал, что на каждое расчленение метки 22 (!) раза вызывается её перерисовка! Как считаете, это нормально?
Считаю это ненормальным, тем более, что этот примитив не меняется при вызове Explode. Мне вот только интересно всё ли время в метод ViewportDraw попадает именно FeatureLabel - у меня подозрения, что это не так.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Переделал код так:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.GraphicsInterface;
  5. using Autodesk.AutoCAD.Runtime;
  6. using Autodesk.Civil.DatabaseServices;
  7. using Autodesk.Civil.DatabaseServices.Styles;
  8. using System;
  9. using System.Collections.Generic;
  10. using AcEntity = Autodesk.AutoCAD.DatabaseServices.Entity;
  11.  
  12. namespace C3dTest
  13. {
  14.     public class ExplodeLabelTest : IExtensionApplication
  15.     {
  16.         public void Initialize()
  17.         {
  18.             Overrule.AddOverrule
  19.                 (RXClass.GetClass(typeof(FeatureLabel)),
  20.                 FeatureLabelDaravableOverrule.Instance,
  21.                 true);
  22.  
  23.             Overrule.AddOverrule
  24.                 (RXClass.GetClass(typeof(FeatureLabel)),
  25.                 FeatureLabelTransformOverrule.Instance,
  26.                 true);
  27.         }
  28.  
  29.         public void Terminate()
  30.         {
  31.         }
  32.  
  33.         [CommandMethod("ExplodeLabelWithBlockTest")]
  34.         public void Run()
  35.         {
  36.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  37.             Editor ed = adoc.Editor;
  38.             Database db = adoc.Database;
  39.  
  40.             PromptEntityOptions entityOptions
  41.                 = new PromptEntityOptions("\nSelect a label with a block component: ");
  42.  
  43.             entityOptions.SetRejectMessage("\nIt's not a label!");
  44.  
  45.             entityOptions.AddAllowedClass(typeof(FeatureLabel), false);
  46.            
  47.             ObjectId selObjId = default;
  48.  
  49.             while (!selObjId.IsValid)
  50.             {
  51.                 PromptEntityResult result = ed.GetEntity(entityOptions);
  52.  
  53.                 if (result.Status != PromptStatus.OK) break;                
  54.  
  55. #pragma warning disable CS0618 // Type or member is obsolete
  56.                 using (FeatureLabel label = result.ObjectId.Open(OpenMode.ForRead) as FeatureLabel)
  57.                 using (LabelStyle style = label.StyleId.Open(OpenMode.ForRead) as LabelStyle)
  58. #pragma warning restore CS0618 // Type or member is obsolete
  59.                 {
  60.                     ObjectIdCollection blkCompCol
  61.                         = style.GetComponents(LabelStyleComponentType.Block);
  62.                     if (blkCompCol.Count > 0)
  63.                     {
  64.                         selObjId = result.ObjectId;
  65.                     }
  66.                     else
  67.                     {
  68.                         ed.WriteMessage("\nThe label does not have a block component!");
  69.                     }
  70.                 }                
  71.             }
  72.  
  73.             if (!selObjId.IsValid) return;
  74.  
  75.             PromptIntegerOptions integerOptions = new PromptIntegerOptions("\nNumber of repeats: ");
  76.             integerOptions.AllowNegative = false;
  77.             integerOptions.AllowZero = false;
  78.             integerOptions.DefaultValue = 300;
  79.             integerOptions.UseDefaultValue = true;
  80.             PromptIntegerResult intResult = ed.GetInteger(integerOptions);
  81.             if (intResult.Status != PromptStatus.OK) return;
  82.  
  83.             FeatureLabelDaravableOverrule.ViewportDrawCounter = 0;
  84.             FeatureLabelDaravableOverrule.WorldDrawCounter = 0;
  85.             FeatureLabelTransformOverrule.Counter = 0;
  86.  
  87.             for (int i = 0; i < intResult.Value; i++)
  88.             {
  89.                 ObjectId[] firstExplodeObjIds;
  90.  
  91.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  92.                 {
  93.                     FeatureLabel label = tr.GetObject(selObjId, OpenMode.ForRead) as FeatureLabel;
  94.  
  95.                     firstExplodeObjIds = ExplodeObject(label, tr);
  96.  
  97.                     tr.Commit();
  98.                 }
  99.  
  100.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  101.                 {
  102.                     foreach (ObjectId id in firstExplodeObjIds)
  103.                     {
  104.                         AcEntity ent = tr.GetObject(id, OpenMode.ForWrite) as AcEntity;
  105.                         if (ent is BlockReference blkRef
  106.                             && blkRef.Name.StartsWith("*U", StringComparison.OrdinalIgnoreCase))
  107.                         {
  108.                             ExplodeObject(ent, tr);
  109.                             ent.Erase(true);
  110.                         }
  111.                     }
  112.                     tr.Commit();
  113.                 }
  114.             }
  115.  
  116.             Application.ShowAlertDialog
  117.                 ($"Number of explodes: {intResult.Value}\n" +
  118.                 $"Drawable ViewportDraw hits: {FeatureLabelDaravableOverrule.ViewportDrawCounter}.\n" +
  119.                 $"Drawable WorldDraw hits: {FeatureLabelDaravableOverrule.WorldDrawCounter}.\n" +
  120.                 $"Transform hits: {FeatureLabelTransformOverrule.Counter}.");
  121.         }
  122.  
  123.         static ObjectId[] ExplodeObject(AcEntity ent, Transaction tr)
  124.         {
  125.             Database db = ent.Database;
  126.  
  127.             List<ObjectId> objIds = new List<ObjectId>();
  128.  
  129.             DBObjectCollection objCol = new DBObjectCollection();
  130.             ent.Explode(objCol);
  131.  
  132.             BlockTableRecord cSpace = tr.GetObject
  133.                 (db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  134.  
  135.             foreach (AcEntity dBObject in objCol)
  136.             {
  137.                 ObjectId newObjId = cSpace.AppendEntity(dBObject);
  138.                 objIds.Add(newObjId);
  139.                 tr.AddNewlyCreatedDBObject(dBObject, true);
  140.             }
  141.  
  142.             return objIds.ToArray();
  143.         }
  144.     }
  145.  
  146.     public class FeatureLabelTransformOverrule : TransformOverrule
  147.     {
  148.         public static int Counter = 0;
  149.  
  150.         static FeatureLabelTransformOverrule _instance;
  151.  
  152.         public static FeatureLabelTransformOverrule Instance
  153.         {
  154.             get
  155.             {
  156.                 if (_instance is null)
  157.                 {
  158.                     _instance = new FeatureLabelTransformOverrule();
  159.                 }
  160.                 return _instance;
  161.             }
  162.         }
  163.  
  164.         private FeatureLabelTransformOverrule() { }
  165.  
  166.         public override void Explode(AcEntity entity, DBObjectCollection entitySet)
  167.         {
  168.             Counter++;
  169.             base.Explode(entity, entitySet);
  170.         }
  171.     }
  172.  
  173.     public class FeatureLabelDaravableOverrule : DrawableOverrule
  174.     {
  175.         public static int ViewportDrawCounter = 0;
  176.         public static int WorldDrawCounter = 0;
  177.  
  178.         static FeatureLabelDaravableOverrule _instance;
  179.  
  180.         public static FeatureLabelDaravableOverrule Instance
  181.         {
  182.             get
  183.             {
  184.                 if (_instance is null)
  185.                 {
  186.                     _instance = new FeatureLabelDaravableOverrule();
  187.                 }
  188.                 return _instance;
  189.             }
  190.         }
  191.  
  192.         private FeatureLabelDaravableOverrule() { }
  193.  
  194.         public override void ViewportDraw(Drawable drawable, ViewportDraw vd)
  195.         {
  196.             if (drawable is FeatureLabel)
  197.             {
  198.                 ViewportDrawCounter++;
  199.             }
  200.             base.ViewportDraw(drawable, vd);
  201.         }
  202.  
  203.         public override bool WorldDraw(Drawable drawable, WorldDraw wd)
  204.         {
  205.             if (drawable is FeatureLabel)
  206.             {
  207.                 WorldDrawCounter++;
  208.             }
  209.             return base.WorldDraw(drawable, wd);
  210.         }
  211.     }
  212. }
  213.  
Получил тот же самый результат.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
И для сравнения - с меткой, которая не содержит внутри блок (отключил соответствующую проверку)

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Честно говоря даже предположений от чего это происходит у меня нет. Видимо какой-то внутренний механизм у метода FeatureLabel.Explode к этому приводит.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Радует только то, что если добавить ещё блоков в метку, то число попаданий в DrawableOverrule не увеличивается. Так и остаётся ровно 22.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Радует только то, что если добавить ещё блоков в метку, то число попаданий в DrawableOverrule не увеличивается. Так и остаётся ровно 22.
Вопрос как это всё влияет на вылет Civil 3d при таком раскладе?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Есть у меня одна догадка. Если подтвердится - отпишусь.

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
В целом, результат есть. Только не знаю, насколько это корректное исследование.
В чём суть. Я решил проверить сколько раз откроется и закроется BlockTableRecord того блока, который используется в метке. Для этого я добавил ещё ObjectOverrule для BlockTableRecord:
Код - C# [Выбрать]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.GraphicsInterface;
  5. using Autodesk.AutoCAD.Runtime;
  6. using Autodesk.Civil.DatabaseServices;
  7. using Autodesk.Civil.DatabaseServices.Styles;
  8. using System;
  9. using System.Collections.Generic;
  10. using AcEntity = Autodesk.AutoCAD.DatabaseServices.Entity;
  11.  
  12. namespace C3dTest
  13. {
  14.     public class ExplodeLabelTest : IExtensionApplication
  15.     {
  16.         public static List<string> CurrentLabelBlockComponentsNames;
  17.  
  18.         public void Initialize()
  19.         {
  20.             Overrule.AddOverrule
  21.                 (RXClass.GetClass(typeof(FeatureLabel)),
  22.                 FeatureLabelDaravableOverrule.Instance,
  23.                 true);
  24.  
  25.             Overrule.AddOverrule
  26.                 (RXClass.GetClass(typeof(FeatureLabel)),
  27.                 FeatureLabelTransformOverrule.Instance,
  28.                 true);
  29.  
  30.             Overrule.AddOverrule
  31.                 (RXClass.GetClass(typeof(BlockTableRecord)),
  32.                 BlockTableRecordObjectOverrule.Instance,
  33.                 true);
  34.         }
  35.  
  36.         public void Terminate()
  37.         {
  38.         }
  39.  
  40.         [CommandMethod("ExplodeLabelWithBlockTest")]
  41.         public void Run()
  42.         {
  43.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  44.             Editor ed = adoc.Editor;
  45.             Database db = adoc.Database;
  46.  
  47.             PromptEntityOptions entityOptions
  48.                 = new PromptEntityOptions("\nSelect a label: ");
  49.  
  50.             entityOptions.SetRejectMessage("\nIt's not a label!");
  51.  
  52.             entityOptions.AddAllowedClass(typeof(FeatureLabel), false);
  53.             PromptEntityResult result = ed.GetEntity(entityOptions);
  54.  
  55.             if (result.Status != PromptStatus.OK) return;
  56.  
  57.             ObjectId selObjId = result.ObjectId;
  58.             int blockComponentsCount;
  59.             CurrentLabelBlockComponentsNames = new List<string>();
  60.  
  61. #pragma warning disable CS0618 // Type or member is obsolete
  62.             using (FeatureLabel label = result.ObjectId.Open(OpenMode.ForRead) as FeatureLabel)
  63.             using (LabelStyle style = label.StyleId.Open(OpenMode.ForRead) as LabelStyle)
  64. #pragma warning restore CS0618 // Type or member is obsolete
  65.             {
  66.                 ObjectIdCollection blkCompCol
  67.                     = style.GetComponents(LabelStyleComponentType.Block);
  68.                 blockComponentsCount = blkCompCol.Count;
  69.                 foreach (ObjectId blkCompId in blkCompCol)
  70.                 {
  71.                     LabelStyleBlockComponent blockComponent
  72. #pragma warning disable CS0618 // Type or member is obsolete
  73.                         = blkCompId.Open(OpenMode.ForRead) as LabelStyleBlockComponent;
  74. #pragma warning restore CS0618 // Type or member is obsolete
  75.  
  76.                     CurrentLabelBlockComponentsNames.Add(blockComponent.Block.BlockName.Value);
  77.                 }
  78.             }
  79.  
  80.             PromptIntegerOptions integerOptions
  81.                 = new PromptIntegerOptions("\nNumber of repeats: ");
  82.             integerOptions.AllowNegative = false;
  83.             integerOptions.AllowZero = false;
  84.             integerOptions.DefaultValue = 300;
  85.             integerOptions.UseDefaultValue = true;
  86.             PromptIntegerResult intResult = ed.GetInteger(integerOptions);
  87.             if (intResult.Status != PromptStatus.OK) return;
  88.  
  89.             FeatureLabelDaravableOverrule.ViewportDrawCounter = 0;
  90.             FeatureLabelDaravableOverrule.WorldDrawCounter = 0;
  91.             FeatureLabelTransformOverrule.Counter = 0;
  92.             BlockTableRecordObjectOverrule.OpenedCounter = 0;
  93.  
  94.             for (int i = 0; i < intResult.Value; i++)
  95.             {
  96.                 ObjectId[] firstExplodeObjIds;
  97.  
  98.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  99.                 {
  100.                     FeatureLabel label = tr.GetObject(selObjId, OpenMode.ForRead) as FeatureLabel;
  101.  
  102.                     firstExplodeObjIds = ExplodeObject(label, tr);
  103.  
  104.                     tr.Commit();
  105.                 }
  106.  
  107.                 using (Transaction tr = db.TransactionManager.StartTransaction())
  108.                 {
  109.                     foreach (ObjectId id in firstExplodeObjIds)
  110.                     {
  111.                         AcEntity ent = tr.GetObject(id, OpenMode.ForWrite) as AcEntity;
  112.                         if (ent is BlockReference blkRef
  113.                             && blkRef.Name.StartsWith("*U", StringComparison.OrdinalIgnoreCase))
  114.                         {
  115.                             ExplodeObject(ent, tr);
  116.                             ent.Erase(true);
  117.                         }
  118.                     }
  119.                     tr.Commit();
  120.                 }
  121.             }
  122.  
  123.             Application.ShowAlertDialog
  124.                 ($"Number of block components: {blockComponentsCount}" +
  125.                 $"\nNumber of explodes: {intResult.Value}\n" +
  126.                 $"Drawable ViewportDraw hits: {FeatureLabelDaravableOverrule.ViewportDrawCounter}.\n" +
  127.                 $"Drawable WorldDraw hits: {FeatureLabelDaravableOverrule.WorldDrawCounter}.\n" +
  128.                 $"Transform hits: {FeatureLabelTransformOverrule.Counter}\n" +
  129.                 $"Not closed block table records: {BlockTableRecordObjectOverrule.OpenedCounter}.");
  130.  
  131.             CurrentLabelBlockComponentsNames = null;
  132.         }
  133.  
  134.         static ObjectId[] ExplodeObject(AcEntity ent, Transaction tr)
  135.         {
  136.             Database db = ent.Database;
  137.  
  138.             List<ObjectId> objIds = new List<ObjectId>();
  139.  
  140.             DBObjectCollection objCol = new DBObjectCollection();
  141.             ent.Explode(objCol);
  142.  
  143.             BlockTableRecord cSpace = tr.GetObject
  144.                 (db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
  145.  
  146.             foreach (AcEntity dBObject in objCol)
  147.             {
  148.                 ObjectId newObjId = cSpace.AppendEntity(dBObject);
  149.                 objIds.Add(newObjId);
  150.                 tr.AddNewlyCreatedDBObject(dBObject, true);
  151.             }
  152.  
  153.             return objIds.ToArray();
  154.         }
  155.     }
  156.  
  157.     public class FeatureLabelTransformOverrule : TransformOverrule
  158.     {
  159.         public static int Counter = 0;
  160.  
  161.         static FeatureLabelTransformOverrule _instance;
  162.  
  163.         public static FeatureLabelTransformOverrule Instance
  164.         {
  165.             get
  166.             {
  167.                 if (_instance is null)
  168.                 {
  169.                     _instance = new FeatureLabelTransformOverrule();
  170.                 }
  171.                 return _instance;
  172.             }
  173.         }
  174.  
  175.         private FeatureLabelTransformOverrule() { }
  176.  
  177.         public override void Explode(AcEntity entity, DBObjectCollection entitySet)
  178.         {
  179.             Counter++;
  180.             base.Explode(entity, entitySet);
  181.         }
  182.     }
  183.  
  184.     public class FeatureLabelDaravableOverrule : DrawableOverrule
  185.     {
  186.         public static int ViewportDrawCounter = 0;
  187.         public static int WorldDrawCounter = 0;
  188.  
  189.         static FeatureLabelDaravableOverrule _instance;
  190.  
  191.         public static FeatureLabelDaravableOverrule Instance
  192.         {
  193.             get
  194.             {
  195.                 if (_instance is null)
  196.                 {
  197.                     _instance = new FeatureLabelDaravableOverrule();
  198.                 }
  199.                 return _instance;
  200.             }
  201.         }
  202.  
  203.         private FeatureLabelDaravableOverrule() { }
  204.  
  205.         public override void ViewportDraw(Drawable drawable, ViewportDraw vd)
  206.         {
  207.             if (drawable is FeatureLabel)
  208.             {
  209.                 ViewportDrawCounter++;
  210.             }
  211.             base.ViewportDraw(drawable, vd);
  212.         }
  213.  
  214.         public override bool WorldDraw(Drawable drawable, WorldDraw wd)
  215.         {
  216.             if (drawable is FeatureLabel)
  217.             {
  218.                 WorldDrawCounter++;
  219.             }
  220.             return base.WorldDraw(drawable, wd);
  221.         }
  222.     }
  223.  
  224.     public class BlockTableRecordObjectOverrule : ObjectOverrule
  225.     {
  226.         public static int OpenedCounter = 0;
  227.  
  228.         static BlockTableRecordObjectOverrule _instance;
  229.  
  230.         public static BlockTableRecordObjectOverrule Instance
  231.         {
  232.             get
  233.             {
  234.                 if (_instance is null)
  235.                 {
  236.                     _instance = new BlockTableRecordObjectOverrule();
  237.                 }
  238.                 return _instance;
  239.             }
  240.         }
  241.  
  242.         private BlockTableRecordObjectOverrule() { }
  243.  
  244.         public override void Open(Autodesk.AutoCAD.DatabaseServices.DBObject dbObject, OpenMode mode)
  245.         {
  246.             if (ExplodeLabelTest.CurrentLabelBlockComponentsNames != null
  247.                 && dbObject is BlockTableRecord record
  248.                 && ExplodeLabelTest.CurrentLabelBlockComponentsNames.Contains(record.Name))
  249.             {
  250.                 OpenedCounter++;
  251.             }
  252.             base.Open(dbObject, mode);
  253.         }
  254.  
  255.         public override void Close(Autodesk.AutoCAD.DatabaseServices.DBObject dbObject)
  256.         {
  257.             if (ExplodeLabelTest.CurrentLabelBlockComponentsNames != null
  258.                 && dbObject is BlockTableRecord record
  259.                 && ExplodeLabelTest.CurrentLabelBlockComponentsNames.Contains(record.Name))
  260.             {
  261.                 OpenedCounter--;
  262.             }
  263.             base.Close(dbObject);
  264.         }
  265.     }
  266. }
  267.  
В результате получается, что на каждую операцию расчленения два экземпляра остаются открытыми.
Можно ли доверять результатам полученным через методы ObjectOverrule? Могут закрываться объекты в обход него?
Либо, объекты эти закрываются позже того как завершится команда?

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Можно ли доверять результатам полученным через методы ObjectOverrule? Могут закрываться объекты в обход него?
Либо, объекты эти закрываются позже того как завершится команда?
На все вопросы вполне возможен положительный ответ. Проверить можно только то, закрываются ли объекты после завершения команды (в событие OnIdle).  Кстати, ты забыл, что для Open обратным действием кроме Close может быть еще и Cancel.
Но это может быть и баг в Civil 3D. Однозначно на этот вопрос могут ответить только в ADN DevHelp.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Еще одно замечание. eAtMaxReaders у тебя было на открытии BlockReference, а не BlockTableRecord. Или это сейчас ты проверяешь уже что-то другое?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Я подозреваю, что при открытии BlockReference открывается и соответствующая ему BlockTableRecord для чтения каких-то данных для BlockReference. И как раз на этом и происходит сбой.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Я подозреваю, что при открытии BlockReference открывается и соответствующая ему BlockTableRecord для чтения каких-то данных для BlockReference. И как раз на этом и происходит сбой.
На этапе открытия BlockReference не должен открываться BlockTableRecord. Впрочем ты можешь и это проверить. Тут ARXDBG и MGDDBG должны помочь.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Тут ARXDBG и MGDDBG должны помочь.
Я не смог найти там нужных инструментов. Нет там такого события "объект был открыт на чтение". Может просто проглядел - глаза уже от этих тестов немного в кучку...
Написал тестовый код, погонял. Тесты показали - да, нет входа в Open для BlockTableRecord, когда BlockReference открывается на чтение.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Тесты показали - да, нет входа в Open для BlockTableRecord, когда BlockReference открывается на чтение.
А с учетом Cancel - всё равно остались не закрытые BlockTableRecord?
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Да, в Cancel не попадает ни разу при выполнении кода.
Я сейчас делаю пошаговое выполнение, провожу очень тщательный анализ всего что происходит. Есть задумка по итогу собрать всё то странное что найду и отправить в DevHelp.

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Да, в Cancel не попадает ни разу при выполнении кода.
Ну если до входа в Idle нет закрытия, то похоже на баг в Civil 3D.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Ну если до входа в Idle нет закрытия
А как это поймать?

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Ну если до входа в Idle нет закрытия
А как это поймать?
Подпишись на событие Idle в конце своей команды Run, не вызывая CurrentLabelBlockComponentsNames = null;
В этом событии выведи результаты. Ну и сразу отпишись от события Idle.
Альтернативным может быть событие: Editor.EnteringQuiescentState
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

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

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Интересно, что в Civil 3D 2008 такая ошибка возникает и без дополнительных приложений (во всяком случае про то, что такие приложения установлены ни слова не сказано): https://forums.autodesk.com/t5/civil-3d-forum/drawings-getting-map-error/td-p/2046148
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Привалов Дмитрий

  • ADN Club
  • *****
  • Сообщений: 533
  • Карма: 117
Я подозреваю, что при открытии BlockReference открывается и соответствующая ему BlockTableRecord для чтения каких-то данных для BlockReference. И как раз на этом и происходит сбой.

Правильно подозреваешь. И возможно причина вылетов в этом.

Как писал ранее Александр Ривилис:
Кстати, BlockReference.Name открывает соответствующий BlockTableRecord и уже оттуда берёт Name.

Недавно наткнулся, что BlockReference.Name работает, если существует тот самый BlockTableRecord, а если имя брать неоткуда, то происходит вылет.

Возможно ты расчленяешь свои объекты, добавляешь в базу данных и запрашиваешь имя в одной транзакции. Возможно надо поэтапно, и возможно не только Name.

Для того, чтобы не было вылетов, при запросе имени не используй BlockReference.Name напрямую, попробуй такой подход для обхода и поиска проблемы:
Код - C# [Выбрать]
  1. ObjectId idRef = br.BlockTableRecord;//ну или AnonymousBlockTableRecord, DynamicBlockTableRecord смотря что надо
  2. if (idRef.IsValid)
  3. {
  4.    BlockTableRecord block = tr.GetObject(idRef, OpenMode.ForRead) as BlockTableRecord;
  5.    if (block != null)
  6.    {
  7.       string name = block.Name;
  8.    }
  9. }

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

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 735
Возможно ты расчленяешь свои объекты, добавляешь в базу данных и запрашиваешь имя в одной транзакции. Возможно надо поэтапно
Вынести расчленение вообще в отдельную транзакцию? А это мысль. Спасибо, попробую! Но уже не сегодня и не в ближайшие несколько дней. Пока пришлось отложить эту проблему.