Примитив – блок? Или ассоциативный массив?

Столкнулся тут на работе с вопросом "как определить ассоциативный массив?".

В .NET для этого есть отдельный метод AssocArray.IsAssociativeArray, а вот в lisp что-то подобного не видать. Ну ладно, займемся снова велосипедостроением :)

Код писать буду постепенно, поэтому статья получится ни фига не короткая. Кому лениво читать - не раскрывайте спойлер ;)

История разбора
Ну ок, есть у нас какой-то указатель на примитив. Скорее всего, понадобится нам и его ename-, и vla-указатель.

1
2
3
4
5
6
7
8
9
10
11
(defun _kpblc-is-ent-assoc-array(ent)
  ;|
*    Определяет, является ли переданный примитив указателем на ассоциативный список
*    Параметры вызова:
  ent    ; указатель (ename- или vla-) на обрабатываемый примитив
*    Возвращает t, если примитив является ассоциативным массивом
*    Примеры вызова:
(_kpblc-is-ent-assoc-array (car (entsel "\nSelect entity : ")))
(_kpblc-is-ent-assoc-array (vlax-ename->vla-object (car (entsel "\nSelect entity : "))))
|;

  )

Первое – приводим ent к хоть какому-то виду. Ну, например, ename. Код элементарен, отдельно его показывать не буду.

Второе, что надо сообразить – что с точки зрения лиспа ассоциативный массив не больше чем блок. Анонимный блок. Следовательно, проверяем – является ли примитив а) блоком; б) анонимным блоком; в) не является вхождением динамического блока (ведь известно, что вхождения дин.блоков практически всегда являются анонимными блоками):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(defun _kpblc-is-ent-assoc-array (ent / name vla_ename)
                                ;|
*    Определяет, является ли переданный примитив указателем на ассоциативный список
*    Параметры вызова:
  ent    ; указатель (ename- или vla-) на обрабатываемый примитив
*    Возвращает t, если примитив является ассоциативным массивом
*    Примеры вызова:
(_kpblc-is-ent-assoc-array (car (entsel "\nSelect entity : ")))
(_kpblc-is-ent-assoc-array (vlax-ename->vla-object (car (entsel "\nSelect entity : "))))
|;

  (and (setq ent (cond ((= (type ent) 'ename) ent)
                       ((= (type ent) 'vla-object) (vlax-vla-object->ename ent))
                 ) ;_ end of cond
       ) ;_ end of setq
       (= (cdr (assoc 0 (entget ent))) "INSERT")
       (setq vla_ename (vlax-ename->vla-object ent))
       (setq name (if (vlax-property-available-p vla_ename 'effectivename)
                    (vla-get-effectivename vla_ename)
                    (vla-get-name vla_ename)
                  ) ;_ end of if
       ) ;_ end of setq
       (wcmatch name "'**" ;; Здесь вместо ' надо ставить обратный апостроф
  ) ;_ end of and
) ;_ end of defun

И вот тут начинается самое интересное. С точки зрения вхождения блока различить – простой это анонимный блок или ассоциативный массив – невозможно. Ни через ename, ни через vla. Кто не верит – проверьте, у меня на AutoCAD 2019 и 2020 разницы не было никакой.

Но как-то их ACAD же различает, верно?!

Значит, ползем в сторону описаний блоков – вдруг там что-то есть?

Тут для упрощения кода сделаю предположение, что работа выполняется только в текущем документе. Для нетекущего просто придется делать дополнительные преобразования, которые особого влияния на общую картину не окажут.

Если выполнить строки

1
2
(setq def (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) name))
(vlax-dump-object def t)

то разницы с обычным блоком будет ноль.

Ну хорошо, ACAD, не хочешь по плохому, по хорошему будет еще хуже:

1
2
(setq def (vlax-vla-object->ename (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) name)))
(entget def '("*"))

И вот тут обнаруживаются забавные вещи:
entget массива

Это что за группа ‘(102 . “{ACAD_REACTORS”) ? Ну-ка, ну-ка…

1
(entget (cdr (assoc 330 (member '(102 . "{ACAD_REACTORS") (entget def)))))

entget реакторов

Ух ты! Вспоминаем начальный уровень английского и внимательно смотрим либо на 0, либо на 100 группу: Бла-бла-ASSOCDEPENDENCY, то бишь ассоциативные зависимости. Может, достаточно просто проверять наличие подобных реакторов и, если они есть – то примитив у нас ассоциативный массив?

Несколько десятков проверок так и показали. Следовательно, конечный код будет…

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-is-ent-assoc-array (ent / name vla_ename def def_list)
                                ;|
*    Определяет, является ли переданный примитив указателем на ассоциативный список
*    Параметры вызова:
  ent    ; указатель (ename- или vla-) на обрабатываемый примитив
*    Возвращает t, если примитив является ассоциативным массивом
*    Примеры вызова:
(_kpblc-is-ent-assoc-array (car (entsel "\nSelect entity : ")))
(_kpblc-is-ent-assoc-array (vlax-ename->vla-object (car (entsel "\nSelect entity : "))))
|;

  (and (setq ent (cond ((= (type ent) 'ename) ent)
                       ((= (type ent) 'vla-object) (vlax-vla-object->ename ent))
                 ) ;_ end of cond
       ) ;_ end of setq
       (= (cdr (assoc 0 (entget ent))) "INSERT")
       (setq vla_ename (vlax-ename->vla-object ent))
       (setq name (if (vlax-property-available-p vla_ename 'effectivename)
                    (vla-get-effectivename vla_ename)
                    (vla-get-name vla_ename)
                  ) ;_ end of if
       ) ;_ end of setq
       (wcmatch name "`**") ; здесь уже иичего менять не надо
       (setq def (vlax-vla-object->ename
                   (vla-item (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) name)
                 ) ;_ end of vlax-vla-object->ename
       ) ;_ end of setq
       (setq def_list (cdr (assoc 330 (member '(102 . "{ACAD_REACTORS") (entget def)))))
       (= (cdr (assoc 0 (entget def_list))) "ACDBASSOCDEPENDENCY")
  ) ;_ end of and
) ;_ end of defun


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


Я не робот.