Преобразование единиц измерения блоков в файле
Известно, что при создании блока (ручного создания) можно указывать единицы, в которых этот блок будет вставляться: миллиметры, метры, дюймы и т.д. Это удобно, если гарантируется, что вся работа всегда выполняется на основе единственного шаблона с раз и навсегда настроенными единицами. Но бывает такое не всегда (да и за смежниками, бывает, приходится "доделывать").
Оптимальным решением, как ни странно, будут "безразмерные" блоки. То есть те, у которых единицы - "Unitless" (в русской версии перевода не помню). С новыми блоками все понятно - достаточно контролировать это значение и стараться не допускать ошибок. А что делать со старыми, уже вставленными? Да очень просто - заменить!
Менять можно вручную, переопределяя блоки (к примеру). И этот подход более чем достаточен, если блоков 1-2. Ну, всяко не больше 10 (и то лично я уже на втором озверею). Программное решение намного более интересно.
Вариантов программы, конечно, может быть сколько угодно. Рассмотрим 2: либо обрабатывать все блоки в файле (независимо ни от чего), либо обрабатывать только указанные блоки. В набор обрабатываемых блоков может попадать несколько блоков. ТЗ составлено, приступаем к реализации.
Наиболее удобным будет применение ActiveX - код получится достаточно простым, читабельным и понятным.
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 | (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)) "<code>*D*,</code>*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 |
При обработке выбранных блоков код немного усложняется:
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 | (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 |
У этого кода есть один, но очень серьезный недостаток: он не обрабатывает (по крайней мере на данный момент) вложенные блоки.
Конечно, будь этот код "для работы", я бы исправил эту ошибку и попытался его ускорить (ввел бы дополнительные переменные, логику бы немного поменял - особенно в части проверки на то, является ли блок внешней ссылкой. Если надо - можно обсудить. Нет - так нет.
---
Добавлено: можно за компанию потом еще и выполнить регенерацию чертежа. По вкусу, как говорится
В случае, если надо обрабатывать только выделяемые блоки, но с учетом вложенных, код становится чуть посложнее.
[cc lang="cadlisp"](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[/cc]
Код не комментирую (хотя по-хорошему надо бы, я там немного логику поменял). Надо будет - обращайтесь
Спасибо. Код пригодился для нормализации блоков геодезических условных знаков.