О создании стилей в dwg
Как известно, в файле dwg есть такое понятие, как стили (текстовый; размерный; мультилинии; начиная с версии 2005 вводится понятие стиля таблиц). Об их создании сейчас и поговорим.
Пост получился очень большой, поэтому здесь пока ограничусь только текстовым стилем. Про размерный стиль и стиль таблиц - позже.
Если честно, то с аннотативными стилями лично я практически не работал, и поэтому не знаю методов их создания (точнее, я подозреваю, в какую сторону надо "копать"; но подозрения не есть уверенность) и из рассмотрения пока исключаю.
Сначала несколько основополагающих предположений.
- Мы не занимаемся редактированием текстового стиля Standard, а создаем свой собственный. Это позволит избежать некоторых не всегда очевидных и предсказуемых проблем (ведь наши файлы могут попасть к субподрядчикам, у которых настройки стиля Standard совершенно иные. В результате файл может стать просто нечитаемым. Имя нашего стиля - уникально (например, "lispru-textstyle")
- В наших размерных стилях используется только наш собственный текстовый стиль
- В стилях таблиц допускается использование только наших текстовых стилей.
- Шрифт, учитывая "любовь" AutoCAD'a к ttf, будем использовать shx.
Будем считать приведенные постулаты непререкаемыми.
Примечание: Пока ведем разработку только для текущего документа, хотя сделать "прицел" на обработку неактивного документа в принципе не помешает.
Как и с обычными примитивами, стили можно создавать либо через ActiveX, либо через entmake-функции. Но если первые позволят работать с любым документом (не только активным), то вторые - только с текущим, без вариантов. И это в свое время сыграет достаточно злую шутку. Но это потом, а пока (воспользовавшись тем, что указано в перегрузке lisp) будем разрабатывать функцию с минимальным количеством обязательных параметров: документ и имя стиля. Остальное - в список.
По ходу дела будем использовать самый устойчивый (но и самый медленный) способ создания неграфических элементов. Объяснение было указано в Особенностях применения vla-функций, часть 3.
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 | (defun _lispru-style-create-textstyle (doc name lst / res) ;| * Создание текстового стиля в документе * Параметры вызова: doc указатель на обрабатываемый документ (документ должен быть открыт) name имя создаваемого стиля lst список дополнительных параметров вида: '(("vert" . <Вертикальность стиля>) ("height" . <Фиксированная высота>) ; nil -> 0.0 ("width" . <Коэффициент сжатия>) ; nil -> 1.0 ("angle" . <Угол наклона, градусы>) ; nil -> 0.0 ("back" . <Задом наперед>) ("down" . <Кверх ногами>) ("font" . <Используемый шрифт>) ; nil -> берется с текущего стиля ) |; (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 код, казалось бы, будет короче и проще для понимания:
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 | (defun _lispru-style-create-textstyle (name lst / res) ;| * Создание текстового стиля в документе * Параметры вызова: name имя создаваемого стиля lst список дополнительных параметров вида: '(("vert" . <Вертикальность стиля>) ("height" . <Фиксированная высота>) ; nil -> 0.0 ("width" . <Коэффициент сжатия>) ; nil -> 1.0 ("angle" . <Угол наклона, градусы>) ; nil -> 0.0 ("back" . <Задом наперед>) ("down" . <Кверх ногами>) ("font" . <Используемый шрифт>) ; nil -> берется с текущего стиля ) |; ;; Проверяем наличие текстового стиля (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 | Шрифт активного стиля |
Теперь получается, что код для создания (пока модификацию созданного стиля не затрагиваем!) будет примерно таким:
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 | (entmakex (list '(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). Оба варианта имеют право на жизнь. Даже не знаю, стоит ли их рассматривать подробно или нет...
Да там в принципе ничего особо сложного нет...
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
;|
* Добавляет аннотативность объекту. Проверялось только для стилей и описаний
* блоков
* Параметры вызова:
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"
Если есть желание, возможность и есть о чем рассказать - почему бы и не сделать отдельный топик про аннотативность. Будет интересно почитать, ума набраться
Я не робот!
Ок, вечером попробую полностью расписать
Готово!
Что-то через activeX не очень получается:
если стиль существует, то вместо vla-указателя в переменой res строка и, соответственно, при задании свойств (vla-put-fonftfile и др..) ругается . Подскажите, как можно получить vla-указатель на существующий неактивный стиль? Где почитать про доступ к объектам TextStyles?
Доброго.
Вариантов на самом деле хватает:
1. Можно после получения _res проверять его тип: если строка, то получаем указатель. vla- - значит, ничего дополнительно делать не надо.
2. Можно пойти немного более геморройным путем:
Коллекция текстовых стилей документа (если работать через ActiveX):
Допустим, что name у нас задан - "LispRuTextStyle":
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(setq name "LispRuTextStyle"
doc (vla-get-activedocument (vlax-get-acad-object))
) ;_ end of setq
(if (/= (type (setq res (vl-catch-all-apply
(function
(lambda ()
(vla-item (vla-get-textstyles doc) name)
) ;_ end of LAMBDA
) ;_ end of function
) ;_ end of VL-CATCH-ALL-APPLY
) ;_ end of setq
) ;_ end of type
) ;_ end of /=
(setq res (vla-add (vla-get-textstyles doc) name))
) ;_ end of if
res
) ;_ end of defun
В результате мы гарантированно получим указатель на созданный стиль. А потом уже его настраивать
---
P.S. Привел наиболее часто лично мною употребляемые варианты. Уверен, что можно "навертеть" еще три раза по столько же - было бы желание
здравствуйте.
в самой первой функции _lispru-style-create-textstyle указан параметр lst, но в самом теле функции есть только _lst. тут нет никакого противоречия?
в комментарии к функции сказано: "lst список дополнительных параметров вида: " . так какого вида этот список?
Добавил. Хотя, если честно, сейчас я создаю стили через NET - удобно, блин! И быстрее значительно.