О создании стилей в dwg
Как известно, в файле dwg есть такое понятие, как стили (текстовый; размерный; мультилинии; начиная с версии 2005 вводится понятие стиля таблиц). Об их создании сейчас и поговорим.
Пост получился очень большой, поэтому здесь пока ограничусь только текстовым стилем. Про размерный стиль и стиль таблиц – позже.
Если честно, то с аннотативными стилями лично я практически не работал, и поэтому не знаю методов их создания (точнее, я подозреваю, в какую сторону надо “копать”; но подозрения не есть уверенность) и из рассмотрения пока исключаю.
Сначала несколько основополагающих предположений.
- Мы не занимаемся редактированием текстового стиля Standard, а создаем свой собственный. Это позволит избежать некоторых не всегда очевидных и предсказуемых проблем (ведь наши файлы могут попасть к субподрядчикам, у которых настройки стиля Standard совершенно иные. В результате файл может стать просто нечитаемым. Имя нашего стиля – уникально (например, “lispru-textstyle”)
- В наших размерных стилях используется только наш собственный текстовый стиль
- В стилях таблиц допускается использование только наших текстовых стилей.
- Шрифт, учитывая “любовь” AutoCAD’a к ttf, будем использовать shx.
Будем считать приведенные постулаты непререкаемыми.
Примечание: Пока ведем разработку только для текущего документа, хотя сделать “прицел” на обработку неактивного документа в принципе не помешает.
Как и с обычными примитивами, стили можно создавать либо через ActiveX, либо через entmake-функции. Но если первые позволят работать с любым документом (не только активным), то вторые – только с текущим, без вариантов. И это в свое время сыграет достаточно злую шутку. Но это потом, а пока (воспользовавшись тем, что указано в перегрузке lisp) будем разрабатывать функцию с минимальным количеством обязательных параметров: документ и имя стиля. Остальное – в список.
По ходу дела будем использовать самый устойчивый (но и самый медленный) способ создания неграфических элементов. Объяснение было указано в Особенностях применения vla-функций, часть 3.
;|
* Создание текстового стиля в документе
* Параметры вызова:
doc указатель на обрабатываемый документ (документ должен быть открыт)
name имя создаваемого стиля
lst список дополнительных параметров вида:
|;
(if (not doc)
(setq doc (vla-get-activedocument (vlax-get-acad-object)))
) ;_ end of if
;; Проверяем наличие текстового стиля
(if (not (setq res
(car
(member (strcase name)
((lambda (/ _lst)
(vlax-for item (vla-get-textstyles doc)
(setq
_lst (cons (strcase (vla-get-name item)) _lst)
) ;_ end of setq
) ;_ end of vlax-for
_lst
) ;_ end of lambda
)
) ;_ end of member
) ;_ end of car
) ;_ end of setq
) ;_ end of not
(setq res (vla-add (vla-get-textstyles doc) name))
) ;_ end of if
;; стиль гарантированно создан или уже существует - это неважно
;; Важно то, что мы получили на него указатель
;; Теперь можно выполнять и настройку стиля
;;
;; <...>
;;
;; И пока на этом остановимся
res
) ;_ end of defun
Для варианта работы через entmake код, казалось бы, будет короче и проще для понимания:
;|
* Создание текстового стиля в документе
* Параметры вызова:
name имя создаваемого стиля
lst список дополнительных параметров вида:
|;
;; Проверяем наличие текстового стиля
(if (not (setq res (tblobjname "style" name)))
; (2 . "Standard") (70 . 0) (40 . 0.0) (41 . 1.0) (50 . 0.0) (71 . 0) (42 . 2.5) (3 . "txt") (4 . ""))
(setq res (entmakex (list '(0 . "STYLE")
(cons 2 name)
) ;_ end of list
) ;_ end of entmakex
) ;_ end of setq
) ;_ end of if
;; стиль гарантированно создан или уже существует - это неважно
;; Важно то, что мы получили на него указатель
;; Теперь можно выполнять и настройку стиля
;;
;; <...>
;;
;; И пока на этом остановимся
res
) ;_ end of defun
До тех пор, пока мы не попытаемся его выполнить. Во-первых, для создания текстового стиля через entmake необходимо сразу указывать шрифт, высоту стиля, угол наклона и кое-что еще. Во-вторых, вносить изменения придется с постоянным применением subst. На текстовом стиле это достаточно просто. На размерном – посложнее. На стиле таблиц подобная задача повергла лично меня в ступор (учитывая, что все то же самое можно было сделать намного проще через ActiveX).
Итак, какие же точечные пары необходимо указывать для создания текстового стиля? Обратимся к DXF Reference:
| Group code | Description | Необходим |
| 100 | Subclass marker (AcDbTextStyleTableRecord) | + |
| 2 | Style name | + |
| 70 | Standard flag values (bit-coded values):
|
+ |
| 40 | Fixed text height; 0 if not fixed | + |
| 41 | Width factor | + |
| 50 | Oblique angle | + |
| 71 | Text generation flags:
|
|
| 42 | Last height used | |
| 3 | Primary font file name | + |
| 4 | Bigfont file name; blank if none |
Таким образом, получается, что без указания обязательных точечных пар создать текстовый стиль невозможно, а код создания уже сразу требует установленных параметров (lst).
Исходя из этого, в lst должны быть значения:
| Ключ | Пояснение | Возможные значения | Значение по умолчанию |
| “vert” | Текст вертикальный | Любое значение, не равное nil интерпретируется как t | nil |
| “height” | Высота текстового стиля | Неотрицательное чЧисло любой точности | 0.0 |
| “width” | Коэффициент сжатия | Положительное число любой точности | 1.0 |
| “angle” | Угол наклона. Поскольку мы более привычны в градусам, будем здесь указывать именно градусы отклонения от вертикали. Минуты и секунды переводить в доли градусов. | Неотрицательное число любой точности. | 0.0 |
| “back” | Текст пишется “зеркально” по горизонтали | Любое значение не nil интерпретируется как t | nil |
| “down” | Текст пишется “зеркально” по вертикали (вверх ногами) | То же | nil |
| “font” | Строка пути к файлу | Если файл шрифта находится в путях доступа AutoCAD, допускается указывать только его имя. Хотя лично я обычно указываю полный путь к файлу shx | Шрифт активного стиля |
Теперь получается, что код создания (пока модификацию созданного стиля не затрагиваем!) будет примерно таким:
'(0 . "STYLE")
'(100 . "AcDbSymbolTableRecord")
'(100 . "AcDbTextStyleTableRecord")
(cons 2 name)
(cons 70
(if (cdr (assoc "vert" lst))
4
0
) ;_ end of if
) ;_ end of cons
(cons 40
(cond
((cdr (assoc "height" lst)))
(t 0.)
) ;_ end of cond
) ;_ end of cons
(cons 41
(cond
((cdr (assoc "width" lst)))
(t 1.)
) ;_ end of cond
) ;_ end of cons
(cons 50
(if (cdr (assoc "angle" lst))
(/ (* (cdr (assoc "angle" lst)) pi) 180.)
0.
) ;_ end of if
) ;_ end of cons
(cons 71
(+ (if (cdr (assoc "back" lst))
2
0
) ;_ end of if
(if (cdr (assoc "down" lst))
4
0
) ;_ end of if
) ;_ end of +
) ;_ end of cons
(cons
3
((lambda (/ font)
(cond
((and
(setq font (cdr (assoc "font" lst)))
(findfile
(strcat
(if (= (vl-filename-directory font) "")
""
(strcat (vl-filename-directory font) "\\")
) ;_ end of if
(vl-filename-base font)
".shx"
) ;_ end of strcat
) ;_ end of findfile
) ;_ end of and
font
)
(t
(cdr
(assoc 3
(entget
(tblobjname "style" (getvar "textstyle"))
) ;_ end of entget
) ;_ end of assoc
) ;_ end of cdr
)
) ;_ end of cond
) ;_ end of lambda
)
) ;_ end of cons
) ;_ end of list
Как видим, код становится сложнее: ведь при работе через ActiveX при условии неуказания каких-либо значений они просто берутся с текущего стиля документа. С одной стороны, это плюс. С другой – минус: ведь мы не уверены, что текстовый стиль будет именно таким, как надо.
Теперь мы вплотную подходим к вопросу внесения изменений в созданный стиль.
Казалось бы, все достаточно просто: используя subst, можно вносить изменения в ename-представление; а для ActiveX просто использовать vlax-put-property (или сокращенную форму, например, vla-put-fontfile). Оба варианта имеют право на жизнь. Даже не знаю, стоит ли их рассматривать подробно или нет…
Материалы для проектирования, работы и разработки (и не только в AutoCAD)
Алексей, а пробовал программно созданный текстовый стиль программно же сделать аннотативным?
Да там в принципе ничего особо сложного нет…
(defun _kpblc-ent-modify-annotative-add (ent / app res)
;|
* Добавляет аннотативность объекту. Проверялось только для стилей и описаний
* блоков
* Параметры вызова:
ent указатель на обрабатываемый объект. ename
|;
(if (>= (atoi (vl-string-trim “VISUALP ” (strcase (ver)))) 2008)
(progn
(regapp (setq app “AcadAnnotative”))
(setq
res (entmod
(list (cons -1 (_kpblc-conv-ent-to-ename ent))
‘(-3
(“AcadAnnotative”
(1000 . “AnnotativeData”)
(1002 . “{“)
(1070 . 1)
(1070 . 1)
(1002 . “}”)
)
)
) ;_ end of list
) ;_ end of entmod
) ;_ end of setq
) ;_ end of progn
(setq res ent)
) ;_ end of if
res
) ;_ end of defun
Но это работает именно на описания, а не на графические объекты. С объектами я как-то не разбирался
Ого, вот это подарок! Спасибо!
Где-то на форуме двг.ру видел твой ответ по поводу аннотативности, что она “сидит глубоко в словарях”, я уж думал, что на лиспе до нее не добраться.
>Но это работает именно на описания, а не на графические объекты
А мне только на описания и надо: для создания текстового и размерного стилей.
Ну, было дело. Пока не прижало, так и думал
).
P.S. Служебную функцию не оформлял. Если надо, можно все эти вещи закинуть в отдельный lsp для загрузки (если, конечно, надо
Служебную функцию? С дополнительными проверками – преобразованиями? Иль что имеется в виду?
“Все эти вещи” – это что? Что-то моя туго понимать…
Под служебной функцией подразумевается _kpblc-conv-ent-to-ename. Обычно я просто стараюсь все коды закидывать в lsp-файлы, доступные для прямого скачивания.
Подумал, что, может, будет иметь смысл сделать вообще отдельный топик по вопросу аннотативности… Есть смысл или нафиг?
Не поставленная галочка “Я не робот” убила мое сообщение


В общем, меня отсутствие библиотечной функции не смутило, я просто заменил “(_kpblc-conv-ent-to-ename ent)” на “ent”
Если есть желание, возможность и есть о чем рассказать – почему бы и не сделать отдельный топик про аннотативность. Будет интересно почитать, ума набраться
Я не робот!
Ок, вечером попробую полностью расписать
Готово!