Тема: Программа для нумерации пожарных извещателей

Вниманию проектировщиков систем пожарной автоматики рекомендую ЛИСП-программу для автоматической нумерации пожарных извещателей по шлейфу, написанная по моей просьбе глубокоуважаемым VK https://www.caduser.ru/forum/topic11772.html

Re: Программа для нумерации пожарных извещателей

> Любознательный
Не стОит путать понятия... Это всего лишь набросок, хотя и вполне рабочий.
НО!
1. Из трех известных типов полилиний понимает только LWPOLYLINE;
2. Имена блоков прописаны в программе (может быть, удобнее когда ткнул в образец блока - и счет по ним пойдет, но тогда стопудово нужна проверка на наличие атрибутов);
3. Нет проверки на блокировку слоя атрибута;
4. Не реализованы точки отката для UNDO;
5. Скорей всего должен быть опциональный выбор сквозной/индивидуальной нумерации, как и выбор метода "по блокам" / "по вершинам";
6. Возможность задания начального значения для подсчета неплохо было бы иметь;
7. А полностью рабочего кода то и нет. Потому как требования разные.... Конструктор "Сделай сам" какой то получился smile))
Это так, на вскидку... чего не хватает тому что лежит по ссылке до того чтоб назваться программой. А точнее - командой. Профессиональные программисты наверняка еще что нибудь вспомнят, документацию, например smile

Re: Программа для нумерации пожарных извещателей

Это если делать совсем уж универсальный код, включая и пожелания Рapila. Для решения моей задачи он достаточен. Приглашаю всех заинтересованных оценить и высказаться.

Re: Программа для нумерации пожарных извещателей

Уважаемый VK!
Аппетит приходит во время еды. Хочу просить Вас расширить возможности Вашей ЛИСП-команды lwsvertnum (или какой другой) для решения такой задачи. В схеме автоматизации технологических процессов необходимо пронумеровать ряд блоков, представляющих собой условное графическое обозначение приборов, линий связи и пр. ЛИСП-команда будет запускаться из меню, поэтому ей будет передаваться имя блока и имя атрибута для нумерации. Далее нужно поступить двояко.
Первое яко. Блоки разбросаны по чертежу в произвольном порядке. Пользователь последовательно указывает блоки в том порядке, в каком ему нужно их пронумеровать - ЛИСП-команда в нужные атрибуты проставляет значение n+1, n - запросить, по умолчанию n=1, умолчание подтверждать Enter или Пробелом.
Второе яко. Блоки находятся в т.н. подвале схемы, с одинаковой координатой Y точки вставки. Пользователь выполняет множественный выбор, заканчивает его Enter - ЛИСП-команда в выбранные блоки слева направо (начиная с блока с меньшей координатой Х точки вставки) в нужные атрибуты проставляет значение n+1, n - запросить, по умолчанию n=1, умолчание подтверждать Enter или Пробелом.
Имеющиеся значения атрибутов игнорировать. Имеющиеся дубликаты блоков с одинаковой координатой Х точки вставки (для второго яко) игнорировать (заполнять только один), если не влом - дубликаты удалить.
Не знаю, как Вас и благодарить! Хотя, говорят, с тех пор, как человечество выдумало деньги, этот вопрос стал решаться значительно легче.

Re: Программа для нумерации пожарных извещателей

Скорей всего, это должна быть другая команда. Или две - по одной на каждое яко. Единственное, чем они все похожи - это правка атрибута блока и запрос n. Остальное - сильно различается.
PS: подвал - это легенда?

Re: Программа для нумерации пожарных извещателей

Подвал - это таблица в нижней части схемы автоматизации технологических процессов, в которой в упорядоченом виде сконцентрированы условные графические обозначения приборов и связи между ними.
Я так понимаю, что вероятность написания Вами таких команд для широкой общественности >0. Ждем-с!

Re: Программа для нумерации пожарных извещателей

Для первого яко что то вроде этого

(defun c:pickblocknum (/ name tag pref suff num ss el)
  (while (= (setq name (getstring "\nИмя блока: ")) ""))
  (while (= (setq tag (getstring "\nТег: ")) ""))
  (setq tag (strcase tag))
  (setq pref (getstring "\nПрефикс: "))
  (setq suff (getstring "\nСуффикс: "))
  (if (null (setq num (getint "\nСтартовый номер: ")))
    (setq num 1)
  ) ;_  if
  (princ "\nБлоки > ")
  (if (setq ss (ssget (list '(0 . "INSERT") '(410 . "Model") (cons 2 name))))
    (while (> (sslength ss) 0)
      (setq ss (ssdel (setq el (ssname ss 0)) ss))
      ;; поиск нужного атрибута
      (while (and (/= (cdr (assoc 0 (entget el))) "SEQEND")
                  (/= (cdr (assoc 2 (entget el))) tag)
             ) ;_  or
        (setq el (entnext el))
      ) ;_  while
      ;;  если атрибут найден
      (if (= (cdr (assoc 2 (entget el))) tag)
        (progn
          (vla-put-textstring (vlax-ename->vla-object el) (strcat pref (rtos num 2 0) suff))
          (setq num (1+ num)) ;_ приращение номера
        ) ;_  progn
      ) ;_  if
    ) ;_  while
  ) ;_  if
  (princ)
) ;_  defun
(vl-load-com)
;;;(c:pickblocknum) ;_ автозапуск

PS: долго не мог собраться написать код...  иногда бывакт, что времени совсем не бывает :((

Re: Программа для нумерации пожарных извещателей

На второе яко

(defun c:xblocknum (/ testf name tag pref suff num ss el lstins ssd eld index)
  ;; функция вернет T, если координата X первого аргумента меньше координаты X второго
  (defun testf (a b /)
    (< (cadr (assoc 10 (entget a))) (cadr (assoc 10 (entget b))))
  ) ;_  defun
  (while (= (setq name (getstring "\nИмя блока: ")) ""))
  (while (= (setq tag (getstring "\nТег: ")) ""))
  (setq tag (strcase tag))
  (setq pref (getstring "\nПрефикс: "))
  (setq suff (getstring "\nСуффикс: "))
  (if (null (setq num (getint "\nСтартовый номер <1>: ")))
    (setq num 1)
  ) ;_  if
  (princ "\nБлоки > ")
  (if (setq ss (ssget (list '(0 . "INSERT") '(410 . "Model") (cons 2 name)))) ;_ набор от пользователя
    (progn
      ;; преобразование набора в список и удаление дубликатов блоков
      (while (> (sslength ss) 0)
        (setq ss (ssdel (setq el (ssname ss 0)) ss))
        (setq lstins (cons el lstins)) ;_ список INSERT'ов
        ;; поиск дубликатов в Модели
        (setq ssd (ssget "_X" (list '(0 . "INSERT") '(410 . "Model") (cons 2 name) (assoc 10 (entget el))))) ;_ только идеально совпадающие
        (if (> (sslength (ssdel el ssd)) 0) ;_ из набора дубликатов удаляем рабочий INSERT
          (while (> (sslength ssd) 0)
            (setq ssd (ssdel (setq eld (entdel (ssname ssd 0))) ssd)) ;_ удаление из чертежа и из набора найденных дубликатов
            (ssdel eld ss) ;_ удаление из набора пользователя
          ) ;_  while
        ) ;_  if
      ) ;_  while
      (setq index (vl-sort-i lstins 'testf)) ;_ индекс, упорядоченный тест-функциией
      (while index
        (setq el (nth (car index) lstins))
        ;; поиск нужного атрибута
        (while (and (/= (cdr (assoc 0 (entget el))) "SEQEND") (/= (cdr (assoc 2 (entget el))) tag))
          (setq el (entnext el))
        ) ;_  while
        ;;  если атрибут найден
        (if (= (cdr (assoc 2 (entget el))) tag)
          (progn
            (vla-put-textstring (vlax-ename->vla-object el) (strcat pref (rtos num 2 0) suff))
            (setq num (1+ num)) ;_ приращение номера
          ) ;_  progn
        ) ;_  if
        (setq index (cdr index))
      ) ;_  while
    ) ;_  progn
  ) ;_  if
  (princ)
) ;_  defun
(vl-load-com)
(c:xblocknum) ;_ автозапуск

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

Re: Программа для нумерации пожарных извещателей

Большое спасибо, уважаемый VK!
Все Ваши команды у меня работают.
Но я погорячился, когда заявил, что

ЛИСП-команда будет запускаться из меню, поэтому ей будет передаваться имя блока и имя атрибута для нумерации.

В другие, простенькие, передаются, а в эти -  нет. Пробовал в своем mns прописывать:
[Нумерация приборов]^C^C(pickblocknum "SA_SIA1" "POZ" "" "" "" "" "") -> error: no function definition
[Нумерация приборов]^C^Cpickblocknum ("SA_SIA1" "POZ" "" "" "" "" "") -> unknown command "pickblocknum"
В (defun C:pickblocknum... пробовал убирать С:
Как правильно передать параметры?
Как правильно убрать ненужные параметры (например, pref и suff)? -> error: too few actual parameters.

Re: Программа для нумерации пожарных извещателей

Так это же команда - потому и из макроса к ней надо обрашаться как к команде, а не как к Лисп-функции. Потому просто передавайте аргументы как в обычную команду, разделяя их пробелами или ; (точкой с запятой). Кавычки не нужны, если нет пробелов в именах.
А в функцию, начинающуюся на c: нельзя передавать аргументы, если не ошибаюсь.

Re: Программа для нумерации пожарных извещателей

> VK
Огромное спасибо!
б-тестирование и отладка завершены, приступаю к опытно-промышленной эксплуатации.
Вопросы для подчистки:
1.  Результат выполнения pickblocknum виден после завершения работы команды, а хотелось бы после каждого клика. Возможно ли?
2. Можно ли в начале работы каждой команды при вводе в командной строке параметров гасить перекрестье курсора с прицелом?
3. Можно ли при выводе в командную строку самодельного "Выберите полилинию >" гасить стандартное "Select objects:"
Пока это все, что нужно для полного счастья.
Формулирую очередную задачку:)

Re: Программа для нумерации пожарных извещателей

3. Можно ли при выводе в командную строку самодельного "Выберите полилинию >" гасить стандартное "Select objects:"

Можно. Надо в нужные места поставить (setvar "cmdecho" 0) и (setvar "cmdecho" 1).
Или попробовать в макросе ^P использовать.

2. Можно ли в начале работы каждой команды при вводе в командной строке параметров гасить перекрестье курсора с прицелом?

Дак вроде параметры то макросом вводятся smile) Если ну оччччень надо - то можно, тока в каких именно местах?

1. Результат выполнения pickblocknum виден после завершения работы команды, а хотелось бы после каждого клика. Возможно ли?

Все возможно... Нечто вроде этого

  (while  (setq ss ":S" (ssget (list '(0 . "INSERT") '(410 . "Model") (cons 2 name))))

и скобку лишнюю убрать... Но тут подумать надо, как организовать выход.

Re: Программа для нумерации пожарных извещателей

Надо в нужные места поставить (setvar "cmdecho" 0) и (setvar "cmdecho" 1).
Или попробовать в макросе ^P использовать.

Не получилось, наверное не угадал с "нужными" местами.

Дак вроде параметры то макросом вводятся smile) Если ну оччччень надо - то можно, тока в каких именно местах?

Дык, какие - макросом, какие - ручками.
В lwsvertnum руками -   (setq pref (getstring "\nПрефикс: "))
В pickblocknum руками - (if (null (setq num (getint "\nСтартовый номер: ")))
В xblocknum руками - (if (null (setq num (getint "\nСтартовый номер: ")))

Все возможно... Нечто вроде этого
  (while  (setq ss ":S" (ssget (list '(0 . "INSERT") '(410 . "Model") (cons 2 name))))
и скобку лишнюю убрать... Но тут подумать надо, как организовать выход.

Не получилось, действительно - надо думать...
А вообще оччччень не надо - и так работает. Может быть, когда делать будет нечего :)
Еще раз спасибо!

Re: Программа для нумерации пожарных извещателей

Привожу пример одной из программ с сокрытием курсора в нужном месте (только для модели!). Думаю, разберетесь куда что воткнуть в других прогах.

(defun c:xblocknum (/ *error* dpfr mbgc mcgc testf name tag pref suff num ss el lstins ssd eld index)
  (defun *error* (msg)
    (vla-put-ModelCrosshairColor dpfr mcgc) ;_ восстановление курсора
  )
  ;; функция вернет T, если координата X первого аргумента меньше координаты X второго
  (defun testf (a b /)
    (< (cadr (assoc 10 (entget a))) (cadr (assoc 10 (entget b))))
  ) ;_  defun
  (setq dpfr (vla-get-display (vla-get-preferences (vlax-get-acad-object))))
  (setq mbgc (vla-get-GraphicsWinModelBackgrndColor dpfr)) ;_ цвет background
  (setq mcgc (vla-get-ModelCrosshairColor dpfr)) ;_ текущий цвет курсора
  (while (= (setq name (getstring "\nИмя блока: ")) ""))
  (while (= (setq tag (getstring "\nТег: ")) ""))
  (setq tag (strcase tag))
  (setq pref (getstring "\nПрефикс: "))
  (setq suff (getstring "\nСуффикс: "))
  (vla-put-ModelCrosshairColor dpfr mbgc) ;_ сокрытие курсора
  (if (null (setq num (getint "\nСтартовый номер <1>: ")))
    (setq num 1)
  ) ;_  if
  (vla-put-ModelCrosshairColor dpfr mcgc) ;_ восстановление курсора
  (princ "\nБлоки > ")
.......

Функция *error* нужна для восстановления курсора при отказе пользователя от продолжения программы по ESC

Re: Программа для нумерации пожарных извещателей

Помогите получить максимальное значение (числовое) для указанного тэга указанонного блока.

> VK
Не могли бы Вы дополнить свою лисп-команду такой возможностью: после запроса

 (if (null (setq num (getint "\nСтартовый номер: ")))

по-умолчанию предлагается 1, а при вводе N (Next) определяется имеющееся максимальное значение и стартуем со следующего. Заранее благодарю!

Re: Программа для нумерации пожарных извещателей

И откуда же его брать? Анализировать все блоки в чертеже?
Да, вот еще... как насчет закрытия "дырок" в последовательности нумерации (например при удалении блока)? wink

Re: Программа для нумерации пожарных извещателей

VK пишет:

И откуда же его брать? Анализировать все блоки в чертеже?

Ну, да.. А что, заморочно писать или долго работать будет?

как насчет закрытия "дырок" в последовательности нумерации (например при удалении блока)?

Никак, только вручную, в моем случае это не смертельно. Но если прога выдаст перечень таких "дырок", будет здорово.

Re: Программа для нумерации пожарных извещателей

Да не... вроде не должно быть заметных тормозов... просто уточнить ТЗ smile
Обдумаю, попробую сделать.

Re: Программа для нумерации пожарных извещателей

Примерно так

(defun c:pickblocknum (/ num-sel hole-nums name tag pref suff num ss el nums mxnum holes)
  ;; извлекает число из строки
  (defun num-sel (str /)
    (while (and (not (wcmatch (substr str 1 1) "#")) (> (strlen str) 0))
      (setq str (substr str 2))
    ) ;_  while
    (atoi str)
  ) ;_  defun
  ;; возвращает список "дыр" в числовой последовательности
  (defun hole-nums (l:nums / mn mx h-nums)
    (setq mn (car (vl-sort l:nums '<)))
    (setq mx (car (vl-sort l:nums '>)))
    (while (< mn mx)
      (if (not (vl-position mn l:nums))
        (setq h-nums (cons mn h-nums))
      ) ;_  if
      (setq mn (1+ mn))
    ) ;_  while
    (vl-sort h-nums '<)
  ) ;_  defun
  (while (= (setq name (getstring "\nИмя блока: ")) ""))
  (while (= (setq tag (getstring "\nТег: ")) ""))
  (setq tag (strcase tag))
  (setq pref (getstring "\nПрефикс: "))
  (setq suff (getstring "\nСуффикс: "))
  (if (setq ss (ssget "_X" (list '(0 . "INSERT") '(410 . "Model") (cons 2 name))))
    (while (> (sslength ss) 0)
      (setq ss (ssdel (setq el (ssname ss 0)) ss))
      ;; поиск нужного атрибута
      (while (and (/= (cdr (assoc 0 (entget el))) "SEQEND")
                  (/= (cdr (assoc 2 (entget el))) tag)
             ) ;_  or
        (setq el (entnext el))
      ) ;_  while
      ;;  если атрибут найден
      (if (= (cdr (assoc 2 (entget el))) tag)
        (setq nums (cons (vla-get-textstring (vlax-ename->vla-object el)) nums))
      ) ;_  if
    ) ;_  while
    (setq nums '(0))
  ) ;_  if
  (if (setq nums (mapcar 'num-sel nums)) ;_ список существующей последовательности
    (progn
      (if (setq holes (hole-nums nums)) ;_ дырки
        (princ (strcat "\nДырки: " (vl-string-trim "()" (vl-princ-to-string holes))))
      ) ;_  if
      (setq mxnum (car (vl-sort nums '>)))
    ) ;_  progn
    (setq mxnum 0) ;_ нет прописаных чисел в атрибутах
  ) ;_  if
  (initget "Next")
  (if (setq num (getint (strcat "\nСтартовый номер или [Next (" (rtos (1+ mxnum) 2 0) ")] <1>:")))
    (if (= num (strcat "Next (" (rtos (1+ mxnum) 2 0) ")]"))
      (setq num (max nums))
    ) ;_  if
    (setq num 1)
  ) ;_  if
  (princ "\nБлоки > ")
  (if (setq ss (ssget (list '(0 . "INSERT") '(410 . "Model") (cons 2 name))))
    (while (> (sslength ss) 0)
      (setq ss (ssdel (setq el (ssname ss 0)) ss))
      ;; поиск нужного атрибута
      (while (and (/= (cdr (assoc 0 (entget el))) "SEQEND")
                  (/= (cdr (assoc 2 (entget el))) tag)
             ) ;_  or
        (setq el (entnext el))
      ) ;_  while
      ;;  если атрибут найден
      (if (= (cdr (assoc 2 (entget el))) tag)
        (progn
          (vla-put-textstring (vlax-ename->vla-object el) (strcat pref (rtos num 2 0) suff))
          (setq num (1+ num)) ;_ приращение номера
        ) ;_  progn
      ) ;_  if
    ) ;_  while
  ) ;_  if
  (princ)
) ;_  defun
(vl-load-com)
;;;(c:pickblocknum) ;_ автозапуск

Только будет глючить, если в префиксе есть цифирь. Или суффикс с цифры начинается.
PS кстати, этой програмкой нумеровать можно еще и лампочки, розетки, выключатели и вобще все что можно пронумеровать :)))

Re: Программа для нумерации пожарных извещателей

Command: (load "pickblocknum.lsp")
Command: pickblocknum
Имя блока: "SA_SIA1"
Тег: "POZ"
Префикс: ""
Суффикс: ""
Дырки: 67
Стартовый номер или [Next (72)] <1>:""
Requires an integer value or option keyword.
Стартовый номер или [Next (72)] <1>:next
Блоки >
Select objects: 1 found
Select objects: 1 found, 2 total
Select objects: 1 found, 3 total
Select objects: 1 found, 4 total
Select objects:
; error: bad argument type: numberp: "Next"
Command:

Это если ввожу "N" или "NEXT", ввод различных префиксов/суффиксов не влияет.
Где-то чего-то не хватает, или лишнее, сам не придумаю...
Если ввожу номер - все нормально.
Дырки считаются правильно. Нашел в своем чертеже ошибки. Спасибо!

PS кстати, этой програмкой нумеровать можно еще и лампочки, розетки, выключатели и вобще все что можно пронумеровать :)))

Ну, конеччччно! wink

Re: Программа для нумерации пожарных извещателей

Да, в одном месте ошибка

  (initget "Next")
  (if (setq num (getint (strcat "\nСтартовый номер или [Next (" (rtos (1+ mxnum) 2 0) ")] <1>:")))
    (if (= num "Next")
      [b](setq num (1+ mxnum))[/b]
    ) ;_  if
    (setq num 1)
  ) ;_  if

Re: Программа для нумерации пожарных извещателей

Все работает! Спасибо.
А это.. ну, как бы... мммм... вот если бы еще... не сочтите слишком назойливым...
Короче, если бы и дубликаты выдать, как дырки... dirol

Re: Программа для нумерации пожарных извещателей

конструирование кнопки "СДЕЛАТЬ ВСЕ" продолжается :)))
может быть... но не сегодня....

Re: Программа для нумерации пожарных извещателей

Извиняюсь, что вклинился в диалог...
Это все очень интересно и нужно...расскажите мне,новичку, как этим воспользоваться, применимо к AutoCad?

Re: Программа для нумерации пожарных извещателей

Скопировать выкладываемый Автором код в буфер обмена ОС.
Запустить текстовый редактор Блокнот.
Вставить код из буфера.
Сохранить файл с именем pickblocknum.lsp в папку с Вашими любимыми программками для Автокада.
Из Автокада загрузить программу: appload или Инструменты -> Приложение...
Набрать в командной строке pickblocknum.
Ввести с командной строки информацию, запрашиваему программой.
Указать блоки чертежа в порядке возрастания порядкового номера. Блоки должны иметь текстовый атрибут для ввода порядкового номера.
Насладиться результатом.
Возможен запуск из самодельной менюшки или кнопки с передачей запрашиваемой информации, но это несколько сложнее. Будет интересно - расскажу.