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

ADN Club => Civil 3D API => Тема начата: Дмитрий Загорулькин от 05-06-2017, 18:33:11

Название: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 05-06-2017, 18:33:11
Накидал по-быстрому под наши сиюминутные нужды небольшой лиспик, который обрабатывает отстойные части колодцев в зависимости от толщины стенок подключенных труб. Все работает как надо, но после его работы не выбрать обработанные колодцы. Помогает только AUDIT. Не особо критично, но все же интересно, почему так?
Проверял на чертеже из комплекта для обучения: <Папка с установленным C3D>\Help\Civil Tutorials\Drawings:

Код - Auto/Visual Lisp [Выбрать]
  1. (defun c:setstructssumpdepth (/ sstolist     round        ss
  2.                                 lst          count        vla-struct
  3.                                 index        max-wall-thick
  4.                                 connected    wall-thick   sump-depth
  5.                                )
  6.  
  7.  
  8.   ;; Вспомогательная функция набор -> список
  9.   (defun sstolist (ss / sscnt sslist)
  10.     (setq sscnt 0)
  11.     (repeat (sslength ss)
  12.       (setq sslist (cons (ssname
  13.                            ss
  14.                            sscnt
  15.                          ) ;_ end of ssname
  16.                          sslist
  17.                    ) ;_ end of cons
  18.       ) ;_ end of setq
  19.       (setq sscnt (1+ sscnt)
  20.       ) ;_ end of setq
  21.     ) ;_ end of repeat
  22.     sslist
  23.   ) ;_ end of defun
  24.  
  25.   ;; Вспомогательная функция для округления
  26.   (defun round (num prec)
  27.     (* prec
  28.        (if (minusp num)
  29.          (fix (- (/ num prec) 0.5))
  30.          (fix (+ (/ num prec) 0.5))
  31.        ) ;_ end of if
  32.     ) ;_ end of *
  33.   ) ;_ end of defun
  34.  
  35.   (vl-load-com)
  36.   ;; Выбираем колодцы. Никакой защиты от неправильных действий
  37.   (setq ss (ssget '((0 . "AECC_STRUCTURE"))))
  38.   ;; Конвертируем набор в список vla-объектов
  39.   (setq lst (mapcar 'vlax-ename->vla-object (sstolist ss)))
  40.   ;; Счетчик обработанных колодцев
  41.   (setq count 0)
  42.   ;; Проходим по списку колодцев
  43.   (foreach vla-struct lst
  44.     ;; Если это соединительный колодец
  45.     (if (= (vlax-get-property vla-struct 'PartType) 102)
  46.       (progn
  47.         ;; Индекс для подключенных труб
  48.         (setq index 0
  49.               ;; Для сохранения максимальной толщины стенки трубы
  50.               max-wall-thick 0
  51.               ;; Кол-во подключенных труб
  52.               connected (vlax-get-property vla-struct 'ConnectedPipesCount)
  53.         ) ;_ end of setq
  54.         ;; Проходим по количеству подключенных труб в колодце
  55.         (repeat connected
  56.           (setq
  57.             ;; получаем толщину стенки трубы
  58.             wall-thick (vlax-get-property vla-struct 'PipeWallThickness index)
  59.             ;; увеличиваем индекс
  60.             index (1+ index)
  61.             ;; берем ее, если она больше предыдущих
  62.             max-wall-thick (max max-wall-thick wall-thick)
  63.           ) ;_ end of setq
  64.         ) ;_ end of repeat
  65.         ;; вычисляем глубину отстойной части
  66.         (setq sump-depth (+ 0.03 (round max-wall-thick 0.01)))
  67.         ;; задаем ее колодцу
  68.         (vlax-put-property vla-struct 'SumpDepth sump-depth)
  69.         ;; обновляем колодец в соответствии с подключенными трубами
  70.         (vlax-invoke-method vla-struct 'ResizeByPipeDepths)
  71.         ;; увеличиваем счетчик обработанных колодцев
  72.         (setq count (1+ count))
  73.       ) ;_ end of progn
  74.     ) ;_ end of if
  75.   ) ;_ end of foreach
  76.   ;; выводим сообщение о результатах
  77.   (princ (strcat "\nОбработано колодцев: " (itoa count)))
  78.   ;; тихий выход
  79.   (princ)
  80. ) ;_ end of defun
  81.  
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 05-06-2017, 18:39:11
Похоже на обычный баг. Проверь по-возможности в других версиях Civil 3D.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 05-06-2017, 18:47:34
Проверил в 2014, 2016 и 2018 - везде одинаковое поведение.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 05-06-2017, 19:05:22
А тоже самое, но на C#?
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 05-06-2017, 19:29:43
Да, такое же поведение! Баг?
Код - 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 System;
  7.  
  8. namespace C3dTest
  9. {
  10.     public class ActiveXForStruct
  11.     {
  12.         [CommandMethod("TestActiveXForStruct")]
  13.         public void RunTest()
  14.         {
  15.             Document adoc = Application.DocumentManager.MdiActiveDocument;
  16.             Editor ed = adoc.Editor;
  17.             Database db = adoc.Database;
  18.  
  19.             PromptSelectionOptions selOpts = new PromptSelectionOptions()
  20.             {
  21.                 MessageForAdding = "\nSelect structures: "                
  22.             };
  23.             SelectionFilter selFl = new SelectionFilter(new TypedValue[]
  24.                 { new TypedValue((int)DxfCode.Start, "AECC_STRUCTURE") });
  25.  
  26.             PromptSelectionResult selRes = ed.GetSelection(selOpts, selFl);
  27.             if (selRes.Status != PromptStatus.OK) return;
  28.  
  29.             ObjectId[] ids = selRes.Value.GetObjectIds();
  30.  
  31.             int counter = 0;
  32.  
  33.             foreach (ObjectId id in ids)
  34.             {
  35.                 dynamic structCom;
  36.                 using (Structure structure = id.Open(OpenMode.ForRead) as Structure)
  37.                 {
  38.                     structCom = structure.AcadObject;
  39.                 }
  40.  
  41.                 if (structCom.PartType == 102)
  42.                 {                    
  43.                     double maxWallThick = 0;
  44.                     int connected = structCom.ConnectedPipesCount;
  45.                     for (int index = 0; index < connected; index++)
  46.                     {
  47.                         double wallThick = structCom.PipeWallThickness(index);
  48.                         maxWallThick = Math.Max(maxWallThick, wallThick);
  49.                     }
  50.                     double sumpDepth = 0.03 + Math.Round(maxWallThick, 2);
  51.                     structCom.SumpDepth = sumpDepth;
  52.                     structCom.ResizeByPipeDepths();
  53.                     counter++;
  54.                 }
  55.             }
  56.  
  57.             ed.WriteMessage("\nОбработано колодцев: {0} шт.", counter);
  58.         }
  59.     }
  60. }
  61.  
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 05-06-2017, 19:35:05
Думаю, что да. Отправь в ADN DevHelp. Интересно что они скажут.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 05-06-2017, 19:38:00
Думаю, что скажут: "Use .NET API instead!"  :)
Ок, отправлю.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 05-06-2017, 19:52:23
Думаю, что скажут: "Use .NET API instead!"  :)
А через .NET API тоже самое работает нормально?
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 05-06-2017, 19:56:33
Да, в .NET с этим порядок. Я на Лиспе писал просто для быстроты
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 05-06-2017, 20:11:16
Тогда задавай вопрос про Lisp, чтобы на .NET не "съезжали". :)
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 20-06-2017, 10:22:55
Пока ответ такой:
Цитировать
Civil 3D COM API не поддерживает LISP. В некоторых случаях он может работать, но в основном возникают проблемы типа этой
Будем дальше вести диалог.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 20-06-2017, 11:01:32
Собственно говоря то, что мы и предполагали.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 20-06-2017, 12:47:48
Немного не то. Я ожидал услышать "Используйте .NET API вместо COM", а ответили "Не используйте LISP в COM". Отправил код C# из #4, посмотрим, что скажут.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 20-06-2017, 13:00:08
....Я ожидал услышать "Используйте .NET API вместо COM"....
Это будет следующим ответом, так как ты подставился и показал, что умеешь писать с помощью .NET :D
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 20-06-2017, 13:04:15
Я думаю, что Augusto Gonsalves и так об этом подозревает :)
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 22-06-2017, 18:48:28
Моим большим проколом оказалось то, что я использовал код .NET для получения COM-объектов колодцев. Мне посоветовали расширить блок using на все изменения, тогда проблема пропадает. Написал и отправил такой простейший, практически "чисто COM", код. При его использовании проблема сохраняется:
Код - C# [Выбрать]
  1. using Autodesk.AECC.Interop.Pipe;
  2. using Autodesk.AutoCAD.ApplicationServices;
  3. using Autodesk.AutoCAD.Interop;
  4. using Autodesk.AutoCAD.Runtime;
  5.  
  6. namespace C3dCOMTest
  7. {
  8.     public class CmdClass
  9.     {
  10.         [CommandMethod("C3dComTest")]
  11.         public void RunCmd()
  12.         {
  13.             AcadApplication acadApp = Application.AcadApplication as AcadApplication;
  14.             AcadDocument adoc = acadApp.ActiveDocument;
  15.             AcadSelectionSet ss = adoc.SelectionSets.Add("SSET");
  16.             ss.SelectOnScreen();
  17.  
  18.             for (int i = 0; i < ss.Count; i++)
  19.             {
  20.                 AeccStructure structure = ss.Item(i) as AeccStructure;
  21.                 if (structure == null || structure.PartType != 102) continue;                
  22.                 structure.ResizeByPipeDepths();
  23.             }
  24.  
  25.             ss.Clear();
  26.             ss.Delete();
  27.         }
  28.     }
  29. }
  30.  
Честно говоря, очень не верится, что проблема только из-за того, что код был написан на LISP. Или, может, я неправ?
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 22-06-2017, 19:30:57
Честно говоря, очень не верится, что проблема только из-за того, что код был написан на LISP. Или, может, я неправ?
Мне тоже не верится, так как Lisp + COM/ActiveX или не работает совсем или работает нормально (так же как и в VBA/.NET). Здесь же какой-то третий вариант.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Дмитрий Загорулькин от 23-06-2017, 12:01:51
В общем, мы сошлись на том, что это некорректная работа метода ResizeByPipeDepths в COM API. Надежды на скорое исправление нет, поэтому, остается только .NET API.
Название: Re: LISP. Странная работа методов ActiveX для колодца сети.
Отправлено: Александр Ривилис от 23-06-2017, 12:28:11
Отметил это как решение.