О создании стилей в dwg

Как известно, в файле dwg есть такое понятие, как стили (текстовый; размерный; мультилинии; начиная с версии 2005 вводится понятие стиля таблиц). Об их создании сейчас и поговорим.

Пост получился очень большой, поэтому здесь пока ограничусь только текстовым стилем. Про размерный стиль и стиль таблиц - позже.
Если честно, то с аннотативными стилями лично я практически не работал, и поэтому не знаю методов их создания (точнее, я подозреваю, в какую сторону надо "копать"; но подозрения не есть уверенность) и из рассмотрения пока исключаю.
Сначала несколько основополагающих предположений.

  1. Мы не занимаемся редактированием текстового стиля Standard, а создаем свой собственный. Это позволит избежать некоторых не всегда очевидных и предсказуемых проблем (ведь наши файлы могут попасть к субподрядчикам, у которых настройки стиля Standard совершенно иные. В результате файл может стать просто нечитаемым. Имя нашего стиля - уникально (например, "lispru-textstyle")
  2. В наших размерных стилях используется только наш собственный текстовый стиль
  3. В стилях таблиц допускается использование только наших текстовых стилей.
  4. Шрифт, учитывая "любовь" 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
(defun _lispru-style-create-textstyle (doc name lst / res)
                                      ;|
*    Создание текстового стиля в документе
*    Параметры вызова:
  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 код, казалось бы, будет короче и проще для понимания:

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
(defun _lispru-style-create-textstyle (name lst / res)
                                      ;|
*    Создание текстового стиля в документе
*    Параметры вызова:
  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):

  1. 1 = If set, this entry describes a shape
  2. 4 = Vertical text
  3. 16 = If set, table entry is externally dependent on an xref
  4. 32 = If both this bit and bit 16 are set, the externally dependent xref has been successfully resolved
  5. 64 = If set, the table entry was referenced by at least one entity in the drawing the last time the drawing was edited. (This flag is for the benefit of AutoCADcommands. It can be ignored by most programs that read DXF files and need not be set by programs that write DXF files)
+
40 Fixed text height; 0 if not fixed +
41 Width factor +
50 Oblique angle +
71 Text generation flags:

  1. 2 = Text is backward (mirrored in X)
  2. 4 = Text is upside down (mirrored in Y)
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
(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). Оба варианта имеют право на жизнь. Даже не знаю, стоит ли их рассматривать подробно или нет...

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



Комментарии

Есть 11 коммент. к “О создании стилей в dwg”
  1. Кулик Алексей aka kpblc пишет:

    Да там в принципе ничего особо сложного нет...

    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
    (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

    Но это работает именно на описания, а не на графические объекты. С объектами я как-то не разбирался :(

  2. Do$ пишет:

    Алексей, а пробовал программно созданный текстовый стиль программно же сделать аннотативным?

  3. Do$ пишет:

    Ого, вот это подарок! Спасибо!
    Где-то на форуме двг.ру видел твой ответ по поводу аннотативности, что она "сидит глубоко в словарях", я уж думал, что на лиспе до нее не добраться. :)
    >Но это работает именно на описания, а не на графические объекты
    А мне только на описания и надо: для создания текстового и размерного стилей.

  4. Кулик Алексей aka kpblc пишет:

    Ну, было дело. Пока не прижало, так и думал ;)
    P.S. Служебную функцию не оформлял. Если надо, можно все эти вещи закинуть в отдельный lsp для загрузки (если, конечно, надо ;)).

  5. Do$ пишет:

    Служебную функцию? С дополнительными проверками - преобразованиями? Иль что имеется в виду?
    "Все эти вещи" - это что? Что-то моя туго понимать...

  6. Кулик Алексей aka kpblc пишет:

    Под служебной функцией подразумевается _kpblc-conv-ent-to-ename. Обычно я просто стараюсь все коды закидывать в lsp-файлы, доступные для прямого скачивания.
    Подумал, что, может, будет иметь смысл сделать вообще отдельный топик по вопросу аннотативности... Есть смысл или нафиг?

  7. Do$ пишет:

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

  8. Кулик Алексей aka kpblc пишет:

    Ок, вечером попробую полностью расписать :)

  9. Кулик Алексей aka kpblc пишет:

    Готово!

  10. ghostt пишет:

    Что-то через activeX не очень получается:
    если стиль существует, то вместо vla-указателя в переменой res строка и, соответственно, при задании свойств (vla-put-fonftfile и др..) ругается . Подскажите, как можно получить vla-указатель на существующий неактивный стиль? Где почитать про доступ к объектам TextStyles?

  11. Кулик Алексей aka kpblc пишет:

    Доброго.
    Вариантов на самом деле хватает:
    1. Можно после получения _res проверять его тип: если строка, то получаем указатель. vla- - значит, ничего дополнительно делать не надо.
    2. Можно пойти немного более геморройным путем:
    Коллекция текстовых стилей документа (если работать через ActiveX):
    Допустим, что name у нас задан - "LispRuTextStyle":

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    (defun test (/ name doc)
      (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. Привел наиболее часто лично мною употребляемые варианты. Уверен, что можно "навертеть" еще три раза по столько же - было бы желание :)

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


Я не робот.