Удаление слоя

Понадобилось мне тут удалить слой из файла. На слое, скорее всего, есть объекты. Че будем делать? Правильно, писать код :)

Общая логика вроде бы проста - снимаем блокировку и заморозку слоя, проходим по коллекции блоков, потом по составу каждого блока (если он не является внешней ссылкой), проверяем слой объекта, при необходимости удаляем объект, в конце - удаление слоя. Что еще... А, если объект - блок, то если он не лежит на удаляемом слое, пройтись по его атрибутам и удалить те, которые лежат на удаляемом слое. Вроде все? Ах, да! Работа выполняется только в текущем документе.

Я попробовал набросать код, благо он несложный:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
(vl-load-com)

(defun _kpblc-layer-erase-vla (name / _kpblc-conv-vla-to-list adoc clayer layer_del) ;|
*    Удаление слоя по имени.
*    Параметры вызова:
  name    имя слоя для удаления
|;

  (defun _kpblc-conv-vla-to-list (value / res)
    (cond ((listp value) (mapcar (function _kpblc-conv-vla-to-list) value))
          ((= (type value) 'variant) (_kpblc-conv-vla-to-list (vlax-variant-value value)))
          ((= (type value) 'safearray)
           (if (>= (vlax-safearray-get-u-bound value 1) 0)
             (_kpblc-conv-vla-to-list (vlax-safearray->list value))
             ) ;_ end of if
           )
          ((and (member (type value) (list 'ename 'str 'vla-object))
                (= (type (_kpblc-conv-ent-to-vla value)) 'vla-object)
                (vlax-property-available-p (_kpblc-conv-ent-to-vla value) 'count)
                ) ;_ end of and
           (vlax-for sub (_kpblc-conv-ent-to-vla value) (setq res (cons sub res)))
           )
          (t value)
          ) ;_ end of cond
    ) ;_ end of defun
  (if (and name
           (/= name "0")
           (not (wcmatch name "*|*"))
           (setq adoc (vla-get-activedocument (vlax-get-acad-object)))
           (= (type
                (setq layer_del (vl-catch-all-apply (function (lambda () (vla-item (vla-get-layers adoc) name)))))
                ) ;_ end of type
              'vla-object
              ) ;_ end of =
           ) ;_ end of and
    (progn (vla-startundomark adoc)
           (setq name (strcase name))
           (if (= (strcase (getvar "clayer")) name)
             (setvar "clayer" "0")
             ) ;_ end of if
           (vla-put-lock layer_del :vlax-false)
           (vla-put-freeze layer_del :vlax-false)
           (vlax-for blk_def (vla-get-blocks adoc)
             (if (equal (vla-get-isxref blk_def) :vlax-false)
               (progn
                 (vlax-for ent blk_def
                   (if (= (strcase (vla-get-layer ent)) name)
                     (vla-erase ent)
                     (if (wcmatch (vla-get-objectname ent) "*BlockRef*")
                       (foreach att (apply (function append)
                                           (mapcar (function (lambda (x)
                                                               (if (vlax-method-applicable-p ent x)
                                                                 (_kpblc-conv-vla-to-list (vlax-invoke-method ent x))
                                                                 ) ;_ end of if
                                                               ) ;_ end of lambda
                                                             ) ;_ end of function
                                                   '("getattributes" "getconstantattributes")
                                                   ) ;_ end of mapcar
                                           ) ;_ end of apply
                         (if (= (strcase (vla-get-layer att)) name)
                           (vla-erase att)
                           ) ;_ end of if
                         ) ;_ end of foreach
                       ) ;_ end of if
                     ) ;_ end of if
                   ) ;_ end of vlax-for
                 ) ;_ end of progn
               ) ;_ end of if
             ) ;_ end of vlax-for
           (vla-delete layer_del)
           (vla-endundomark adoc)
           (princ)
           ) ;_ end of progn
    ) ;_ end of if
  ) ;_ end of defun

... и время на обработку всего-то 3-метрового файла составило в некомпилированном варианте почти 4 секунды. Подозреваю, что использование ename-представлений сильно ситуацию не поменяет (но могу и ошибаться). И при этом вызов стандартной _.-laydel срабатывал практически моментально!

У _.-laydel есть другой недостаток: она выводит отчет в ком.строку. При этом попытки погасить вывод, меняя nomutt, cmdecho и menuecho никакого эффекта (по крайней мере у меня) не оказали. Ну что ж, попробуем на C# что-нибудь нарисовать. Нуачо, забавно же! Заодно и потренируюсь ;)

Как результат (логику не менял):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using System;

namespace NetToLisp
{
  public class LayerErase
  {
    [LispFunction("_kpblc-layer-erase")]
    public static bool LispEraseLayer(ResultBuffer arguments)
    {
      Array args = arguments.AsArray();
      bool res = false;
      if (args.Length == 1)
      {
        string sLayerName = ((TypedValue)(args.GetValue(0))).Value.ToString();
        if (sLayerName != "0")
        {
          Document doc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
          Database db = doc.Database;        

          using (Transaction tr = db.TransactionManager.StartTransaction())
          {
            LayerTable layerTable = (LayerTable)tr.GetObject(db.LayerTableId, OpenMode.ForRead);
            if (layerTable.Has(sLayerName))
            {
              ObjectId idLayerDelete = layerTable[sLayerName];
              ObjectId idCurrentLayer = db.Clayer;

              if (idCurrentLayer == idLayerDelete)
              {
                db.Clayer = layerTable["0"];
              }

              LayerTableRecord layer = (LayerTableRecord)tr.GetObject(idLayerDelete, OpenMode.ForRead);
              BlockTable blockTable = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);

              layer.IsLocked = false;
              layer.IsFrozen = false;

              foreach (ObjectId btrId in blockTable)
              {
                BlockTableRecord blockTableRecord = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);
                if (!blockTableRecord.IsFromExternalReference)
                {
                  foreach (ObjectId entId in blockTableRecord)
                  {
                    Entity ent = (Entity)tr.GetObject(entId, OpenMode.ForRead);
                    if (ent.Layer.ToUpper() == sLayerName.ToUpper())
                    {
                      ent.UpgradeOpen();
                      ent.Erase();
                    }
                    else
                    {
                      BlockReference blkRef = ent as BlockReference;
                      if (blkRef != null)
                      {
                        foreach (ObjectId attId in blkRef.AttributeCollection)
                        {
                          AttributeReference att = (AttributeReference)tr.GetObject(attId, OpenMode.ForRead);
                          if (att.Layer.ToUpper() == sLayerName.ToUpper())
                          {
                            att.UpgradeOpen();
                            att.Erase();
                          }
                        }
                      }
                    }
                  }
                }
              }
              layer.UpgradeOpen();
              layer.Erase();

              res = true;
              tr.Commit();
            }
          }
        }
      }
      return res;
    }
  }
}

Скорость - весьма впечатляет! Блин, действительно, что ли, начать на C# играться? :)

Размещено в .NET, Код LISP, Функции LISP · Метки: , ,



Поделитесь своим мнением


Я не робот.