Тема: LISP. Удобная команда построения 3-х мерной полилинии.

Рискнул поместить её в "готовые", хотя тестирование должным образом не было проведено. Не судите строго. Если что - пишите, исправим.

; Команда построения 3-х мерной полилинии с дополнительными опциями управления текущей ПСК.
; Перед указанием каждой следующей вершины полилинии имеется возможность установить желаемую ориентацию осей ПСК.
; Опции командной строки похожи на опции команды UCS, но имеются особенности:
; 1. Точка начала ПСК всегда переносится в последнюю построенную вершину полилинии.
;    Все изменения ПСК с помощью доступных опций касаются только направления её осей X и Y.
;    Точка начала ПСК остается неизменной. Это позволяет задавать координаты вершин (кроме первой)
;    с командной строки в абсолютных координатах (не используя @).
; 2. Oпция Above.
;    Запрашивает смещение следующей вершины относительно последней построенной вдоль оси Z ПСК.
;    Строит новую вершину и переносит в неё ПСК.
; 3. Опция ZDepth.
;    Запрашивает смещение ПСК вдоль оси Z относительно последней вершины, переносит ПСК, но вершину не строит,
;    а ждет указания точки уже в новой плоскости построений.
; 4. Опция Prev.
;    Ориентирует оси текущей ПСК в соответствии с ориентацией осей ближайшей ПСК из списка отката, у которой
;    направление осей не совпадает с текущим. Начало текущей ПСК остается неизменным.
; Загружать весь файл.
; Вызов с командной строки: 3DPLINE
;
;
(defun c:3dpline ( /
          read-ucs; локальная функция.
          ucs; список - состояние ПСК на момент вызова команды.
          icon; текущее состояние системной переменной UCSICON.
          )
  ; Определение локальной функции:
  (defun read-ucs ( / org)
    (setq org (getvar 'ucsorg))
    (list org
      (mapcar '+ (getvar 'ucsxdir) org)
      (mapcar '+ (getvar 'ucsydir) org)
    ); return.
  ); end defun.
  ;
  (begin-undo-group 0)
  ;
  (setq icon (getvar 'ucsicon))
  (setq ucs (read-ucs))
  ;
  (vl-catch-all-apply 'brokenline)
  ;
  ; Восстановление исходной ПСК и видимости пиктограммы:
  (setvar 'ucsicon 0)
  (command "_.ucs" "_World" "_.ucs" "_3point" (car ucs) (cadr ucs) (caddr ucs))
  (setvar 'ucsicon icon)
  ;
  (end-undo-group)
  (princ)
); end defun.
; BROKENLINE.
; Внешняя функция: READ-UCS.
; Внешняя переменная: icon - состояние системной переменной UCSICON на момент вызова команды.
; Переменная уровня документа: ::model_space - указатель пространства модели.
(defun brokenline ( /
           pt; результат запроса точки.
           brol; vla-указатель.
           disp; смещение начала ПСК.
           nullbase; точка (0.0 0.0 0.0).
           org; точка начала ПСК.
           act; список с информацией о последнем действии пользователя.
           actions; список действий.
           coords; список координат построенной полилинии.
           )
  (setq nullbase '(0.0 0.0 0.0))
  (if (not ::model_space) (setq ::model_space (vla-get-modelspace (vla-get-activedocument (vlax-get-acad-object)))));
  ;
  (initget "eXit")
  (setq pt (getpoint "\nSpecify first vertex or [eXit] <exit>: "))
  (if (or (not pt) (= pt "eXit")) (quit));
  (setq actions (append (list (cons nil (read-ucs))) actions))
  (command "_.ucs" "_Origin" pt)
  (while pt
    (initget 0 "Above ZDepth Top Bottom Front BAck Left Right X Y Z Prev Undo")
    (setq pt (getpoint
           nullbase
           "\nSpecify next vertex or [Above/ZDepth/Top/Bottom/Front/BAck/Left/Right/X/Y/Z/Prev/Undo] <exit>: "
         )
    ); setq.
    (cond
      ((not pt)); конец построений.
      ((listp pt); указана точка:
       (cond
     (brol; добавляем новую вершину:
      (setq actions (append (list (cons T (read-ucs))) actions))
      (command "_.ucs" "_Origin" pt)
      (vlax-invoke-method brol 'AppendVertex (vlax-3d-point (trans nullbase 1 0)))
      (vlax-invoke-method brol 'update)
      );
     (T; создаем полилинию из 2х вершин:
      (setq brol (vlax-invoke-method
               ::model_space
               'Add3Dpoly
               (vlax-make-variant
             (vlax-safearray-fill
               (vlax-make-safearray vlax-vbdouble '(0 . 5))
               (append (trans nullbase 1 0) (trans pt 1 0))
               )
             (+ vlax-vbarray vlax-vbdouble)
             );
               );
        ); setq.
      (setq actions (append (list (cons T (read-ucs))) actions))
      (command "_.ucs" "_Origin" pt)
     );
       ); end cond.
      );
      ((= pt "ZDepth"); указание на смещение ПСК вдоль оси Z:
       (setq disp nil)
       (while (not disp)
     (initget 128)
     (setq disp (getpoint "\nSpecify Z-elevation for new UCS origin: "))
     (cond
       ((not disp) (princ "\nInvalid input. Please retry.")); пустой ввод. Повтор.
       ((listp disp) (setq disp (caddr disp)));
       ((numberp (setq disp (atof disp))));
       (T (princ "\nInvalid input. Please retry.") (setq disp nil));
       ); end cond.
     ); end while.
       (setq actions (append (list (cons nil (read-ucs))) actions))
       (command "_.ucs" "_Move" "_Zdepth" disp)
      );
      ((= pt "Above"); указание на построение следующей вершины смещением предыдущей по оси Z:
       (setq disp nil)
       (while (not disp)
     (initget 128)
     (setq disp (getpoint "Specify Z-elevation for next vertex: "))
     (cond
       ((not disp) (princ "\nInvalid input. Please retry.")); пустой ввод. Повтор.
       ((listp disp) (setq disp (caddr disp)));
       ((numberp (setq disp (atof disp))));
       (T (princ "\nInvalid input. Please retry.") (setq disp nil));
       ); end cond.
     ); end while.
       (setq actions (append (list (cons T (read-ucs))) actions))
       (command "_.ucs" "_Origin" (setq pt (list 0.0 0.0 disp)))
       (vlax-invoke-method brol 'AppendVertex (vlax-3d-point (trans nullbase 1 0)))
       (vlax-invoke-method brol 'update)
      );
      ((wcmatch pt "[XYZ]"); поворот вокруг оси:
       (setq ang (getreal (strcat "\nSpecify rotation angle about " pt " axis <0.0>: ")))
       (cond
     (ang
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (command "_.ucs" (strcat "_" pt) ang)
     );
       ); end cond.
      );
      ((or (wcmatch (substr pt 1 1) "[TBFLRW]") (= pt "BAck"))
       (setq actions (append (list (cons nil (read-ucs))) actions))
       (setq org (getvar 'ucsorg))
       (setvar 'ucsicon 0)
       (command "_.ucs" (strcat "_" pt))
       (setq org (trans org 0 1))
       (command "_.ucs" "_Origin" org)
       (setvar 'ucsicon icon)
      );
      ((= pt "Prev")
       (setq pt 0)
       (setq act (car actions))
       (while (and act (equal
             (list (getvar 'ucsxdir) (getvar 'ucsydir))
             (list (mapcar '- (caddr act) (cadr act)) (mapcar '- (cadddr act) (cadr act)))
             1e-9; точность сравнения.
               );
          ); and.
     (setq pt (1+ pt))
     (setq act (nth pt actions))
       ); end while.
       (cond
     (act; найдена ПСК в списке отката, которая отличается от текущей:
      (setq org (getvar 'ucsorg))
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setq org (trans org 0 1))
      (command "_.ucs" "_Origin" org)
      (setvar 'ucsicon icon)
     );
     (T (princ "All previous UCSs not differs from current UCS."));
       ); end cond.
      );
      ((= pt "Undo"); отмена последнего действия:
       (setq act (car actions)); последнее зафиксированное действие.
       (setq actions (cdr actions))
       (cond
     ((car act); последним действием была добавлена вершина полилинии:
      (setq coords (reverse (vlax-safearray->list (vlax-variant-value (vlax-get-property brol 'coordinates)))))
      (cond
        ((= (length coords) 6); полилиния из oдного сегмента:
         (vlax-invoke-method brol 'delete)
         (vlax-release-object brol)
         (setq brol nil)
        );
        (T; полилиния из 2х и более сегментов:
         (vlax-invoke-method brol 'delete)
         (vlax-release-object brol)
         (setq coords (reverse (cdddr coords)))
         (setq brol (vlax-invoke-method
              ::model_space
              'Add3Dpoly
              (vlax-make-variant
                (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble (cons 0 (1- (length coords)))) coords)
                (+ vlax-vbarray vlax-vbdouble)
              );
            );
         ); setq.
        );
      ); end cond.
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
     );
     (actions; изменялась только ПСК и список отката не пустой:
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
     );
     (T
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
      (initget "eXit")
      (setq pt (getpoint "\nSpecify first vertex or [eXit] <exit>: "))
      (if (or (not pt) (= pt "eXit")) (quit));
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (command "_.ucs" "_Origin" pt)
     );
       ); end cond.
      );
    ); end cond.
  ); end while.
  (princ)
); end defun.
; BEGIN-UNDO-GROUP.
; Установка отметки начала группы команд.
; Возврат: набор объектов предварительного выбора или nil.
(defun begin-undo-group (mode; режим обработки набора предварительно выбранных объектов.
             /
             undo_state; текущая настройка команды UNDO.
             ss; набор объектов предварительного выбора.
             )
  (cond
    ((= mode 0) (sssetfirst nil nil)); не разрешен предварительный выбор.
    ((= mode 1); команда может использовать набор предварительного выбора:
     (if (and (setq ss (ssget "_I")) (= 0 (getvar 'pickfirst))) (sssetfirst nil nil)); end if.
    );
    ((= mode 2); функция не меняет набор предварительного выбора:
     (setq ss (ssget "_I"))
    );
  ); end cond.
  ;
  (setq undo_state (getvar 'undoctl))
  (setvar 'cmdecho 0)
  (cond
    ((= 0 (logand undo_state 1)) (command "_.undo" "_All")); если отключена возможность отмены.
    ((= 2 (logand undo_state 2)) (command "_.undo" "_control" "_all")); если запрещена отмена более одной команды.
  ); end cond.
  (if (= 0 (logand undo_state 8)) (command "_.undo" "_begin")); если нет открытой группы команд.
  (if (and (= mode 2) ss) (sssetfirst nil ss))
  ss; return.
); end defun.
; END-UNDO-GROUP.
; Установка отметки окончания группы команд.
; Возврат: nil.
(defun end-undo-group ( / )
  (setvar 'cmdecho 0)
  (if (= 8 (logand (getvar 'undoctl) 8))(command "_.undo" "_end")); end if.
); end defun.

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> Пастух
Разрешите ли вы для тестирования и применения в личном пользовании русифицировать эту программу?

Re: LISP. Удобная команда построения 3-х мерной полилинии.

К тому нет никаких препятствий. Эта программа без всяких авторских претензий.
Просто у меня английский ACAD и я стараюсь, чтобы всё выглядело единообразно, как родное smile

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> Пастух
Поясни пожалуйста кусочек кода:

(initget "eXit")
(setq pt (getpoint "\nSpecify first vertex or [eXit] <exit>: "))
(if (or (not pt) (= pt "eXit")) (quit))

Как я ни старался, не смог сделать (= pt "eXit")...
Хотя идея понравилась, но хочется понять реализацию...
К сожалению никогда подобными конструкциями с initget не баловался - что я недоглядел?

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Все, разобрался...
Просто у тебя ошибочка, надо:

(initget 0 "eXit X")

тогда будет работать в обоих случаях

(= pt "eXit")

я пробовал сокращения x - она же у тебя взрослая.

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> Евгений Елпанов
Ошибочка вышла
(initget 0 "eXit X") = (initget 0 "eXit")

Re: LISP. Удобная команда построения 3-х мерной полилинии.

У меня работает и с маленькой х и сбольшой Х (естественно, английской).
Заглавной буквой обозначают сокращенный вариант ввода.  При вводе ключевого слова или его допустимого сокращенного варианта регистр не имеет значения. Об этом пишет Н.Н. Полещук да и мой английский ACAD это подтверждает.
А бит управления = 0 по умолчанию.

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> Пастух
Наверное у меня дома акад сошел с ума...
У меня английский 2004, но без бита отказывается выдавать "eXit".
Ладно, завтра буду его лечить, давно пора, сколько можно издеваться!

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Надо хорошенько растереть его спиртом :^)

Re: LISP. Удобная команда построения 3-х мерной полилинии.

А обязательно ли так записывать:

(initget "eXit")
(setq pt (getpoint "\nSpecify first vertex or [eXit] <exit>: "))
(if (or (not pt) (= pt "eXit")) (quit))

У меня прекрасно работает (на выход) такая запись (без initget):

(setq pt (getpoint "\nУкажите первую вершину <Enter-Отказ>: "))
(if (not pt) (quit))

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Не обязательно. Но так появляется дополнительный способ выхода через контекстное меню во время запроса.

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Хотя выход и без этого состоится по правому щелчку.
Согласен с Вами. Наверное это лишнее.

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Вариант для пользователей, работающих с русскими версиями AutoCAD.

; Команда построения 3-х мерной полилинии с дополнительными опциями управления текущей ПСК.
; Перед указанием каждой следующей вершины полилинии имеется возможность установить желаемую ориентацию осей ПСК.
; Опции командной строки похожи на опции команды UCS (ПСК), но имеются особенности:
; 1. Точка начала ПСК всегда переносится в последнюю построенную вершину полилинии.
;    Все изменения ПСК с помощью доступных опций касаются только направления её осей X и Y.
;    Точка начала ПСК остается неизменной. Это позволяет задавать координаты вершин (кроме первой)
;    с командной строки в абсолютных координатах (не используя @).
; 2. Oпция "Выше".
;    Запрашивает смещение следующей вершины относительно последней построенной вдоль оси Z ПСК.
;    Строит новую вершину и переносит в неё ПСК.
; 3. Опция "ZПск".
;    Запрашивает смещение ПСК вдоль оси Z относительно последней вершины, переносит ПСК, но вершину не строит,
;    а ждет указания точки уже в новой плоскости построений.
; 4. Опция "Предыдущая".
;    Ориентирует оси текущей ПСК в соответствии с ориентацией осей ближайшей ПСК из списка отката, у которой
;    направление осей не совпадает с текущим. Начало текущей ПСК остается неизменным.
; Загружать весь файл, сохранить код можно в файле 3d_pline.lsp.
; Вызов с командной строки: 3D_PLINE
;
;        Автор - участник конференции autocad.ru под ником [b]Пастух[/b].
;        Русификацию командной строки выполнил [b]Владимир Громов[/b].
;
(defun C:3D_PLINE ( /
      read-ucs; локальная функция.
      ucs; список - состояние ПСК на момент вызова команды.
      icon; текущее состояние системной переменной UCSICON.
      )
  ; Определение локальной функции:
  (defun read-ucs ( / org)
    (setq org (getvar 'ucsorg))
    (list org
    (mapcar '+ (getvar 'ucsxdir) org)
    (mapcar '+ (getvar 'ucsydir) org)
    ); return.
  ); end defun.
  ;
  (begin-undo-group 0)
  ;
  (setq icon (getvar 'ucsicon))
  (setq ucs (read-ucs))
  ;
  (vl-catch-all-apply 'brokenline)
  ;
  ; Восстановление исходной ПСК и видимости пиктограммы:
  (setvar 'ucsicon 0)
  (command "_.ucs" "_World" "_.ucs" "_3point" (car ucs) (cadr ucs) (caddr ucs))
  (setvar 'ucsicon icon)
  ;
  (end-undo-group)
  (princ)
); end defun.
; BROKENLINE.
; Внешняя функция: READ-UCS.
; Внешняя переменная: icon - состояние системной переменной UCSICON на момент вызова команды.
; Переменная уровня документа: ::model_space - указатель пространства модели.
(defun brokenline ( /
       pt; результат запроса точки.
       brol; vla-указатель.
       disp; смещение начала ПСК.
       nullbase; точка (0.0 0.0 0.0).
       org; точка начала ПСК.
       act; список с информацией о последнем действии пользователя.
       actions; список действий.
       coords; список координат построенной полилинии.
       )
  (setq nullbase '(0.0 0.0 0.0))
  (if (not ::model_space) (setq ::model_space (vla-get-modelspace (vla-get-activedocument
(vlax-get-acad-object)))));
  ;
  (setq pt (getpoint "\nУкажите первую вершину <Enter-Отказ>: "))
  (if (not pt) (quit));
  (setq actions (append (list (cons nil (read-ucs))) actions))
  (command "_.ucs" "_Origin" pt)
  (while pt
    (initget 0 "Выше ZПск сВЕрху сНИзу сПЕреди сЗАди сЛЕва сПРава X Y Z Предыдущая Отменить
               _Above ZDepth Top Bottom Front BAck Left Right X Y Z Prev Undo")
    (setq pt (getpoint
         nullbase
         "\nУкажите следующую вершину или
[Выше/ZПск/сВЕрху/сНИзу/сПЕреди/сЗАди/сЛЕва/сПРава/X/Y/Z/Предыдущая/Отменить] <Конец>: "
       )
    ); setq.
    (cond
      ((not pt)); конец построений.
      ((listp pt); указана точка:
       (cond
   (brol; добавляем новую вершину:
    (setq actions (append (list (cons T (read-ucs))) actions))
    (command "_.ucs" "_Origin" pt)
    (vlax-invoke-method brol 'AppendVertex (vlax-3d-point (trans nullbase 1 0)))
    (vlax-invoke-method brol 'update)
    );
   (T; создаем полилинию из 2х вершин:
    (setq brol (vlax-invoke-method
           ::model_space
           'Add3Dpoly
           (vlax-make-variant
       (vlax-safearray-fill
         (vlax-make-safearray vlax-vbdouble '(0 . 5))
         (append (trans nullbase 1 0) (trans pt 1 0))
         )
       (+ vlax-vbarray vlax-vbdouble)
       );
           );
    ); setq.
    (setq actions (append (list (cons T (read-ucs))) actions))
    (command "_.ucs" "_Origin" pt)
   );
       ); end cond.
      );
      ((= pt "ZDepth"); указание на смещение ПСК вдоль оси Z:
       (setq disp nil)
       (while (not disp)
   (initget 128)
   (setq disp (getpoint "\nСмещение по Z для начала новой ПСК: "))
   (cond
     ((not disp) (princ "\nНеверный ввод. Пожалуйста повторите.")); пустой ввод. Повтор.
     ((listp disp) (setq disp (caddr disp)));
     ((numberp (setq disp (atof disp))));
     (T (princ "\nНеверный ввод. Пожалуйста повторите.") (setq disp nil));
     ); end cond.
   ); end while.
       (setq actions (append (list (cons nil (read-ucs))) actions))
       (command "_.ucs" "_Move" "_Zdepth" disp)
      );
      ((= pt "Above"); указание на построение следующей вершины смещением предыдущей по оси Z:
       (setq disp nil)
       (while (not disp)
   (initget 128)
   (setq disp (getpoint "Расстояние по Z для следующей вершины: "))
   (cond
     ((not disp) (princ "\nНеверный ввод. Пожалуйста повторите.")); пустой ввод. Повтор.
     ((listp disp) (setq disp (caddr disp)));
     ((numberp (setq disp (atof disp))));
     (T (princ "\nНеверный ввод. Пожалуйста повторите.") (setq disp nil));
     ); end cond.
   ); end while.
       (setq actions (append (list (cons T (read-ucs))) actions))
       (command "_.ucs" "_Origin" (setq pt (list 0.0 0.0 disp)))
       (vlax-invoke-method brol 'AppendVertex (vlax-3d-point (trans nullbase 1 0)))
       (vlax-invoke-method brol 'update)
      );
      ((wcmatch pt "[XYZ]"); поворот вокруг оси:
       (setq ang (getreal (strcat "\nУгол поворота вокруг оси " pt " <0.0>: ")))
       (cond
   (ang
    (setq actions (append (list (cons nil (read-ucs))) actions))
    (command "_.ucs" (strcat "_" pt) ang)
   );
       ); end cond.
      );
      ((or (wcmatch (substr pt 1 1) "[TBFLRW]") (= pt "BAck"))
       (setq actions (append (list (cons nil (read-ucs))) actions))
       (setq org (getvar 'ucsorg))
       (setvar 'ucsicon 0)
       (command "_.ucs" (strcat "_" pt))
       (setq org (trans org 0 1))
       (command "_.ucs" "_Origin" org)
       (setvar 'ucsicon icon)
      );
      ((= pt "Prev")
       (setq pt 0)
       (setq act (car actions))
       (while (and act (equal
       (list (getvar 'ucsxdir) (getvar 'ucsydir))
       (list (mapcar '- (caddr act) (cadr act)) (mapcar '- (cadddr act) (cadr act)))
       1e-9; точность сравнения.
           );
        ); and.
   (setq pt (1+ pt))
   (setq act (nth pt actions))
       ); end while.
       (cond
   (act; найдена ПСК в списке отката, которая отличается от текущей:
    (setq org (getvar 'ucsorg))
    (setq actions (append (list (cons nil (read-ucs))) actions))
    (setvar 'ucsicon 0)
    (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
    (setq org (trans org 0 1))
    (command "_.ucs" "_Origin" org)
    (setvar 'ucsicon icon)
   );
   (T (princ "Все предыдущие ПСК не отличаются от текущей ПСК."));
       ); end cond.
      );
      ((= pt "Undo"); отмена последнего действия:
       (setq act (car actions)); последнее зафиксированное действие.
       (setq actions (cdr actions))
       (cond
   ((car act); последним действием была добавлена вершина полилинии:
    (setq coords (reverse (vlax-safearray->list (vlax-variant-value (vlax-get-property brol
'coordinates)))))
    (cond
      ((= (length coords) 6); полилиния из oдного сегмента:
       (vlax-invoke-method brol 'delete)
       (vlax-release-object brol)
       (setq brol nil)
      );
      (T; полилиния из 2х и более сегментов:
       (vlax-invoke-method brol 'delete)
       (vlax-release-object brol)
       (setq coords (reverse (cdddr coords)))
       (setq brol (vlax-invoke-method
        ::model_space
        'Add3Dpoly
        (vlax-make-variant
          (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble (cons 0 (1- (length coords)))) coords)
          (+ vlax-vbarray vlax-vbdouble)
        );
      );
       ); setq.
      );
    ); end cond.
    (setvar 'ucsicon 0)
    (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
    (setvar 'ucsicon icon)
   );
   (actions; изменялась только ПСК и список отката не пустой:
    (setvar 'ucsicon 0)
    (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
    (setvar 'ucsicon icon)
   );
   (T
    (setvar 'ucsicon 0)
    (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
    (setvar 'ucsicon icon)
    (setq pt (getpoint "\nУкажите первую вершину <Enter-Отказ>: "))
    (if (not pt) (quit));
    (setq actions (append (list (cons nil (read-ucs))) actions))
    (command "_.ucs" "_Origin" pt)
   );
       ); end cond.
      );
    ); end cond.
  ); end while.
  (princ)
); end defun.
; BEGIN-UNDO-GROUP.
; Установка отметки начала группы команд.
; Возврат: набор объектов предварительного выбора или nil.
(defun begin-undo-group (mode; режим обработки набора предварительно выбранных объектов.
       /
       undo_state; текущая настройка команды UNDO.
       ss; набор объектов предварительного выбора.
       )
  (cond
    ((= mode 0) (sssetfirst nil nil)); не разрешен предварительный выбор.
    ((= mode 1); команда может использовать набор предварительного выбора:
     (if (and (setq ss (ssget "_I")) (= 0 (getvar 'pickfirst))) (sssetfirst nil nil)); end if.
    );
    ((= mode 2); функция не меняет набор предварительного выбора:
     (setq ss (ssget "_I"))
    );
  ); end cond.
  ;
  (setq undo_state (getvar 'undoctl))
  (setvar 'cmdecho 0)
  (cond
    ((= 0 (logand undo_state 1)) (command "_.undo" "_All")); если отключена возможность отмены.
    ((= 2 (logand undo_state 2)) (command "_.undo" "_control" "_all")); если запрещена отмена более одной
команды.
  ); end cond.
  (if (= 0 (logand undo_state 8)) (command "_.undo" "_begin")); если нет открытой группы команд.
  (if (and (= mode 2) ss) (sssetfirst nil ss))
  ss; return.
); end defun.
; END-UNDO-GROUP.
; Установка отметки окончания группы команд.
; Возврат: nil.
(defun end-undo-group ( / )
  (setvar 'cmdecho 0)
  (if (= 8 (logand (getvar 'undoctl) 8))(command "_.undo" "_end")); end if.
); end defun.

Возможный макрос для кнопки или пункта меню:

^C^C^P(if (not C:3D_PLINE) (load "3d_pline")) 3D_PLINE

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Дополнение.
Для работы программы необходимо загрузить функцию

(vl-load-com)

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Обнаружил и исправил ошибку:
Изменения касаются функции BROKENLINE.
Неверная работа опции ZDepth и вылет при выборе опции Above в самом начале построения (при запросе указания второй точки).
Надеюсь что не добавил новых ошибок.

(defun brokenline ( /
           pt1; координаты первой вершины в МСК.
           pt; результат запроса точки.
           brol; vla-указатель.
           disp; смещение начала ПСК.
           nullbase; точка (0.0 0.0 0.0).
           org; точка начала ПСК.
           act; список с информацией о последнем действии пользователя.
           actions; список действий.
           coords; список координат построенной полилинии.
           )
  (setq nullbase '(0.0 0.0 0.0))
  (if (not ::model_space) (setq ::model_space (vla-get-modelspace (vla-get-activedocument (vlax-get-acad-object)))));
  ;
  (initget 0 "eXit")
  (setq pt (getpoint "\nSpecify first vertex or [eXit] <exit>: "))
  (if (or (not pt) (= pt "eXit")) (quit));
  (setq pt1 (trans pt 1 0))
  (setq actions (append (list (cons nil (read-ucs))) actions))
  (command "_.ucs" "_Origin" pt)
  (while pt
    (initget 0 "Above ZDepth Top Bottom Front BAck Left Right X Y Z Prev Undo")
    (if disp
      (setq disp nil)
      (setq pt (getpoint
         nullbase
         "\nSpecify next vertex or [Above/ZDepth/Top/Bottom/Front/BAck/Left/Right/X/Y/Z/Prev/Undo] <exit>: "
           )
      ); setq.
    ); end if.
    (cond
      ((not pt)); конец построений.
      ((listp pt); указана точка:
       (setq actions (append (list (cons T (read-ucs))) actions))
       (command "_.ucs" "_Origin" pt)
       (cond
     (brol; добавляем новую вершину:
      (vlax-invoke-method brol 'AppendVertex (vlax-3d-point (trans nullbase 1 0)))
      (vlax-invoke-method brol 'update)
      );
     (T; создаем полилинию из 2х вершин:
      (setq brol (vlax-invoke-method
               ::model_space
               'Add3Dpoly
               (vlax-make-variant
             (vlax-safearray-fill
               (vlax-make-safearray vlax-vbdouble '(0 . 5))
               (append pt1 (trans nullbase 1 0))
               )
             (+ vlax-vbarray vlax-vbdouble)
               );
             );
      ); setq.
     );
       ); end cond.
      );
      ((= pt "ZDepth"); указание на смещение ПСК вдоль оси Z:
       (while (not disp)
     (initget 128)
     (setq disp (getpoint "\nSpecify Z-elevation for new UCS origin: "))
     (cond
       ((not disp) (princ "\nInvalid input. Please retry.")); пустой ввод. Повтор.
       ((listp disp) (setq disp (caddr disp)));
       ((numberp (setq disp (atof disp))));
       (T (princ "\nInvalid input. Please retry.") (setq disp nil));
       ); end cond.
     ); end while.
       (setq actions (append (list (cons nil (read-ucs))) actions))
       (command "_.ucs" "_Move" "_Zdepth" disp)
       (setq disp nil)
      );
      ((= pt "Above"); указание на построение следующей вершины смещением предыдущей по оси Z:
       (while (not disp)
     (initget 128)
     (setq disp (getpoint "Specify Z-elevation for next vertex: "))
     (cond
       ((not disp) (princ "\nInvalid input. Please retry.")); пустой ввод. Повтор.
       ((listp disp) (setq disp (caddr disp)));
       ((numberp (setq disp (atof disp))));
       (T (princ "\nInvalid input. Please retry.") (setq disp nil));
     ); end cond.
       ); end while.
       (setq pt (list 0.0 0.0 disp))
      );
      ((wcmatch pt "[XYZ]"); поворот вокруг оси:
       (setq ang (getreal (strcat "\nSpecify rotation angle about " pt " axis <0.0>: ")))
       (cond
     (ang
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (command "_.ucs" (strcat "_" pt) ang)
     );
       ); end cond.
      );
      ((or (wcmatch (substr pt 1 1) "[TBFLRW]") (= pt "BAck"))
       (setq actions (append (list (cons nil (read-ucs))) actions))
       (setq org (getvar 'ucsorg))
       (setvar 'ucsicon 0)
       (command "_.ucs" (strcat "_" pt))
       (setq org (trans org 0 1))
       (command "_.ucs" "_Origin" org)
       (setvar 'ucsicon icon)
      );
      ((= pt "Prev")
       (setq pt 0)
       (setq act (car actions))
       (while (and act (equal
             (list (getvar 'ucsxdir) (getvar 'ucsydir))
             (list (mapcar '- (caddr act) (cadr act)) (mapcar '- (cadddr act) (cadr act)))
             1e-9
               );
          ); and.
     (setq pt (1+ pt))
     (setq act (nth pt actions))
       ); end while.
       (cond
     (act; найдена ПСК в списке отката, которая отличается от текущей:
      (setq org (getvar 'ucsorg))
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setq org (trans org 0 1))
      (command "_.ucs" "_Origin" org)
      (setvar 'ucsicon icon)
     );
     (T (princ "All previous UCSs not differs from current UCS."));
       ); end cond.
      );
      ((= pt "Undo"); отмена последнего действия:
       (setq act (car actions)); последнее зафиксированное действие.
       (setq actions (cdr actions))
       (cond
     ((car act); последним действием была добавлена вершина полилинии:
      (setq coords (reverse (vlax-safearray->list (vlax-variant-value (vlax-get-property brol 'coordinates)))))
      (cond
        ((= (length coords) 6); полилиния из oдного сегмента:
         (vlax-invoke-method brol 'delete)
         (vlax-release-object brol)
         (setq brol nil)
        );
        (T; полилиния из 2х и более сегментов:
         (vlax-invoke-method brol 'delete)
         (vlax-release-object brol)
         (setq coords (reverse (cdddr coords)))
         (setq brol (vlax-invoke-method
              ::model_space
              'Add3Dpoly
              (vlax-make-variant
                (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble (cons 0 (1- (length coords)))) coords)
                (+ vlax-vbarray vlax-vbdouble)
              );
            );
         ); setq.
        );
      ); end cond.
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
     );
     (actions; изменялась только ПСК и список отката не пустой:
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
     );
     (T
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
      (initget 0 "eXit")
      (setq pt (getpoint "\nSpecify first vertex or [eXit] <exit>: "))
      (if (or (not pt) (= pt "eXit")) (quit));
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (command "_.ucs" "_Origin" pt)
     );
       ); end cond.
      );
    ); end cond.
  ); end while.
  (princ)
); end defun.

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> Пастух
А я как-то не нарвался. Теперь вот думаю, локализовать этот вариант?

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Я исправлю в локализованном и выложу.

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Отлично!

Re: LISP. Удобная команда построения 3-х мерной полилинии.

Исправленная, локализованная.

(defun brokenline ( /
           pt1; координаты первой вершины в МСК.
           pt; результат запроса точки.
           brol; vla-указатель.
           disp; смещение начала ПСК.
           nullbase; точка (0.0 0.0 0.0).
           org; точка начала ПСК.
           act; список с информацией о последнем действии пользователя.
           actions; список действий.
           coords; список координат построенной полилинии.
           )
  (setq nullbase '(0.0 0.0 0.0))
  (if (not ::model_space) (setq ::model_space (vla-get-modelspace (vla-get-activedocument (vlax-get-acad-object)))));
  ;
  (setq pt (getpoint "\nУкажите первую вершину <Enter-Отказ>: "))
  (if (not pt) (quit));
  (setq pt1 (trans pt 1 0))
  (setq actions (append (list (cons nil (read-ucs))) actions))
  (command "_.ucs" "_Origin" pt)
  (while pt
    (initget 0 "Выше ZПск сВЕрху сНИзу сПЕреди сЗАди сЛЕва сПРава X Y Z Предыдущая Отменить _Above ZDepth Top Bottom Front BAck Left Right X Y Z Prev Undo")
    (if disp
      (setq disp nil)
      (setq pt (getpoint
         nullbase
         "\nУкажите следующую вершину или [Выше/ZПск/сВЕрху/сНИзу/сПЕреди/сЗАди/сЛЕва/сПРава/X/Y/Z/Предыдущая/Отменить] <Конец>: "
               )
      ); setq.
    ); end if.
    (cond
      ((not pt)); конец построений.
      ((listp pt); указана точка:
       (setq actions (append (list (cons T (read-ucs))) actions))
       (command "_.ucs" "_Origin" pt)
       (cond
     (brol; добавляем новую вершину:
      (vlax-invoke-method brol 'AppendVertex (vlax-3d-point (trans nullbase 1 0)))
      (vlax-invoke-method brol 'update)
      );
     (T; создаем полилинию из 2х вершин:
      (setq brol (vlax-invoke-method
               ::model_space
               'Add3Dpoly
               (vlax-make-variant
             (vlax-safearray-fill
               (vlax-make-safearray vlax-vbdouble '(0 . 5))
               (append pt1 (trans nullbase 1 0))
               )
             (+ vlax-vbarray vlax-vbdouble)
               );
             );
      ); setq.
     );
       ); end cond.
      );
      ((= pt "ZDepth"); указание на смещение ПСК вдоль оси Z:
       (while (not disp)
     (initget 128)
     (setq disp (getpoint "\nСмещение по Z для начала новой ПСК: "))
     (cond
       ((not disp) (princ "\nНеверный ввод. Пожалуйста повторите.")); пустой ввод. Повтор.
       ((listp disp) (setq disp (caddr disp)));
       ((numberp (setq disp (atof disp))));
       (T (princ "\nНеверный ввод. Пожалуйста повторите.") (setq disp nil));
     ); end cond.
       ); end while.
       (setq actions (append (list (cons nil (read-ucs))) actions))
       (command "_.ucs" "_Move" "_Zdepth" disp)
       (setq disp nil)
      );
      ((= pt "Above"); указание на построение следующей вершины смещением предыдущей по оси Z:
       (while (not disp)
     (initget 128)
     (setq disp (getpoint "Расстояние по Z для следующей вершины: "))
     (cond
       ((not disp) (princ "\nНеверный ввод. Пожалуйста повторите.")); пустой ввод. Повтор.
       ((listp disp) (setq disp (caddr disp)));
       ((numberp (setq disp (atof disp))));
       (T (princ "\nНеверный ввод. Пожалуйста повторите.") (setq disp nil));
     ); end cond.
       ); end while.
       (setq pt (list 0.0 0.0 disp))
      );
      ((wcmatch pt "[XYZ]"); поворот вокруг оси:
       (setq ang (getreal (strcat "\nУгол поворота вокруг оси " pt " <0.0>: ")))
       (cond
     (ang
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (command "_.ucs" (strcat "_" pt) ang)
     );
       ); end cond.
      );
      ((or (wcmatch (substr pt 1 1) "[TBFLRW]") (= pt "BAck"))
       (setq actions (append (list (cons nil (read-ucs))) actions))
       (setq org (getvar 'ucsorg))
       (setvar 'ucsicon 0)
       (command "_.ucs" (strcat "_" pt))
       (setq org (trans org 0 1))
       (command "_.ucs" "_Origin" org)
       (setvar 'ucsicon icon)
      );
      ((= pt "Prev")
       (setq pt 0)
       (setq act (car actions))
       (while (and act (equal
             (list (getvar 'ucsxdir) (getvar 'ucsydir))
             (list (mapcar '- (caddr act) (cadr act)) (mapcar '- (cadddr act) (cadr act)))
             1e-9; точность сравнения.
               );
          ); and.
     (setq pt (1+ pt))
     (setq act (nth pt actions))
       ); end while.
       (cond
     (act; найдена ПСК в списке отката, которая отличается от текущей:
      (setq org (getvar 'ucsorg))
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setq org (trans org 0 1))
      (command "_.ucs" "_Origin" org)
      (setvar 'ucsicon icon)
     );
     (T (princ "Все предыдущие ПСК не отличаются от текущей ПСК."));
       ); end cond.
      );
      ((= pt "Undo"); отмена последнего действия:
       (setq act (car actions)); последнее зафиксированное действие.
       (setq actions (cdr actions))
       (cond
     ((car act); последним действием была добавлена вершина полилинии:
      (setq coords (reverse (vlax-safearray->list (vlax-variant-value (vlax-get-property brol 'coordinates)))))
      (cond
        ((= (length coords) 6); полилиния из oдного сегмента:
         (vlax-invoke-method brol 'delete)
         (vlax-release-object brol)
         (setq brol nil)
        );
        (T; полилиния из 2х и более сегментов:
         (vlax-invoke-method brol 'delete)
         (vlax-release-object brol)
         (setq coords (reverse (cdddr coords)))
         (setq brol (vlax-invoke-method
              ::model_space
              'Add3Dpoly
              (vlax-make-variant
                (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble (cons 0 (1- (length coords)))) coords)
                (+ vlax-vbarray vlax-vbdouble)
              );
            );
         ); setq.
        );
      ); end cond.
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
     );
     (actions; изменялась только ПСК и список отката не пустой:
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
     );
     (T
      (setvar 'ucsicon 0)
      (command "_.ucs" "_World" "_.ucs" "_3point" (cadr act) (caddr act) (cadddr act))
      (setvar 'ucsicon icon)
      (setq pt (getpoint "\nУкажите первую вершину <Enter-Отказ>: "))
      (if (not pt) (quit));
      (setq pt1 (trans pt 1 0))
      (setq actions (append (list (cons nil (read-ucs))) actions))
      (command "_.ucs" "_Origin" pt)
     );
       ); end cond.
      );
    ); end cond.
  ); end while.
  (princ)
); end defun.

И ещё!
Десятая строка снизу.
В русской версии:

(setq pt1 (trans pt 1 0))

В английской, там же, отсутствует по недосмотру!
Буду признателен АДМИНИСТРАТОРУ, если он внесет исправление в код.

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> Пастух
Вы видимо не заметили новую возможность внесения исправлений в код. Обратите внимание на иконку с карандашиком в начале каждого сообщения (справа).

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> [Re:] Александр Ривилис
У меня не отображается никакой иконки!

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> Пастух
Включи у себя отображение картинок, у меня в опере при отключенных картинках, тоже не видно ни каких кнопок...

Re: LISP. Удобная команда построения 3-х мерной полилинии.

> Пастух
Она выглядит:
http://www.autocad.ru/images/edit.gif