Научите лиспу на примере (или как kpblc, VVA и компания пытаются обучить чайника лиспу) - Страница 236
| Правила | Регистрация | Пользователи | Сообщения за день |  Справка по форуму | Файлообменник |

Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > Научите лиспу на примере (или как kpblc, VVA и компания пытаются обучить чайника лиспу)

Научите лиспу на примере (или как kpblc, VVA и компания пытаются обучить чайника лиспу)

Ответ
Поиск в этой теме
Непрочитано 20.07.2008, 20:12 1 |
Научите лиспу на примере (или как kpblc, VVA и компания пытаются обучить чайника лиспу)
Red Nova
 
ՃԱՐՏԱՐԱԳԵՏ, տ.գ.թ.
 
Торонто
Регистрация: 23.10.2007
Сообщений: 1,990

Со школы не ладится у меня с программированием. Все предметы щелкал, а на экзамене по информатике (Visual foxpro) программку типа суммирования столбцов списал у соседа (это уже в университете).
Не смотря на эте намерен научится писать программы для Автокада на лиспе, скачал книгу Хювенена, несколько примеров создания программ, но после получасового “смотрения” таких книг мое мышление явно притормаживает.
Решил пойти другим путем.
Нашел самый короткий лисп из моей коллекции, и прошу программистов с этого форума пошагово объяснить какой символ что означает. Надеюсь на вашу помощь.


Код:
[Выделить все]
(defun c:make-blocks-explodeable (/ adoc)
  (vl-load-com)
  (vla-startundomark
    (setq adoc (vla-get-activedocument (vlax-get-acad-object)))
    ) ;_ end of vla-startundomark
  (vlax-for blk_def (vla-get-blocks adoc)
    (if (and (equal (vla-get-isxref blk_def) :vlax-false)
             (equal (vla-get-islayout blk_def) :vlax-false)
             ) ;_ end of and
      (vl-catch-all-apply '(lambda () (vla-put-explodable blk_def :vlax-true)))
      ) ;_ end of if
    ) ;_ end of vlax-for
  (vla-endundomark adoc)
  (princ)
  ) ;_ end of defun
_____________________________________________________________________________________________________________

Прошло много лет и топик теперь представляет из себя площадку для обучения азов программирования для многих начинающих.
Так что начинающие лиспогрызы приветствуются .
__________________
Блог

Последний раз редактировалось Red Nova, 12.07.2017 в 05:43.
Просмотров: 2048112
 
Непрочитано 05.08.2024, 16:13
#4701
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Цитата:
Сообщение от Сет Посмотреть сообщение
как определить какие именно объекты были скопированы
Вопрос на форуме уже поднимался, тему искать лениво (да и в отпуске я, так что звиняй ) А так - на реакторе начала команды получаешь (entlast), все что после него - получить через entnext - вот тебе и список новых объектов. Ну понятно, что переменную, в которой (entlast), придется обнулять при отмене / завершении / ошибки команды.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 05.08.2024, 16:29
#4702
Сет


 
Регистрация: 19.11.2014
Сообщений: 2,606


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
А так - на реакторе начала команды получаешь (entlast), все что после него - получить через entnext - вот тебе и список новых объектов. Ну понятно, что переменную, в которой (entlast), придется обнулять при отмене / завершении / ошибки команды.
Только потом еще фильтровать набор надо.

Может дело вкуса, мне объектный реактор вполне удобен. Хотя и он не без недостатков. Например событие редактирования сложного объекта, например блока, состоящего из нескольких полилиний и атрибутов, срабатывает несколько раз. Он реагирует на изменение каждой вершины полилинии. И чем сложнее блок- тем больше будет срабатываний. Не придумал как прервать эту цепочку срабатываний после первой сработки. Я сейчас работаю с блоком не таким уж большим. Событие модификации срабатывает не более десятка раз. Код в обработчике совсем небольшой - поэтому меня это не сильно напрягает. Основной код в обработчике командного реактора - он вызывается всегда один раз.

К слову о прерывании цепочки срабатываний. Выключение реактора в функции-обработчике - почему-то не помогает. Других вариантов прервать цепочку не придумал.
Код:
[Выделить все]
 
(setq cs_node_modified_object_reactor
		(vlr-object-reactor (list blc) "cs_node_modified_object_reactor"
		    (list '(:vlr-openedForModify . cs_node_modified) '(:vlr-subObjModified . cs_node_modified)))
	    ) ; setq

(defun cs_node_modified (obj reac args / )
    (setq cs_ModifiedNode obj)
    (setq cs_NodeEventsCounter (1+ cs_NodeEventsCounter))
    (vlr-remove cs_node_modified_object_reactor) ; не прерывает цепочку!
) ; defun
Здесь:
blc - блок, на который вешаю объектный реактор,
cs_ModifiedNode - глобальная переменная, в которой содержится ссылка на измененный блок
cs_NodeEventsCounter - глобальный счетчик, подсчитывает количество раз срабатывания реактора
Сет вне форума  
 
Непрочитано 05.08.2024, 16:47
#4703
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Цитата:
Сообщение от Сет Посмотреть сообщение
Только потом еще фильтровать набор надо.
Вот это вообще не проблема ИМХО. vl-remove и вперед
Цитата:
Сообщение от Сет Посмотреть сообщение
мне объектный реактор вполне удобен
После своих экспериментов с реакторами базы данных чертежа я предпочитаю более топорные методы
Цитата:
Сообщение от Сет Посмотреть сообщение
К слову о прерывании цепочки срабатываний
Я бы делал по-другому. В глобальную переменную в начале редактирования засовываешь, к примеру, 0. В конце редактирования добавляешь 1. Если общее количество <= 1, то выполнять обработку. Нет - значит нет. Это тупо как идея, без реализации.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 05.08.2024, 17:09
#4704
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,499


Цитата:
Сообщение от Сет Посмотреть сообщение
К слову о прерывании цепочки срабатываний. Выключение реактора в функции-обработчике - почему-то не помогает. Других вариантов прервать цепочку не придумал.
это потому что в лиспе нет idle реактора, насколько помню) Это где уж гарантировано закончилась транзакция БД, и можно отцепить обработчики изменений и сделать что-то с объектом без опасения повторного вхождения в обработчики изменений.
Сергей812 вне форума  
 
Непрочитано 05.08.2024, 18:10
#4705
Сет


 
Регистрация: 19.11.2014
Сообщений: 2,606


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
Я бы делал по-другому. В глобальную переменную в начале редактирования засовываешь, к примеру, 0. В конце редактирования добавляешь 1. Если общее количество <= 1, то выполнять обработку. Нет - значит нет. Это тупо как идея, без реализации.
Ты не совсем понял проблему. Нет возможности в какой-либо момент времени влиять на работу реактора в момент срабатывания события редактирования. Автокад помечает объект как редактируемый столько раз, сколько параметров было изменено при редактировании - и вот столько раз и вызывает функцию-обработчик. То есть вот это - "Если общее количество <= 1" - просто негде вставить. Произошло 10 изменений в блоке при редактировании - значит 10 раз вызовется функция-обработчик. Отменить ее вызов - не получается.
Сет вне форума  
 
Непрочитано 05.08.2024, 18:12
#4706
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Думаешь, я просто так сказал про "топорные" подходы?

----- добавлено через ~1 мин. -----
А так - ну реально я бы смотрел в сторону MultiCAD, NET и пользовательских объектов.
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 05.08.2024, 18:56
#4707
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,499


имитировать на лиспе кастомные объекты через динблоки и обработчики событий - это вообще смело) Интересно, как это все будет работать, когда подобных объектов в чертеже будет этак несколько тысяч...
Сергей812 вне форума  
 
Непрочитано 06.08.2024, 10:07
#4708
Сет


 
Регистрация: 19.11.2014
Сообщений: 2,606


Продолжаем про реакторы. Задача - при копировании объектов через буфер обмена нужно новые объекты включить в список владельцев реактора копирования (на самом деле еще и в список владельцев реактора изменения, но я это пока опустил для упрощения). Есть вот такой код:
Код:
[Выделить все]
 ; объектный реактор (копирование)
(setq cs_node_copied_object_reactor (vlr-object-reactor (list blc) "cs_node_copied_object_reactor" (list '(:vlr-copied . cs_node_copied))))

; реактор базы данных (добавление примитива)
(setq cs_node_acdb_reactor (vlr-acdb-reactor "cs_node_acdb_reactor" (list '(:vlr-objectAppended . cs_node_pasteclip))))

; функция-обработчик копирования
(defun cs_node_copied (obj reac args / )
    (setq cs_CopiedNodes (append cs_CopiedNodes args))
    (setq cs_NodeEventsCounter (1+ cs_NodeEventsCounter))
) ; defun

; функция-обработчик добавление примитива
(defun cs_node_pasteclip (reac args / )
    (if (and
	    (> cs_NodeEventsCounter 0)
	    (/= cs_CopiedNodes nil)
	    (/= cs_node_copied_object_reactor nil)
        ) ; and
        (progn
	    (foreach x cs_CopiedNodes
	        (vlr-owner-add cs_node_copied_object_reactor (vlax-ename->vla-object x))
	    ) ; foreach
	    (princ (strcat "\nКоличество срабатываний реактора копирования: " (itoa cs_NodeEventsCounter)
		           ". Обработано событие добавление примитива."))
	    (setq cs_CopiedNods nil)
            (setq cs_NodeEventsCounter 0)
        ) ; progn
    ) ; if
) ;defun
Создаю два реактора - объектный (отслеживает копирование) и реактор базы данных (отслеживает добавление примитива). При помещении объекта в буфер обмена (Ctrl+C) - срабатывает реактор копирования и добавляет имя будущего объекта в список cs_CopiedNodes, также инкрементируется счетчик. Затем вставляю объекты в чертеж (Ctrl+V) - срабатывает функция-обработчик cs_node_pasteclip, которая добавляет в список владельцев реактора копирования - объекты из списка cs_CopiedNodes. Проблема в том, что в этом списке оказываются вовсе не те объекты, которые будут затем вставлены в чертеж, а некие промежуточные. Ведь после Ctrl+V нужно еще указать точку вставки. После непосредственно вставки - имена добавленных объектов не соответствуют именам из списка cs_CopiedNodes. Как же здесь получить список реальных объектов после вставки из буфера?

P.S. При тестировании всего этого дела счетчик копирования у меня почему-то получает очень высокое значение - 43.

----- добавлено через ~24 мин. -----
Наверное действительно стоит добывать объекты через entlast.

Последний раз редактировалось Сет, 06.08.2024 в 10:13.
Сет вне форума  
 
Непрочитано 06.08.2024, 11:09
#4709
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Вот скажи, а на фига вообще объектный реактор-то?
Мне кажется, что, во-первых, не "при копировании", а "при завершении команды вставки из буфера обмена". Во-вторых, я не уверен, что твой код сработает при простом _.copy / _.mocoro.
Код:
[Выделить все]
 (if *vlr-cmd*
  (progn
    (vlr-remove *vlr-cmd*)
    (setq *vlr-cmd* nil)
  )
)

(if (not *vlr-cmd*)
  (progn
    (setq *vlr-cmd* (vlr-command-reactor
                      "kpblc-cmd-reactor"
                      '((:vlr-commandwillstart . _kpblc-vlr-command-start)
                        (:vlr-commandended . _kpblc-vlr-command-ended)
                        (:vlr-commandfailed . _kpblc-vlr-command-failed)
                        (:vlr-commandcancelled . _kpblc-vlr-command-cancelled)
                       )
                    )
    )
  )
)

(defun _kpblc-vlr-command-start (reactor cmd)
  (setq *kpblc-ent-last* (entlast)
        *kpblc-ent-list* nil
  )
)

(defun _kpblc-vlr-command-ended (reactor cmd / ent)
  (setq cmd (strcase (vl-string-trim "_-." (car cmd))))
  (if (member cmd '("COPY" "COPYCLIP" "MOCORO" "PASTE" "PASTECLIP"))
    (progn
      (while (setq *kpblc-ent-last* (entnext *kpblc-ent-last*))
        (setq *kpblc-ent-list* (cons *kpblc-ent-last* *kpblc-ent-list*))
      )
      ;; И тут уже обрабатываешь *kpblc-ent-list* как душе угодно
    )
  )
)

(defun _kpblc-vlr-command-failed (reactor cmd)
  (setq *kpblc-ent-last* nil
        *kpblc-ent-list* nil
  )
)

(defun _kpblc-vlr-command-cancelled (reactor cmd)
  (setq *kpblc-ent-last* nil
        *kpblc-ent-list* nil
  )
)
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 06.08.2024, 12:06
#4710
Сет


 
Регистрация: 19.11.2014
Сообщений: 2,606


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
Вот скажи, а на фига вообще объектный реактор-то?
Для формирования списка копируемых объектов. Я пока не въехал вот в эту твою конструкцию, которая отвечает судя по всему за то же самое.

Код:
[Выделить все]
 (while (setq *kpblc-ent-last* (entnext *kpblc-ent-last*))
(setq *kpblc-ent-list* (cons *kpblc-ent-last* *kpblc-ent-list*))
      )
Что будет в твоем списке *kpblc-ent-list*, если скопировано несколько объектов одной командой COPY? Функция entnext в твоем цикле перебирает вообще ВСЕ объекты чертежа, а не только добавленные последней командой COPY. Или я не понимаю как работает команда entnext.

В моем случае объектный реактор легко формирует набор новых объектов. И проблема, которую я здесь обозначил, не в объектном реакторе, а в командном, там где я, собственно, обрабатываю команду COPY или PASTECLIP. С командой COPY нет проблем - она корректно обрабатывает мой список объектов, полученный в объектном реакторе. А вот PASTECLIP обрабатывается некорректно, потому что после окончания выполнения этой команды объекты еще не существуют - я не могу их обработать. Собственно тот же самый вопрос и к твоему коду. Обработав PASTECLIP ты оперируешь списком (*kpblc-ent-list*) реальных объектов или неких временных? Это твой реальных рабочий код или ты сейчас набросал его для пояснения своей мысли?
Сет вне форума  
 
Непрочитано 06.08.2024, 13:40
#4711
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


А ты проверь. А заодно и посмотри на справку по функции entnext
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 06.08.2024, 15:06
#4712
Сет


 
Регистрация: 19.11.2014
Сообщений: 2,606


Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
А ты проверь.
Проверил - работает.

Но во-первых я все равно не понял как работает entnext. В справке указано, что entnext возвращает следующий за указанным примитив в базе данных. Нигде не нашел оговорки, что речь идет о только что добавленных примитивах или что-то типа того. Хотя по факту так и работает.

Во-вторых - entnext расчленяет составные объекты и считает их отдельно. А мне нужно, чтобы блок считался за один объект. Наверняка это как-то можно сделать?
Сет вне форума  
 
Непрочитано 06.08.2024, 15:37
#4713
===AAA===


 
Регистрация: 15.08.2005
г. Норильск
Сообщений: 616


Цитата:
Наверное действительно стоит добывать объекты через entlast.
Тут вот ещё не забудь про один подводный камень.

"Последним" вполне может оказаться не "цельный" объект (типа отрезка),
а "составной" (типа полилинии или блока с атрибутами).

Поэтому (entnext) будет возвращать не "свежедобавленный" объект,
а подобъект от уже существующего в базе объекта.

Я в своё время делал так - добавлял в чертеж "отрезок", запоминал его
как (entlast), от него искал добавленные примитивы и затем удалял его.

Разумеется, с обвесом в виде проверок и удаления этого отрезка по ERROR.
Не слишком изящно, но это было очень давно, ещё до появления (vl-load-com) ...
И оно работало вполне себе стабильно.
__________________
Счастливо, Алексей!
===AAA=== вне форума  
 
Непрочитано 06.08.2024, 15:42
#4714
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,499


Цитата:
Сообщение от Сет Посмотреть сообщение
Но во-первых я все равно не понял как работает entnext. В справке указано, что entnext возвращает следующий за указанным примитив в базе данных. Нигде не нашел оговорки, что речь идет о только что добавленных примитивах или что-то типа того. Хотя по факту так и работает.
просто у любого объекта в БД чертежа есть уникальный идентификатор (UID). В качестве этого UID используется целое число и при добавлении каждого следующего объекта в БД чертежа просто добавляют единицу к этому числу - это достаточно для уникальности. Соответственно, если взять в качестве "опорной точки" некий объект чертежа и получить его UID - то все добавленные после него объекты будут иметь больший по значению UID в порядке их добавления (но могут быть и пропуски при удаленных объектах).
Сергей812 вне форума  
 
Непрочитано 06.08.2024, 15:52
#4715
Сет


 
Регистрация: 19.11.2014
Сообщений: 2,606


Цитата:
Сообщение от Сергей812 Посмотреть сообщение
просто у любого объекта в БД чертежа есть уникальный идентификатор (UID). В качестве этого UID используется целое число и при добавлении каждого следующего объекта в БД чертежа просто добавляют единицу к этому числу - это достаточно для уникальности. Соответственно, если взять в качестве "опорной точки" некий объект чертежа и получить его UID - то все добавленные после него объекты будут иметь больший по значению UID в порядке их добавления (но могут быть и пропуски при удаленных объектах).
Да, но почему при этом entnext работает только до первого только что добавленного примитива, а не до самого первого в базе данных чертежа?
Сет вне форума  
 
Непрочитано 06.08.2024, 16:00
#4716
Сергей812


 
Регистрация: 10.08.2013
Сообщений: 11,499


Цитата:
Сообщение от Сет Посмотреть сообщение
Да, но почему при этом entnext работает только до первого только что добавленного примитива, а не до самого первого в базе данных чертежа?
это функция просто ищет следующий по UID объект, у которого нет пометки - что он был удален. Если не задавать объект - будет искать с дефолтного значения UID, т.е. с начала БД чертежа.
---
И этот UID называется хэндлом (DXF группа 5, насколько помню).

Последний раз редактировалось Сергей812, 06.08.2024 в 16:07.
Сергей812 вне форума  
 
Непрочитано 06.08.2024, 16:02
#4717
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Цитата:
Сообщение от Сет Посмотреть сообщение
Во-вторых - entnext расчленяет составные объекты и считает их отдельно. А мне нужно, чтобы блок считался за один объект. Наверняка это как-то можно сделать?
А фильтрация на что?
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
 
Непрочитано 06.08.2024, 16:09
#4718
===AAA===


 
Регистрация: 15.08.2005
г. Норильск
Сообщений: 616


Так (entnext) идёт "вперёд" по базе данных.

Вызов (entnext) без параметра - первый примитив в базе.

С параметром (entnext <имя_примитива>) - вперёд от указанного,
включая субпримитивы. Пока база данных чертежа не закончится.
__________________
Счастливо, Алексей!
===AAA=== вне форума  
 
Непрочитано 06.08.2024, 16:13
#4719
Сет


 
Регистрация: 19.11.2014
Сообщений: 2,606


Цитата:
Сообщение от Сергей812 Посмотреть сообщение
это функция просто ищет следующий по UID объект, у которого нет пометки - что он был удален. Если не задавать объект - будет искать с дефолтного значения UID, т.е. с начала БД чертежа.
Ну вот добавили мы 5 объектов в чертеж, у них имена - 1, 2, 3, 4, 5. Затем выделяем объекты 2 и 5 - и копируем, получаем два новых объекта - 6 и 7. И запускаем команду entnext в цикле. Получили в список объекты 6 и 7, но почему (entnext 6) дает nil? Ведь есть предыдущий объект - 5 и так далее до 1.

Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
А фильтрация на что?
О какой фильтрации речь? Проверять каждый примитив не является ли он субпримитивом и его не добавлять в список? А что является признаком этого? В справке пишут, что как-то через SEQEND можно добраться до родительских примитивов, но пример бы посмотреть.
Сет вне форума  
 
Непрочитано 06.08.2024, 16:19
1 | #4720
Кулик Алексей aka kpblc
Moderator

LISP, C# (ACAD 200[9,12,13,14])
 
Регистрация: 25.08.2003
С.-Петербург
Сообщений: 40,404


Цитата:
Сообщение от Сет Посмотреть сообщение
О какой фильтрации речь?
Ты специально не читаешь, да? )
Цитата:
Сообщение от Кулик Алексей aka kpblc Посмотреть сообщение
vl-remove и вперед
Как пример:
Код:
[Выделить все]
 (vl-remove-if-not
               (function
                 (lambda (x)
                   (and (entget x)
                        (= (cdr (assoc 0 (entget x))) "INSERT")
                   )
                 )
               )
               *kpblc-ent-list*
             )
__________________
Моя библиотека lisp-функций
---
Обращение ко мне - на "ты".
Все, что сказано - личное мнение.
Кулик Алексей aka kpblc вне форума  
Ответ
Вернуться   Форум DWG.RU > Программное обеспечение > Программирование > LISP > Научите лиспу на примере (или как kpblc, VVA и компания пытаются обучить чайника лиспу)



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
LISP. Вставка в таблицу поля, соотвествующего площади примитива Profan Готовые программы 272 06.06.2021 23:12
Сейсмозащита и сейсмоизоляция существующих, построенных зд. IANationalInformAgentstvo Прочее. Архитектура и строительство 216 20.01.2015 16:51
Мониторы LCD CRT Разное 94 17.06.2008 10:51
ЮМОР 2006 =) Perezz!! Разное 1122 04.01.2007 00:46