faqs.org.ru

 Главная > Программирование > Программирование графики >

AutoLISP FAQ

Секция 2 из 3 - Предыдущая - Следующая
Все секции - 1 - 2 - 3

[11] Мой LISP больше не загружается при запуске

LISP файлы могут быть загружены при запуске, используя LOAD в ACAD.LSP. Некоторые LISP-файлы, работающие с меню, чтобы работать, должны быть загружены из соответствующего <меню>. MNL-файла. <меню>.MNL- файл, загружаемый по умолчанию - ACAD.MNL

LISP функции вызываемые при запуске должны быть определены в функции S::STARTUP в файле ACAD.LSP. Эта функция вызывается при запуске после инициализации автоматически. Иначе вы получите ошибку: "Command list interruption (6.2)".

Если имя файла указано без расширения, функция LOAD добавляет .LSP по умолчанию. Если нет указания полного пути к файлу, используется обычный путь к библиотекам AutoCAD, то есть:
  1. ) Текущий каталог
  2. ) Каталог, содержащий файл текущего чертежа
  3. ) Каталоги, определенные в переменной среды AUTOCAD (устанавливается в пункте меню Preferences, пути к каталогу SUPPORT)
  4. ) Каталог acad.exe
Если ваша программа не загружается больше автоматически, проверьте ваш путь к библиотекам AutoCAD.

ACADLC (от ACOMP) и внутренние версии AutoCAD R12 не загружают автоматически файл ACAD.LSP. Следовательно Вы должны добавить (load "ACAD" -1) в ваш ACAD.MNL.

Пример ACAD.LSP:

;;;ACAD.LSP ;;; Fred the Beaver, 12/12/94 (load "init" -1) ;загружает некие инструментальные средства (defun S::STARTUP () (load "new-end" -1) ; переопределение команды END )

-1 параметр предохраняет LOAD от прерывания процесса запуска, если происходит любой отказ функции LOAD (возможные ошибки в AutoLISPе). Если отказ во время загрузки происходит, -1 возвращается, но вычисление кода не останавливается. -1 может быть в также в любом выражении.

Типовой пример, осуществления расширения S::STARTUP в вашей программе (с компилированным кодом Vital Lisp это не будет работать: это не должно компилироваться)

(defun MY::STARTUP () ;Ваш код автозапуска ;.. (princ) ) (setq S::STARTUP (if (and S::STARTUP (listp S::STARTUP)) ;если уже определен в ACAD.LSP ;то в общий список автозапуска (append S::STARTUP (cdr MY::STARTUP)) ;добавляется Ваш код, иначе MY:STARTUP)) ;выполняется только Ваш код

или другой пример:

(if (and S::STARTUP (listp S::STARTUP)) (setq S::STARTUP (append S::STARTUP (list func '(princ)))) (setq S::STARTUP (list nil func '(princ))))

См. также [12] Как сделать чтобы мои программы загружались автоматически?


[12] Как сделать чтобы мои программы загружались автоматически?

[обновления для R14]

Как сделать чтобы мои программы загружались автоматически?
Вы можете или загружать ваши программы при запуске (см. [11] Мой LISP больше не загружается при запуске) что создает потребность в большем количестве времени и памяти во время запуска, или Вы может определять их через механизм автозагрузки.
ARX (версии R14) программы используют новую схему автозагрузки, называемую загрузкой по потребности, которая использует несколько регистрируемых установок (в системном реестре) и не использует ACADR14.LSP.

В конце файла ACADR12.LSP для R12, или для R13 - ACADR13.LSP, можно увидеть как AutoCAD производит автозагрузку своих программ.

;;;===== AutoLoad LISP Applications ===== ... (autoload "dline" '("dline" "dl")) ...

Эти строки определяют список команд DLINE и DL из файла DLINE.LSP, которые будут загружены при первом обращении к ним. Ранее функция определялась просто как:

(defun C:DL () (load "DLINE")(C:DL))

Фактически это определение было более сложным из-за ошибки обработки

После первого обращения функция перезаписывается поверх предыдущего определения.

Преимущества автозагрузки:
Запуск AutoCAD происходит быстрее, т.к. не надо загружать все lisp-файлы. Вам нужно сделать лишь объявить как показано выше. Что осуществляется с помощью функции (autoload).

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

Недостатки:
При ошибках в Вашей программе Вы попадаете в замкнутый цикл, который можно остановить лишь после переполнения стека или нажав Ctrl-C
Примечания: используя acomp-компилированный код, остановка с помощью Ctrl-C невозможно, поэтому где-нибудь вставьте обращение на некомпилируемый (princ).

В autoload Вы должны определить и сохранять все имена команд из вашей программы. Изменения имени lisp-файла или имени команды вызовет вышеупомянутую ошибку.

Где помещать Ваши определения (autoload)?
Не в ACADR13.LSP. Мы рекомендуем помещать свои определения в отдельный файл, не в ACAD.LSP, т.к. этот файл будет часто изменяется разными приложениями а файл ACAD.LSP должен оставаться небольшим.

То есть, прместите свои определения в AUTOLOAD.LSP или INIT.LSP (их создаете Вы сами), и сделайте ссылку на него из ACAD.LSP См. [11] Мой LISP больше не загружается при запуске

Это должно быть упомянуто: пользователи *неt* должны изменять ACADR13.LSP (или ACADR12.LSP, хотя это не было 'официально' до r13). С этих версий - ACAD.LSP не перезаписывается во время модернизации версии, что гарантирует сохранность. Кроме того (как получилось с исправлением (patch) R13c4a), если файл ACADR13.LSP был изменен, то процесс установки исправления не будет осуществлен.


[13] Как передать разное количество аргументов одной и той же функции LISP?

Напрямую, AutoLISP не может это сделать.

Вы можете передать необходимые аргументы списком, как например:

;;; печатает любое количество аргументов (любого типа) передаваемых функции (defun my-princ (x) ;; упрощенная версия, полную версию см. в SDK2: PRINTF.LLB (if (listp x) (mapcar 'princ x) (princ x)))

Или Вы должны определить функцию с помощью ADS или ARX и экспортировать ее в AutoLISP. Then you are free to write:

(ads-print "Hello " "World " 1 2 3) или даже (ads-printf "Hello %s %i %i" "World" 2 3)

Посмотрите ADS примеры от Reini Urban's и Vladimir Nesterovsky's - http://xarch.tu-graz.ac.at/autocad/ads/ - для бесплатного распространения.

Официально было объявлено AutoDesk regarding &optional о включении как расширение языка AutoLISP, но не включены в состав версии R14.


[14] Как мне избежать переполнения стека?

В AutoLISP размер стека жестко фиксирован. Он не может быть расширен, но этот размер достаточен для большинства целей.
Большинство ошибок, связанных с переполнением стека, происходят из-за ошибок в ваших программах. Для предовращения сбоев системы избегайте использование бесконечных циклов, и не используйте рекурсивные функции при обработки больших списков. В стандартном AutoLISPе при использовании рекурсивных функций Вы ограничены ~200-ми элементами.

Вы не сможете уменьшать используемый размер стека используя меньше локальных параметров в вашей рекурсивной функции! Старайтесь не использовать APPLY, EVAL или MAPCAR, для вызва вашей функции рекурсивно, т.к. они поедают стек. Using tail recursion doesn't help either.

Вы будете должны преобразовать вашу рекурсивную функцию в итерационную. (Имеется математическая теорема, которая говорит, что каждая рекурсивная функция может быть преобразована в итерационную, а обратно-рекурсивную даже автоматически.) Итерационные версии могут использовать стеко-подобные функции как (push) и (pop), но эти версии хранят стек в куче(heap) (пространстве узлов (node) Autolisp), величина которого ограничена только размером Вашей виртуальной памяти.

Вы можете протестировать переполнение стека этой простой функцией:

;;; формирование списка из n чисел (zero based) (defun intlst (l n) (cond ((zerop n) l) (T (intlst (cons (1- n) l) (1- n))))) И попытайтесь: (setq n 100)(while (intlst nil (setq n (+ 10 n)))(print n)) В AutoLISP версии R12/DOS вы достигаете пределов стека с результатом (intlst nil 138), в A13/Win - (intlst nil 240), в acomp bi4's - (intlst nil 1240), в Vital LISP IDE - (intlst nil 984). При использовании Vital LISP или Visual LISP RTS размер стека неограничен.
При использовании R10c10, первой версии лисп для расширенного dos, Вы могли расширить размер стека используя системную переменную LISPSTACK. А при работе с Acomp для R10 имел переменную COMPSTACK. С современными версиями это уже невозможно.

Преобразование в итерационную форму приводит к ожидаемым результатам:

(defun intlst (n / l) (repeat n (setq l (cons (setq n (1- n)) l)))) ;это выглядит ужасно, но работает Единственная возможность физически увеличить размер стека, это ипользовать vlisp, ViLL или acomp интерпретатор ACADLC. См. [5].


[15] (command "ROTATE3D") не работает! Почему?

Некоторые команды не являются внутренними командами AutoCAD, а являются простыми AutoLISP-программами, начинающиеся с C:, включая те что кодированы в ADS.

Список всех этих команд можно найти в файле ACADR13.LSP в разделе AUTOLOAD. (см. также"[12]")
Все подобные команды должны вызываться, следующим образом (C:ROTATE3D) вместо (command "ROTATE3D").

Кроме вышесказанного, ADS функции способны получать дополнителные параметры. Для более подробной информации см. руководство пользователя.
Т.е. (c:rotate3d ss p1 p2 angle) также допустим, как и (rotate3d ...)


[16] LISP-программы, работающие с несколькими чертежами.

"У меня проблема в написании lisp программы, которая должна открывать чертеж и продолжать выполняться. Но, как только открывается новый чертеж, lisp-файл удаляется из памяти AutoCAD, и необходимо заново загружать его."
При загрузке чертежа LISP-память очищается. Но, существует несколько способов заставить работать lisp-программы с несколькими чертежами:
  1. Используя скрипт. MYSCRIPT.SCR. (load "mylisp") _QSAVE _OPEN !nextdwg (load "mylisp") _QSAVE _OPEN !nextdwg ... (setq *VILL-NEW-FULL-INIT* nil); хранит символы между сеансами
  2. Внешние программы других разработчиков, такие как RunLisp или DDSCRIPT automate step 1.
  3. Версия R14 имеет новую возможность, называемую 'Persistent LISP'.
    Устанавливаемую в Preferences-Compatibility-Persistent Lisp
  4. Vital LISP имеет встроенную переменную действующую как Persistent Lisp:
    (setq *VILL-NEW-FULL-INIT* nil) ;keep symbols between sessions
  5. аналогично у Visual LISP: (setq *VLISP-NEW-FULL-INIT* nil)


[17] Как экспортировать функции из Visual Lisp в AutoLISP/AutoCAD?

C: функции автоматичекси экспортируются в AutoLISP. Функции vlisp/vill-lisp должны экспортироватся либо с помощью (vl-acad-defun 'myx-funcname), либо используя специальный компилятор pragma, либо должны быть определены в файлах LSP или GLD (глобальные определения (declarations)). Для таких функций лучше добавлять специальный префикс. .GLD: (AUTOEXPORT-to-ACAD-PREFIX ;| префиксы к названию функций автоматически экспортируемой в AutoCAD: (strings) |; "myx-*" ) или, один за другим .LSP: (pragma '((export-to-acad myx-func1 myx-func2))) Примечания: Используя vlisp или vill, при получении и возврате аргументов функций являющимися списками атомов или списками точечных пар могут произойти известные ошибки. См. [7].

Функции экспортируемые внешними программами и используемые вашей, должны быть определены с помощью XDF.

Символы (переменные) значения которых изменяются в Visual Lisp, и используются AutoLISP-ом или AutoCAD-ом (например, меню), сначала должны быть отмечены для компилятора (который должен быть внешним): (pragma '((not-localize myx:symbol)))
а их значения экспортируются:
(vlisp-export-symbol 'myx:symbol)
всякий раз, когда значение переменной изменяется в Visual Lisp-е а управление возвращается AutoCADу, чтобы получить последнее ее значение в AutoLISPе или в AutoCADе: !myx:symbol

Возможны коренные изменения данной главы при выходе следующей версии AutoCAD. См. http://www.autodesk.com/support/techdocs/td17/td175363.htm


Часть 2: примеры, код.


[20] Общие сервисные функции

Больше общих AutoLISP функций можно найти в Стандартной AutoLISP Библиотеки, см. http://xarch.tu-graz.ac.at/autocad/stdlib/ Еще немного можно найти на различных AutoLISP сайтах [1] и в SDK от Autodesk [1.2]

Далее, отвечая на вопросы сети, в небольших программках включены несколько, очень полезных, сервисных функций.

Вы, можете быть уверены что эти функции общеизвестны, как например знаменитые, dxf функция, которая определена как (defun dxf (grp ele) (cdr (assoc grp ele))) и особый аналог (getval) работающий с ename и entget списками.

[20.1] Работа со списками

См. http://xarch.tu-graz.ac.at/autocad/stdlib/STDLIST.LSP

Полезные утилиты для работы со списками:

;;; CONSP - не пустой список (a not empty list) (defun consp (x) (and x (listp x))) ;;; POSITION - возвращает индекс первого найденного значения, ;;; начиная с 0, или nil если не найден ;;; (position 'x '(a b c)) -> nil, (position 'b '(a b c d)) -> 1 (defun position (x lst / ret) (if (not (zerop (setq ret (length (member x lst))))) (- (length lst) ret))) ;;; REMOVE - Удаляет элемент из списка (допустимы двойные элементы) ;;; (remove 0 '(0 1 2 3 0)) -> (1 2 3) (defun remove (ele lst) ; (c) by Serge Volkov (apply 'append (subst nil (list ele) (mapcar 'list lst)))) ;;; REMOVE-IF - Удаление с условием, из плоского списка ;;; fun требует исключительно 1 аргумент ;;; (remove-if 'zerop '(0 1 2 3 0)) -> (1 2 3) ;;; (remove-if 'numberp '(0 (0 1) "")) -> ((0 1) "") (defun remove-if (fun from) (cond ((atom from) from) ;nil или символ (return that) ((apply fun (list (car from))) (remove-if fun (cdr from))) (t (cons (car from) (remove-if fun (cdr from)))) ) ) | ;;; REMOVE-IF-NOT - keeps all elements to which the predicate applies | ;;; say: "keep if", it need not be defined recursively, also like this. | ;;; [fixed, thanks to Serge Pashkov, in FAQ-CODE.LSP it was okay] (defun remove-if-not (pred lst) ; by Vladimir Nesterowsky (apply 'append (mapcar '(lambda (e) (if (apply pred (list e)) (list e))) lst))) ;;; ADJOIN - добавляет элемент ele в список если его там нет ;;; хитрость: принимает quoted списки ;;; (setq l '(1 2 3) (adjoin 0 'l) ;;; -> !l (0 1 2 3) (defun adjoin (ele lst / tmp) (if (= (type lst) 'SYM) (setq tmp lst lst (eval tmp))) (setq lst (cond ((member ele lst) lst) (t (cons ele lst)))) (if tmp (set tmp lst) lst) ) ;;; ROT1 - перемещает первый элемент списка в его конец, упрощенная версия ;;; (rotate by one) (defun rot1 (lst) (append (cdr lst) (list (car lst)))) ;;; BUTLAST - обрезает список удаляя последний элемент (defun butlast (lst) (reverse (cdr (reverse lst))))

[20.2] Обработка строк

См. http://xarch.tu-graz.ac.at/autocad/stdlib/STDSTR.LSP

Здесь приводятся несколько полезных функций для обработки строк:

Некоторые можно найти на http://xarch.tu-graz.ac.at/autocad/code/vnestr/strtok.lsp или в Вашем AI_UTILS.LSP. Он Вам нужен, особенно для DCL функций.

[20.3] символ -> строку

Функция обратная (read) -(symbol-name). Не спрашивайте почему, но то что приводиться ниже является лишь общим решением: ;;; SYMBOL-NAME возвращает имя переменной как строку ;;; преобразует любое правильное лисп выражение в строку ;;; (symbol-name a) -> "a", (symbol-name '(0 1 2 a)) -> "(0 1 2 A)" (defun symbol-name (sym / f str tmp) (setq tmp "$sym.tmp") ;имя файла temp., должно быть удалено (setq f (open tmp "w"))(princ sym f) (close f) (setq f (open tmp "r") str (read-line f) f (close f)) str ) Для отдельных символов существует отличный трюк рассказанный Christoph Candido, см. http://xarch.tu-graz.ac.at/autocad/news/symbol-string.txt
Vill/vlisp внедрили, быстрый vl-symbol-name. См. http://xarch.tu-graz.ac.at/autocad/stdlib/STDINIT.LSP

[20.4] Доступ к примитивам AutoCAD

См. http://xarch.tu-graz.ac.at/autocad/stdlib/STDENT.LSP

;;; возвращает первое значение группы примитива. ;;; подобно знаменитой функции (dxf), но принимающая любые ;;; представления примитива (ename, entget list, entsel list) ;;; ПРИМЕЧАНИЕ: Не годиться для получения ;;; группы 10 из LWPOLYLINE ! (defun GETVAL (grp ele) ;"dxf значение" любого примитива - ele... (cond ((= (type ele) 'ENAME) ;ENAME (cdr (assoc grp (entget ele)))) ((not ele) nil) ;пустое значение ((not (listp ele)) nil) ;не действительный ele ((= (type (car ele)) 'ENAME) ;entsel-список (cdr (assoc grp (entget (car ele))))) (T (cdr (assoc grp ele))))) ;entget-список ;;; Пример: (gettyp pline) => "POLYLINE" (defun GETTYP (ele) ;возвращает тип (getval 0 ele)) ;;; проверяет ENAME ;;; конвертирует примитив в тип ENAME (чтобы код был короче) (defun ENTITY (ele) ;конвертирует в имя примитива (cond ;работает со следующими типами: ((= (type ele) 'ENAME) ele) ; ENAME ((not (listp ele)) nil) ; ошибка: не список ((= (type (car ele)) 'ENAME) (car ele)) ; entsel-список ((cdr (assoc -1 ele))) ; entget-список или nil ) ) ;теперь стало проще: (defun getval (grp ele) (cdr (assoc grp (entget (entity ele))))) ;;; Пример: (istypep ele "TEXT") ;;; является ли элемент - "SOLID"? (defun istypep (ele typ) ;проверяет тип (= (gettyp ele) typ)) ;;; Пример: (istypep ele '("TEXT" "ATTDEF")) ;;; является ли элемент - "TEXT" или "ATTDEF"? (defun ISTYPEP (ele typ) ;улучшено, чтобы принимал списки (cond ((listp typ) (member (gettyp ele) typ)) ;исправлено ((stringp typ) (= (gettyp ele) typ)) ;преобразование typ в верхний (T nil))) ; регистр, использовать wcmatch ; было бы хорошо, но медленно ;;; Пример: (getpt (entsel)) => ( 0.1 10.0 24) (defun GETPT (ele) ;возвращает точку вставки любого элемена (getval 10 ele)) ;группа 10 ;;; Пример: (getflag pline) => 1 если закрыто (closed) (defun GETFLAG (ele) (getval 70 ele)) ;то же с флогом примитива ;;; Значение бита val в флажке установленного элемента? ;;; Пример: (flagsetp 1 pline) => T если закрыто (closed) ;;; Пример: (flagsetp 16 vertex) => T если контрольная точка сплайна (defun FLAGSETP (val ele) (bitsetp val (getflag ele))) ;;; Пример: (bitsetp 4 12) => T ;Значение бита 4 (=2.Bit) установлено в 12 (=4+8) (defun BITSETP (val flag) (= (logand val flag) val)) ;;; преобразует выборку в список. медленный, но легкий алгоритм. ;;; Примечания: рекомендуется использовать с ai_ssget, ;;; т.к. некоторые примитивы могут находиться ;;; в заблокированных (locked) слоях ;;; Пример: (sslist (ai_ssget (ssget))) => список выбранных ;;; не заблокированных примитивов ;;; или (mapcar 'entupd (sslist (ssget "X" '((8 . "TEMP"))))) ;;; - регенерирует все примитивы слоя TEMP (defun SSLIST (ss / n lst) (if (= 'PICKSET (type ss)) (repeat (setq n (sslength ss)) (setq n (1- n) lst (cons (ssname ss n) lst))))) ;;; выполняет функцию применяя ее ко всем примитивам ent ;;; ent из выборки ss, в обратном порядке ;;; Быстрая, но алгоритм не прост для понимания. см. [22.2] ;;; Пример: (ssapply 'entupd (ssget)) ; регенерирует только некоторые примитивы (defun SSAPPLY (fun ss / n) (if (= 'PICKSET (type ss)) (repeat (setq n (sslength ss)) (apply fun (list (ssname ss (setq n (1- n))))))))


[21] Примеры лисп программ:

[21.1] Изменения параметров текста и полилиний, утилиты для работы со слоями и установка даты

Для изменений атрибутов текста, используйте CHTEXT.LSP из директория SAMPLE.

Для изменений атрибутов полилиний, блокировки слоев по выбранному примитиву, и для решения прочих подобных задач ищите беслатные утилиты на сайтах AutoLISP библиотек. Также, см. [1], и немного на [22], [23], и [24].

Для автоматической распечатки даты на чертеж, проверьте поддерживает ли Ваш графопостроитель (plotter) HPGL/2. Если ДА, то используя HPGL/2 драйвер измените конфигурацию datestamp в HPCONFIG.

DATESTAMP.LSP: Сам изменяет атрибут заголовка чертежа, как в [22.2]. Профессиональная программа изменения даты см. на: http://ourworld.compuserve.com/homepages/tonyt/plotstmp.htm

[21.2] Диалог вывода на печать из лиспа. Используя DDE или ActiveX

Вызов диалога вывода на печать (PLOT dialogbox) возможен только на Windows платформе, например с помощью LISPPLOT от Mike Dickason http://www.cadalog.com/cadalog/files/lispd-l/lspplw.zip , или ftp://ftp.mcwi.com/pub/mcwi/lisp/winplt.lsp
Другое решение, заключается в том чтобы, написать скрипт и поместить его в конец лиспа, но при этом не появляется окно диалога.

Xiang Zhu: Под Windows Вы можете использовать "ddelisp", подобно:

;;; [исправлено для всех версий] (defun DDECMD (str / tmp acadver ddestr) (if (not (boundp 'initiate)) (cond ((= 14 (setq acadver (atoi (getvar "ACADVER")))) (setq ddestr "AutoCAD.R14.DDE") (arxload "ddelisp")) ((= 13 acadver) (setq ddestr "autocad.r13.dde") (xload "ddelisp")) ((= 12 acadver) (setq ddestr "autocad.dde") (xload "ddelisp")) (T (princ "DDE not supported")(exit)))) (if (not (zerop (setq tmp (initiate ddestr "system")))) (progn (execute tmp (strcat "[" str "]")) (terminate tmp) str))) Для версии R12, используя "autocad.dde" как имя сервера, Внутри своего лисп-приложения вы можете использовать (ddecmd "_plot "). Функция DDECMD возвращает значение nil если что-то не правильно, или переданную Вами строку, если ошибок нет. Но, строка будет идентичной той, что Вы можете напечатать в командной строке, т.е. в коммандной строке необходимо ввести пробел (Space) либо ввод (Enter), а к строке нужно добавить "^13".

Кроме того, вышеописаная функция очень полезна в следующей ситуации: Если в лиспе, Вам нужно вызвать прозрачную команду автокада, как например LAYER (слой), то в порядке вещей будет использовать (command "_layer"). После этого, сам лисп перестает быть прозрачным, но используя вышеупомянутую функцию удается решить эту проблему.

Запомните! Acad работает с командами DDE только через командную строку, т.е. окна открываться не будут.

Работая с vlisp/ViLL Вам доступны ActiveX методы:

;;; синтаксис vlisp: (setq vlax:ActiveDocument (vla-get-ActiveDocument (vlax-get-Acad-Object))) (setq plt (vla-get-plot vlax:ActiveDocument)) ;=> печатуемый объект (vla-PlotWindow plt pt1 pt2) ; определяет окно (pts in WCS) (vla-PlotPreview plt 1) ; 0 для фрагмента, 1 - целиком (vla-PlotToDevice plt "Default System Printer") ; если он существует В версии R14 вызов диалога печати проще чем в DDE:
(initdia)(command "_PLOT")

[21.3] (entmod) и (entmake) Слоев, не используя (command "_LAYER"...)

Работа со слоем используя ENTMOD
Я, задался целью, в лисп программе изменить свойства слоя, при этом не применяя командных функций (command function).

Под r13, использовал следующий лисп:

(setq tbl_lst (entget (tblobjname "LAYER" "ANY_LAYER")) clr_grp (assoc 62 tbl_lst) ) (entmod (subst (cons 62 (- (cdr clr_grp))) clr_grp tbl_lst)) Так Вы можете блокировать/разблокировать любой слой, "ANY_LAYER", даже если это текущий слой (current layer).

AutoCAD не узнает что ввод в таблицу был изменен, пока Вы не нажмете Layer Control на панели инструментов или на чем-нибудь подобном. Кроме того, Вы можете использовать 'DDLMODES чтобы посмотреть свойства Вкл./Выкл. любого, "ANY_LAYER", измененного слоя.
Если тем же способом заморозить слой, то Вы будете видеть находящиеся там примитивы, хотя и не сможете их выбрать. Это продолжится до тех пор, пока Вы не активизируете какую-либо команду для работы со слоями, и только тогда автокад удалит их с экрана.

Работа со слоем используя ENTMAKE
Вам нужно получить шаблон используя entget, при этом используя, как аргумент, имя из таблицы объектов. Это имя можно получить с помощью функции TBLOBJNAME: (entget (tblobjname "LAYER" "ANY_LAYER_NAME")) ;;; Эта программа создает слой с заданным вами именем: (defun c:mlay () ; от Reinaldo Togores <rtogores@mundivia.es> (setq laynam (getstring "\nНазвание слоя: ")) (entmake (list '(0 . "LAYER") '(5 . "28") '(100 . "AcDbSymbolTableRecord") '(100 . "AcDbLayerTableRecord") (cons 2 laynam) '(70 . 64) '(62 . 7) '(6 . "CONTINUOUS") ) ) )
[21.4] Как выбрать несколько файлов в лиспе? (как в FILES - Unlock)

На http://xarch.tu-graz.ac.at/autocad/progs/MGETFILD.ZIP, находится программа использующая DCL для выбора нескольких файлов.
Также, Вам нужна DOSLIB от McNeel для доступа к специальным функциям DOS для работы с каталогами(directory). http://www.mcneel.com/mcneel/doslib.html

[21.5] Замена нескольких блоков

Ищите в лисп-коллекциях:
Cadalyst: http://www.cadonline.com/search.phtml
=> 97code.htm , вопрос об имени пользователя решается бесплатно и автоматически.
xarch: http://xarch.tu-graz.ac.at/autocad/code и ищи запрашивая "BLOCK;REPLACE"
=> http://xarch.tu-graz.ac.at/autocad/code/cadalyst/94-02/replace.lsp
а также см. Cadalog:
http://www.cadalog.com/find.htm Ключевые слова "Block Replace"
=> http://www.cadalog.com/cadalog/files/lispr-z/replace.zip (это наилучший сайт)

[21.6] (vports), VIEWPORT примитив, преобразование пикселей
Примитив VIEWPORT:
Ответ на вопрос, "Использовал (entget), чтобы из VIEWPORT получить нижний-левый угол (DXF группа 10) и верхний-правый угол (DXF группа 11). Но, получаемые значения предсавлены в координатах "paper" пространства. Меня интересует какая часть, "настоящего" чертежа (координаты "model" пространства), показывается в текущем видовом окне.", смотри на http://xarch.tu-graz.ac.at/autocad/news/vports.lsp

[новое]: Несколько трюков можно посмотреть на http://www.ez-sys.net/~coopfra/lisp.htm#view.

Как изменить видовой экран используя AutoLISP?
Используй (setvar "CVPORT" vport-id) см. http://xarch.tu-graz.ac.at/autocad/news/change_vports.html

Ниже, приведены функции позволяющие преобразовывать пиксель<->единицы чертежа:

;;; Преобразование пикселей в единицы чертежа (defun PIX2UNITS (pix) (* pix (/ (getvar "VIEWSIZE") (cadr (getvar "SCREENSIZE"))))) ;;; Преобразование единицы чертежа в пикселей (defun UNITS2PIX (units) (* units (/ (cadr (getvar "SCREENSIZE"))(getvar "VIEWSIZE")))) [новое] Обратите внимание на ошибки "Pixel Off by One" автокада, описаные Vibrant, см.: http://xarch.tu-graz.ac.at/autocad/news/pixel-off-by-one-error.txt

[21.7] Выбор всех видимых объектов: координаты масштабирования
Не делайте этого используя (ssget). Получиться выборка из объектов видимых только в текущем видовом экране, т.к. все интерфейсные функции (entsel,ssget,osnap) работают с пикселями, и лишь (ssget "X") выберет все видимые объекты, включая те что находятся за пределами видового экрана. ;;; возвращает список координат углов текущего видового экрана ;;; в WCS системе координат (defun zoompts ( / ctr h screen ratio size size_2) (setq ctr (xy-of (getvar "VIEWCTR")) ;3D -> 2D h (getvar "VIEWSIZE") ;real screen (getvar "SCREENSIZE") ;2D: Pixel x,y ratio (/ (float (car screen)) ;aspect ratio (cadr screen)) size (list (* h ratio) h) ; screensize in coords size_2 (mapcar '/ size '(2.0 2.0))) (list (mapcar '- ctr size_2) (mapcar '+ ctr size_2))) (defun xy-of (pt) (list (car pt)(cadr pt))) ;assure 2D coords Примечания: Точки возвращенные с предприятия - в WCS но это - OK поскольку "CP" "WP" и "P" выборы ssget ожидают точки WCS ("W" и "C" требует, что точки UCS - почему различие, которое Я не знаю) Точки возвращаемые примитивом представлены в WCS системе координат, и это хорошо, т.к. опции "CP", "WP" и "P" требуют точки в WCS (опции "W" и "C" требуют точки в UCS координатах - разницу не понимаю). ;;; один из спопобов определения функции (defun ssall-visible (/ l) (ssget "C" (car (setq l (maptrans0-1 (zoompts)))) (cadr l))) ;;; еще один (defun ssall-visible-1 () ;объединяет "C" и (p1 p2) в один список (apply 'ssget (append '("C") (maptrans0-1 (zoompts))))) ;;; преобразует несколько точек из WCS в UCS, ;;; легко с одним аргументом [исправлен] (defun maptrans0-1 (pts)(mapcar '(lambda (pt)(trans pt 0 1)) pts))
[21.8] Как записать XYZ значения, выбранных объектов, в файл?

;;; CDF - строки ограниченные запятыми (defun cdf-point (pt) (strcat (car pt) ", " (cadr pt) ", " (caddr pt))) ;;; SDF - ограниченные прбелами, ;;; легко обратно считывается AutoCAD (defun sdf-point (pt) (strcat (car pt) " " (cadr pt) " " (caddr pt))) ;;; Преобразует SDF фомат обратно в точку (defun str->point (s) (eval (read (strcat "(" s ")")))) ;;; Записывает в XYZ файл все выбранные ;;; объекты (SDF см. ниже) (defun C:XYZ (/ ss fname f) (if (and (setq ss (ssget)) (setq fname (getfiled "Запись XYZ в файл" (strcat (getvar "DWGNAME") ".XYZ") "XYZ" 7)) (setq f (open fname "w"))) (foreach ele (sslist ss) ; -> [20.4] (foreach pt (getpts ele) ; -> [23.1] (write-line (cdf-point pt) f) ) ) ) (if f (close f)) ) ;;; => <fname>.xyz ;;; 0.45, 12.3, -34.0 Для преобразования в ASC файл (SDF-формат) нужно заменить все XYZ на ASC, и cdf-точку(cdf-point) на sdf-точку(sdf-point).

Другой способ: создавай PLINES используя ascii x,y файл, лучше всего преобразовать файл в некий скрипт похожий на:

PLINE 300.2,10 350.4,10.4


[22] Атрибуты блоков

[22.1] Как получать доступ к атрибутам блоков?
Проверьте все примитивы после INSERT пока не будет обнаружен нужный Вам атрибут. Также см. http://www.autodesk.com/support/techdocs/td30/td300518.htm -> "Retrieving Complex Entities and Sub-entities with AutoLISP" ;;; возвращает список entget атрибута s (STRING) в элементе ele (ENAME) ;;; или nil - если не находит его (defun ATTELE (ele attname / rslt) (if (and (istypep ele "INSERT") (= (getval 66 ele) 1)) (progn (setq ele (entnext (entity ele))) (while (and ele (istypep ele "ATTRIB")) (if (= (strcase (getval 2 ele)) (strcase attname)) (setq rslt (entget ele) ele nil) ;прерывает цикл (setq ele (entnext ele)) ) ) ) ) rslt ) ;;Пример: (attele (entsel) "TEST") ; возвращает список entget ; атрибута "TEST" если он есть в блоке BTW: Более сложные функции, GET и EDLGETENT, для получения группы кодов DXF примитивов представлены Vladimir Nesterowsky. ;;;Пример вызова: ;;; возращает список из значений групп 2, 1 и -1 (defun get-attribs-look-up (block-ename) (get '(2 1 -1) (cdr (edlgetent block-ename)))) (defun all-verticies-and-bulges (pline-ename) (get '(10 42) (cdr (edlgetent pline-ename)))) см. http://members.tripod.com/~vnestr/

[22.2] Как изменить (MODIFY) атрибуты блока? DATESTAMP
Используйте entmod, и список entget будет извлечен из (attele). ;;; изменяет значение атрибута на новое, группа 1 (defun ATTCHG (ele attname new / b) (if (setq b (attele ele attname)) (entmod (subst (cons 1 new) (getval 1 b) b)))) ;;; Изменяет все DATESTAMP атрибуты ;;; во всех вставках блока PLOT* (defun C:DATESTAMP () (ssapply ;исправл. 13.Сент 97 ;args the other way 'round '(lambda (ele) (attchg ele "DATESTAMP" (today)) (entupd ele) ) (ssget "X" '((0 . "INSERT")(2 . "PLOT*"))) )) ;;;возвращает текущую дату, ;;;может быть DIESEL или преобразованная строка (defun TODAY (/ s) (setq s (rtos (getvar "CDATE") 2)) ;получает дату по Юлианскому календарю (strcat (substr s 5 2) "-" (substr s 7 2)"-"(substr s 3 2)))
[22.3] Как подкорректировать (UPDATE) атрибуты блока?
В директории ..\SUPPORT\ должен быть файл ATTREDEF.LSP, служащий чтобы корректировать своиства атрибутов вставленных блоков (положение, слой,...).

К сложным примитивам Вы должны применить entupd, чтобы произошло обновление экрана (она принуждает к выполнению REGEN). ;;; Пример: (setq s (getstring "Изменить атрибут на: ")) (attchg (attele (setq b (entsel "из блока: ")) s))) (entupd (car b)) ; указывается блок, а не атрибут ;;; дополнительные функции позволяющие получить ;;; основные примитивы из атрибута или блока (defun MAIN-ENTITY (ele) (setq b (entity b)) ;force ENAME (while (istypep b '("ATTRIB" "ATTDEF" "VERTEX")) (setq b (entnext b))) ; повторяется пока ; не закончаться примитивы (if (istypep b '("SEQEND" "ENDBLK")) (getval -2 b) ;сложный примитив -> заголовок b ;обычный примитив ) )

[22.4] Как создать блок со сложными примитивами в AutoLISP с использованим ENTMAKE>
Это пример многократного использования (entmake) для создания заголовка блока (block header), примитивы (entities), закрыть блок (closes the block) и наконец для его вставки (INSERT) в чертеж.

см. http://www.autodesk.com/support/techdocs/td30/td301515.htm Осторожнее с анонимными блоками которые при (setq bn (entmake '((0 . "ENDBLK")))) возвращают имя блока (entmake (list '(0 . "INSERT")'(70 . 1)(cons 2 bn) ...))

Секция 2 из 3 - Предыдущая - Следующая

Вернуться в раздел "Программирование графики" - Обсудить эту статью на Форуме
Главная - Поиск по сайту - О проекте - Форум - Обратная связь

© faqs.org.ru