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

ADN Club => Civil 3D API => Тема начата: Дмитрий Загорулькин от 23-01-2020, 12:02:21

Название: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 12:02:21
Начало этой темы тут: 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%.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 23-01-2020, 12:26:39
...Опыты показали, что если расчленять метки этой командой в "чистом" Civil 3D, то всё проходит гладко. Без вылетов и исключений.
Но если загрузить в Civil 3D моё основное приложение (в котором есть обработки событий и Overrule), при выполнении этой команды в том же самом чертеже Civil падает с вероятностью 99%.
Ну тут ты вроде сам даёшь ответ на свой вопрос - нужно более детально разбираться с твоими обработчиками событий и Overrule.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 14:48:49
Да. Это сейчас наподобие "Здравствуй мой дорогой дневничок..."  :)
Чтобы самому не забыть ничего и как некий путевой лист для тех, кто в будущем с этим может столкнуться.
Дальнейшие опыты показали, что при отключении всех 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 (!) раза вызывается её перерисовка! Как считаете, это нормально?
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 23-01-2020, 14:58:10
Тест показал, что на каждое расчленение метки 22 (!) раза вызывается её перерисовка! Как считаете, это нормально?
Считаю это ненормальным, тем более, что этот примитив не меняется при вызове Explode. Мне вот только интересно всё ли время в метод ViewportDraw попадает именно FeatureLabel - у меня подозрения, что это не так.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 15:08:11
Переделал код так:
Код - 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.  
Получил тот же самый результат.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 15:12:35
И для сравнения - с меткой, которая не содержит внутри блок (отключил соответствующую проверку)
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 23-01-2020, 15:17:29
Честно говоря даже предположений от чего это происходит у меня нет. Видимо какой-то внутренний механизм у метода FeatureLabel.Explode к этому приводит.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 15:40:07
Радует только то, что если добавить ещё блоков в метку, то число попаданий в DrawableOverrule не увеличивается. Так и остаётся ровно 22.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 23-01-2020, 15:43:27
Радует только то, что если добавить ещё блоков в метку, то число попаданий в DrawableOverrule не увеличивается. Так и остаётся ровно 22.
Вопрос как это всё влияет на вылет Civil 3d при таком раскладе?
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 15:45:27
Есть у меня одна догадка. Если подтвердится - отпишусь.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 16:17:58
В целом, результат есть. Только не знаю, насколько это корректное исследование.
В чём суть. Я решил проверить сколько раз откроется и закроется 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? Могут закрываться объекты в обход него?
Либо, объекты эти закрываются позже того как завершится команда?
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 23-01-2020, 17:06:57
Можно ли доверять результатам полученным через методы ObjectOverrule? Могут закрываться объекты в обход него?
Либо, объекты эти закрываются позже того как завершится команда?
На все вопросы вполне возможен положительный ответ. Проверить можно только то, закрываются ли объекты после завершения команды (в событие OnIdle).  Кстати, ты забыл, что для Open обратным действием кроме Close может быть еще и Cancel.
Но это может быть и баг в Civil 3D. Однозначно на этот вопрос могут ответить только в ADN DevHelp.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 23-01-2020, 17:23:44
Еще одно замечание. eAtMaxReaders у тебя было на открытии BlockReference, а не BlockTableRecord. Или это сейчас ты проверяешь уже что-то другое?
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 17:40:50
Я подозреваю, что при открытии BlockReference открывается и соответствующая ему BlockTableRecord для чтения каких-то данных для BlockReference. И как раз на этом и происходит сбой.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 23-01-2020, 17:50:05
Я подозреваю, что при открытии BlockReference открывается и соответствующая ему BlockTableRecord для чтения каких-то данных для BlockReference. И как раз на этом и происходит сбой.
На этапе открытия BlockReference не должен открываться BlockTableRecord. Впрочем ты можешь и это проверить. Тут ARXDBG и MGDDBG должны помочь.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 23-01-2020, 19:36:06
Тут ARXDBG и MGDDBG должны помочь.
Я не смог найти там нужных инструментов. Нет там такого события "объект был открыт на чтение". Может просто проглядел - глаза уже от этих тестов немного в кучку...
Написал тестовый код, погонял. Тесты показали - да, нет входа в Open для BlockTableRecord, когда BlockReference открывается на чтение.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 24-01-2020, 16:49:04
Тесты показали - да, нет входа в Open для BlockTableRecord, когда BlockReference открывается на чтение.
А с учетом Cancel - всё равно остались не закрытые BlockTableRecord?
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 24-01-2020, 17:05:02
Да, в Cancel не попадает ни разу при выполнении кода.
Я сейчас делаю пошаговое выполнение, провожу очень тщательный анализ всего что происходит. Есть задумка по итогу собрать всё то странное что найду и отправить в DevHelp.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 24-01-2020, 17:06:54
Да, в Cancel не попадает ни разу при выполнении кода.
Ну если до входа в Idle нет закрытия, то похоже на баг в Civil 3D.
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 24-01-2020, 17:11:51
Ну если до входа в Idle нет закрытия
А как это поймать?
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 24-01-2020, 17:19:27
Ну если до входа в Idle нет закрытия
А как это поймать?
Подпишись на событие Idle в конце своей команды Run, не вызывая CurrentLabelBlockComponentsNames = null;
В этом событии выведи результаты. Ну и сразу отпишись от события Idle.
Альтернативным может быть событие: Editor.EnteringQuiescentState
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Александр Ривилис от 24-01-2020, 17:29:56
Интересно, что в Civil 3D 2008 такая ошибка возникает и без дополнительных приложений (во всяком случае про то, что такие приложения установлены ни слова не сказано): https://forums.autodesk.com/t5/civil-3d-forum/drawings-getting-map-error/td-p/2046148
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Привалов Дмитрий от 27-01-2020, 16:08:51
Я подозреваю, что при открытии 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. }
Название: Re: Чем вызваны вылеты Civil 3D в процессе расчленения его объектов?
Отправлено: Дмитрий Загорулькин от 27-01-2020, 17:42:36
Возможно ты расчленяешь свои объекты, добавляешь в базу данных и запрашиваешь имя в одной транзакции. Возможно надо поэтапно
Вынести расчленение вообще в отдельную транзакцию? А это мысль. Спасибо, попробую! Но уже не сегодня и не в ближайшие несколько дней. Пока пришлось отложить эту проблему.