Преобразование единиц измерения блоков в файле

Известно, что при создании блока (ручного создания) можно указывать единицы, в которых этот блок будет вставляться: миллиметры, метры, дюймы и т.д. Это удобно, если гарантируется, что вся работа всегда выполняется на основе единственного шаблона с раз и навсегда настроенными единицами. Но бывает такое не всегда (да и за смежниками, бывает, приходится “доделывать”).

Оптимальным решением, как ни странно, будут “безразмерные” блоки. То есть те, у которых единицы – “Unitless” (в русской версии перевода не помню). С новыми блоками все понятно – достаточно контролировать это значение и стараться не допускать ошибок. А что делать со старыми, уже вставленными? Да очень просто – заменить!

Менять можно вручную, переопределяя блоки (к примеру). И этот подход более чем достаточен, если блоков 1-2. Ну, всяко не больше 10 (и то лично я уже на втором озверею). Программное решение намного более интересно.

Вариантов программы, конечно, может быть сколько угодно. Рассмотрим 2: либо обрабатывать все блоки в файле (независимо ни от чего), либо обрабатывать только указанные блоки. В набор обрабатываемых блоков может попадать несколько блоков. ТЗ составлено, приступаем к реализации.

Наиболее удобным будет применение ActiveX – код получится достаточно простым, читабельным и понятным.

(vl-load-com)

;; Вызов: (lispru-change-block-units)
(defun lispru-change-block-units (/ adoc)
  ;; Поставим метку начала отмены. Ну так, на всякий случай
  (vla-startundomark (setq adoc (vla-get-activedocument (vlax-get-acad-object))))
  ;; Проходим по всем описаниям блоков документа
  (vlax-for blk_def (vla-get-blocks adoc)
    ;; Из обработки исключаем внешние ссылки, пространства модели и листа
    (if (and (equal (vla-get-islayout blk_def) :vlax-false)
             (equal (vla-get-isxref blk_def) :vlax-false)
             ;; И дополнительно исключаем блоки таблиц и размеров
             (not (wcmatch (strcase (vla-get-name blk_def)) "`*D*,`*T*"))
             ) ;_ end of and
      (vl-catch-all-apply
        (function
          (lambda ()
            (vla-put-units blk_def 0)
            ) ;_ end of lambda
          ) ;_ end of function
        ) ;_ end of vl-catch-all-apply
      ) ;_ end of if
    ) ;_ end of vlax-for
  ;; Теперь метка конца отмены
  (vla-endundomark adoc)
  ;; Ну и "тихий" выход
  (princ)
  ) ;_ end of defun

При обработке выбранных блоков код немного усложняется:

(vl-load-com)

;; Вызов: (lispru-change-block-units-by-select)
(defun lispru-change-block-units-by-select (/ _dwgru-conv-pickset-to-list adoc selset blk_list name)

  (defun fun_get-name (ent)
    ;; Получение имени блока
    (cond
      ((vlax-property-available-p ent 'effectivename)
       (vla-get-effectivename ent)
       )
      ((vlax-property-available-p ent 'name)
       (vla-get-name ent)
       )
      ) ;_ end of cond
    ) ;_ end of defun

  (defun _dwgru-conv-pickset-to-list (value / tab item)
;;; http://forum.dwg.ru/showpost.php?p=188342&postcount=21
    (repeat (setq tab  nil
                  item (sslength value)
                  ) ;_ end setq
      (setq tab (cons (ssname value (setq item (1- item))) tab))
      ) ;_ end repeat
    ) ;_ end defun

  ;; Поставим метку начала отмены. Ну так, на всякий случай
  (vla-startundomark (setq adoc (vla-get-activedocument (vlax-get-acad-object))))
  ;; Получаем набор блоков, обрабатывая нажатие Esc
  (if (= (type (setq selset (vl-catch-all-apply
                              (function
                                (lambda ()
                                  (ssget '((0 . "INSERT")))
                                  ) ;_ end of lambda
                                ) ;_ end of function
                              ) ;_ end of vl-catch-all-apply
                     ) ;_ end of setq
               ) ;_ end of type
         'pickset
         ) ;_ end of =
    (progn
      ;; Сформируем список имен блоков, исключая дубликаты
      (foreach ent
                   ;; Преобразовываем набор в список элементов, исключая внешние ссылки.
                   ;; Это при полностью программной обработке надо отслеживать блоки листов
                   ;; и модели. Вручную их не выделить.
                   (vl-remove-if
                     (function
                       (lambda (x)
                         (equal (vla-get-isxref (vla-item (vla-get-blocks adoc) (vla-get-name x))) :vlax-true)
                         ) ;_ end of lambda
                       ) ;_ end of function
                     (mapcar (function vlax-ename->vla-object) (_dwgru-conv-pickset-to-list selset))
                     ) ;_ end of vl-remove-if
        (if (not (member (setq name (fun_get-name ent)) blk_list))
          (setq blk_list (cons name blk_list))
          ) ;_ end of if
        ) ;_ end of foreach
      ;; Запускаем новый цикл
      (foreach blk_def
                       ;; Из списка имен получаем список указателей на описания блоков
                       (mapcar
                         (function
                           (lambda (x)
                             (vla-item (vla-get-blocks adoc) x)
                             ) ;_ end of lambda
                           ) ;_ end of function
                         blk_list
                         ) ;_ end of mapcar
        (vl-catch-all-apply
          (function
            (lambda ()
              (vla-put-units blk_def 0)
              ) ;_ end of lambda
            ) ;_ end of function
          ) ;_ end of vl-catch-all-apply
        ) ;_ end of foreach
      ) ;_ end of progn
    ) ;_ end of if
  ;; Теперь метка конца отмены
  (vla-endundomark adoc)
  ;; Ну и "тихий" выход
  (princ)
  ) ;_ end of defun

У этого кода есть один, но очень серьезный недостаток: он не обрабатывает (по крайней мере на данный момент) вложенные блоки.

Конечно, будь этот код “для работы”, я бы исправил эту ошибку и попытался его ускорить (ввел бы дополнительные переменные, логику бы немного поменял – особенно в части проверки на то, является ли блок внешней ссылкой. Если надо – можно обсудить. Нет – так нет.

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

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



Комментарии

Есть 1 комментарий к “Преобразование единиц измерения блоков в файле”
  1. Кулик Алексей aka kpblc пишет:

    В случае, если надо обрабатывать только выделяемые блоки, но с учетом вложенных, код становится чуть посложнее.

    (vl-load-com)

    ;; Вызов: (lispru-change-block-units-by-select-with-subblocks)
    (defun lispru-change-block-units-by-select-with-subblocks
           (/ _dwgru-conv-pickset-to-list adoc selset blk_list name)

           ;|
    *    Преобразование единиц измерения блоков, включая вложенные блоки
    |;


      (defun fun_get-name (ent)
        ;; Получение имени блока
        (cond
          ((vlax-property-available-p ent 'effectivename)
           (vla-get-effectivename ent)
           )
          ((vlax-property-available-p ent 'name)
           (vla-get-name ent)
           )
          ) ;_ end of cond
        ) ;_ end of defun

      (defun _dwgru-conv-pickset-to-list (value / tab item)
    ;;; http://forum.dwg.ru/showpost.php?p=188342&postcount=21
        (repeat (setq tab  nil
                      item (sslength value)
                      ) ;_ end setq
          (setq tab (cons (ssname value (setq item (1- item))) tab))
          ) ;_ end repeat
        ) ;_ end defun

      ;; Поставим метку начала отмены. Ну так, на всякий случай
      (vla-startundomark
        (setq adoc (vla-get-activedocument (vlax-get-acad-object)))
        ) ;_ end of vla-startundomark
      ;; Получаем набор блоков, обрабатывая нажатие Esc
      (if (= (type (setq selset (vl-catch-all-apply
                                  (function
                                    (lambda ()
                                      (ssget '((0 . "INSERT")))
                                      ) ;_ end of lambda
                                    ) ;_ end of function
                                  ) ;_ end of vl-catch-all-apply
                         ) ;_ end of setq
                   ) ;_ end of type
             'pickset
             ) ;_ end of =
        (progn
          ;; Сформируем список имен блоков, исключая дубликаты
          ;; И не забываем про вложенные блоки
          (foreach ent
                   ;; Преобразовываем набор в список элементов, исключая внешние ссылки.
                   ((lambda (/ item lst)
                      (foreach item
                               (apply
                                 (function append)
                                 (mapcar
                                   (function
                                     (lambda (x / res)
                                       ;; применяем эту функцию
                                       (setq res (list x))
                                       (vlax-for item x
                                         (if
                                           (wcmatch
                                             (strcase
                                               (vla-get-objectname item)
                                               ) ;_ end of strcase
                                             "*BLOCK*"
                                             ) ;_ end of wcmatch
                                            (setq res (cons item res))
                                            ) ;_ end of if
                                         ) ;_ end of vlax-for
                                       res
                                       ) ;_ end of lambda
                                     ) ;_ end of function
                                   ;; begin : удаление внешних ссылок
                                   (vl-remove-if
                                     (function
                                       (lambda (x)
                                         (equal
                                           (vla-get-isxref
                                             (vla-get-name x)
                                             ) ;_ end of vla-get-isxref
                                           :vlax-true
                                           ) ;_ end of equal
                                         ) ;_ end of lambda
                                       ) ;_ end of function
                                     (mapcar
                                       (function
                                         (lambda (x)
                                           (vla-item
                                             (vla-get-blocks adoc)
                                             (fun_get-name
                                               (vlax-ename->vla-object x)
                                               ) ;_ end of fun_get-name
                                             ) ;_ end of vla-item
                                           ) ;_ end of lambda
                                         ) ;_ end of function
                                       (_dwgru-conv-pickset-to-list selset)
                                       ) ;_ end of mapcar
                                     ) ;_ end of vl-remove-if
                                   ;; end : удаление внешних ссылок
                                   ) ;_ end of mapcar
                                 ) ;_ end of apply
                        (if (not (member (fun_get-name item)) lst)
                          (setq lst (cons item lst))
                          ) ;_ end of if
                        ) ;_ end of foreach
                      lst
                      ) ;_ end of lambda
                    ) ;_ end of foreach
            (if (not (member (setq name (fun_get-name ent)) blk_list))
              (setq blk_list (cons name blk_list))
              ) ;_ end of if
            ) ;_ end of foreach
          ;; Запускаем новый цикл
          (foreach blk_def
                           ;; Из списка имен получаем список указателей на описания блоков
                           (mapcar
                             (function
                               (lambda (x)
                                 (vla-item (vla-get-blocks adoc) x)
                                 ) ;_ end of lambda
                               ) ;_ end of function
                             blk_list
                             ) ;_ end of mapcar
            (vl-catch-all-apply
              (function
                (lambda ()
                  (vla-put-units blk_def 0)
                  ) ;_ end of lambda
                ) ;_ end of function
              ) ;_ end of vl-catch-all-apply
            ) ;_ end of foreach
          ) ;_ end of progn
        ) ;_ end of if
      ;; Теперь метка конца отмены
      (vla-endundomark adoc)
      ;; Ну и "тихий" выход
      (princ)
      ) ;_ end of defun

    Код не комментирую (хотя по-хорошему надо бы, я там немного логику поменял). Надо будет – обращайтесь :)

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


Я не робот.