Тема: Как добавить вершину в полилинию нажатием одной кнопки?

Возможно ли добавлять вершину в полилинию путем нажатия одной кнопки, подобно Break at Point, только не разрывая линию? Путем редактирования полилинии (PEDIT-Edit Vertex-Insert) получается слишком муторно.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Вот такая конструкция:

(vl-cmdf "_PEDIT" pause "_E" "_I" pause "_X" "")

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

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Так вот в этом и проблема.. а если вершин много? 20-30 например. Конкретная задача - трассировка нагорной канавы. Допустим мне нужно приблизить дно канавы к определенному уклону, для этого требуется изогнуть канаву в определенном месте рельефа. Добавляю вершину. Я нажимаю Break at Point, рву полилинию в нужном месте, потом склеиваю. Так быстрее получается, нежели до этой вершины скакать, а потом втыкать ее.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Можно попробовать лиспом:

;|=============================================================================
*    Функция разрыва полилинии и одновременной передвижки новой вершины.
* Полилиния не меняет следующих свойств: цвет, слой, тип.
*    Ограничения:
*    1. Не производится отлов ошибок ввода (никто не запрещает работать с арками и
*    окружностями)
*    2. Не производится отлов нажатия Esc - не выполняется восстановление
*    системных переменных. Обработчик ошибок писать просто некогда.
*    3. Не производится проверка usc, в которой работает пользователь.
*    4. Неправильное указание точки (не принадлежащей объекту) может свалить
*    функцию в ноль.
*    5. Не отслеживается "заморозка" слоя.
*    6. Не отслеживается вариант, когда указывается пересечение двух объектов -
*    в таком случае работа непредсказуема.
*    Функция тестировалась на ADT 2005, usc = world.
*
*    Функцию желательно сохранить в файл kpblc-stretch-pline.lsp. Файл должен
* быть сохранен в путях поддержки AutoCAD.
*    Возможный макрос для вызова:
^C^C(if (not "c:kpblc-stretch-pline") (load "kpblc-stretch-pline.lsp"));c:kpblc-stretch-pline;
=============================================================================|;
(defun c:kpblc-stretch-pline ( / break_point _osmode_ selset_oper)
  (setq _osmode_ (getvar "osmode")) ;_ end of setq
  (setvar "osmode" 512)
  (setq    break_point (getpoint "\nУкажите точку разрыва : ")
    selset_oper (ssget break_point)
    ) ;_ end of setq
  (command "_.break" selset_oper break_point break_point)
  (command "_.pedit" "_M" "_C" break_point break_point "" "_join" 0 "")
  (command "_.stretch" "_C" break_point break_point "")
  (setvar "osmode" 1)
  (while (/= (getvar "cmdactive") 0)
    (command pause)
    ) ;_ end of while
  (setvar "osmode" _osmode_)
  (princ)
  ) ;_ end of defun
;;; Конец файла kpblc-stretch-pline.lsp

Как вариант, не более. Для нормальной работы можно еще массу всего понаворотить.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> Azor
Попробуй такую фичу, указывать полилинию нужно
на том участке, где будет добавлена вершина
~'J'~

;; Вспомогательные функции
;; Группировка списка по числу элементов субсписка
(defun group-by-num (lst num / ls ret)
  (if (= (rem (length lst) num ) 0)
    (progn
      (setq ls nil)
      (repeat (/ (length lst) num)
    (repeat num (setq ls
            (cons (car lst) ls)
          lst (cdr lst)))
    (setq ret (append ret (list (reverse ls)))
          ls nil)))
    )
ret
  )
;; Голова списка по номеру:
(defun head (lst num )
    (if (< 0 (1- num))
      (cons (car lst) (head (cdr lst) (1- num)))))
;; Хвост списка по номеру:
(defun tail (lst num / )
(if (> (length lst) (1- num ))
(append (tail (reverse (cdr (reverse lst))) num)
    (list (last lst)))))
;; Добавление элемента в список по номеру позиции
(defun add-elt (lst num elt)
(if elt
    (append (head lst num)
          (cons  elt (tail lst num)))))
;; Создание и заполнение безопасного массива точек
(defun safe-points (lst / pt_list points)
  (setq pt_list (apply 'append lst))
  (setq    points (vlax-safearray-fill
         (vlax-make-safearray
           vlax-vbdouble
           (cons 0 (1- (length pt_list)))
         )
         pt_list
           )
  )
  )
;; Обработсик ошибок с пошаговым возвратом
(defun div-error (msg)
  (if
    (vl-position
      msg
      '("console break"
    "Function cancelled"
    "quit / exit abort"
       )
    )
     (princ "Error!")
     (princ msg)
  )
  (while (> (getvar "cmdactive") 0) (command))
  (command "._undo" "_end")
  (command "._u")
  (setq *error* olderror)
  (princ)
)
(vl-load-com)
(prompt "\n    ***    Type ADV to execute    *** \n")
;;    ОСНОВНАЯ ПРОГРАММА    ;;
(defun C:adv (/    *error*     acsp      adoc       appd        coord
           div-error     new_pl      olderror pl        pn
           pt    pt_list     seg_num  util
          )
  (or adoc
      (setq adoc
         (vla-get-activedocument
           (vlax-get-acad-object)
         )
      )
  )
  (or appd (setq appd (vla-get-application adoc)))
  (or acsp
      (setq acsp
         (vla-get-block
           (vla-get-activelayout adoc)
         )
      )
  )
  (or util (setq util (vla-get-utility adoc)))
  (command "._undo" "_end")
  (command "._undo" "_mark")
  (setq olderror *error*)
  (setq *error* div-error)
  (vla-getentity
    util
    'pl
    'pt
    "\nSelect polyline to add vertex: >>> \n"
  )
  (if pl
    (progn
      (setq pn (trans (getpoint "\nSpecify new vertex location: >>> \n") 1 0))
      (setq coord (vlax-get pl 'Coordinates)
        coord
          (cond
            ((eq (rem (length coord) 2) 0)
             (group-by-num coord 2)
            )
            ((eq (rem (length coord) 3) 0)
             (group-by-num coord 3)
            )
            (T nil)
          )
        coord (mapcar (function (lambda (x)
                      (trans x 1 0))) coord)
      )
      (setq
    seg_num    (+ (fix (vlax-curve-getparamatpoint
               pl
               (osnap (vlax-safearray->list pt) "_nea")
             )
            )
           2
        )
    )
      (setq coord (add-elt coord seg_num pn))
      (setq pt_list (safe-points coord))
      (setq new_pl (vla-addpolyline acsp pt_list))
      (vla-delete pl)
      (mapcar (function    (lambda    (x)
              (if (not (vlax-object-released-p x))
                (vlax-release-object x)
              )
            )
          )
          (list pl new_pl)
      )
    )
    (princ "\nNothing selected try again\n")
  )
  (vla-zoomextents appd)
  (vla-regen adoc acactiveviewport)
  (setq    *error*    olderror
    div-error nil
  )
  (command "._undo" "_end")
  (princ)
)
(C:adv)
(princ)

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> Олег(jr.)
Интересная программа.
Вершины вставляются там, где надо, только замкнутая полилиния размыкается со стиранием замыкающего сегмента, а дуговые сегменты заменяются линейными...

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> kpblc
Непонятно, что делать после указания точки разрыва?

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> Владимир Громов
Тащить новую вершину на нужное место. На ней (на вершине) просто надо дополнительно щелкнуть - не удалось мне слету указать ее для stretch'a.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Упустил из виду: если таскать сразу не требуется, надо будет закомментировать строки

  (command "_.stretch" "_C" break_point break_point "")
  (setvar "osmode" 1)
  (while (/= (getvar "cmdactive") 0)
    (command pause)
    ) ;_ end of while

Т.е. перед ними поставить ;;

Re: Как добавить вершину в полилинию нажатием одной кнопки?

В Toolpac-е есть такая функция:
указываешь курсором место новой вершины, потом - сегмент, который разрывается и дотягивается до неё. Там же есть и опция удаления ненужной вершины. Toolpac > Polyline > Vertex > ... Только после этих операций ассоциативность этой плинии теряется, так что контуры штриховок я меняю по старинке, pedit-ом.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> shishoq
Ну на этот предмет не тестировал. Но и у меня тоже ассоциативность рушится. Надо по новой штриховать. За компанию: если полилиния служила обрамлением wipeout, его понадобится перестраивать.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

а нельзя ли написать фичу на основе PEDIT ,чтобы не портила ассоциативность?

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Немного подправленный мой код (автоматически после указания точки разрыва идет требование указать новое положение точки):

;|=============================================================================
*    Функция разрыва полилинии и одновременной передвижки новой вершины.
* Полилиния не меняет следующих свойств: цвет, слой, тип.
*    Ограничения:
*    1. Не производится отлов ошибок ввода (никто не запрещает работать с арками и
*  окружностями)
*    2. Не производится отлов нажатия Esc - не выполняется восстановление
*  системных переменных. Обработчик ошибок писать просто некогда.
*    3. Не производится проверка usc, в которой работает пользователь.
*    4. Неправильное указание точки (не принадлежащей объекту) может свалить
*  функцию в ноль.
*    5. Не отслеживается "заморозка" слоя.
*    6. Не отслеживается вариант, когда указывается пересечение двух объектов -
*  в таком случае работа непредсказуема.
*    Функция тестировалась на ADT 2005, usc = world.
*
*    Функцию желательно сохранить в файл kpblc-stretch-pline.lsp. Файл должен
* быть сохранен в путях поддержки AutoCAD.
*    Возможный макрос для вызова:
^C^C(if (not "c:pline-str") (load "kpblc-stretch-pline.lsp"));c:pline-str;
=============================================================================|;
(defun kpblc-stretch-pline (/ break_point _osmode_ selset_oper)
  (setq _osmode_ (getvar "osmode")) ;_ end of setq
  (setvar "osmode" 512)
  (setq    break_point (getpoint "\nУкажите новую вершину : ")
    selset_oper (ssget break_point)
    ) ;_ end of setq
  (command "_.break" selset_oper break_point break_point)
  (command "_.pedit" "_M" "_C" break_point break_point "" "_join" 0 "")
  (command "_.stretch" "_C" break_point break_point "" break_point)
  ;;(command (list break_point) pause)
  ;|(while (/= (getvar "cmdactive") 0)
    (command pause)
    ) ;_ end of while
    |;
  (setvar "osmode" _osmode_)|;
  (princ)
  ) ;_ end of defun
(defun c:pline-str()
  (kpblc-stretch-pline)
  ) ;_ end of defun
;;; Конец файла kpblc-stretch-pline.lsp

> shishoq : у меня не получилось. Может, у Олега (jr) выйдет?

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Тьфу ты, там в коде надо снести закомментрованные строки (command (list...)) и (while...);_end of while.
Хотя с другой стороны они не мешают.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Так, все. 2 предыдущих поста можно сносить. Здес окончательный вариант:

;|===================================================================
*    Функция разрыва полилинии и одновременной передвижки новой вершины.
* Полилиния не меняет следующих свойств: цвет, слой, тип.
*    Ограничения:
*    1. Не производится отлов ошибок ввода (никто не запрещает работать с арками и
*  окружностями)
*    2. Не производится отлов нажатия Esc - не выполняется восстановление
*  системных переменных. Обработчик ошибок писать просто некогда.
*    3. Не производится проверка usc, в которой работает пользователь.
*    4. Неправильное указание точки (не принадлежащей объекту) может свалить
*  функцию в ноль.
*    5. Не отслеживается "заморозка" слоя.
*    6. Не отслеживается вариант, когда указывается пересечение двух объектов -
*  в таком случае работа непредсказуема.
*    Функция тестировалась на ADT 2005, usc = world.
*
*    Функцию желательно сохранить в файл kpblc-stretch-pline.lsp. Файл должен
* быть сохранен в путях поддержки AutoCAD.
*    Возможный макрос для вызова:
^C^C(if (not "c:pline-str") (load "kpblc-stretch-pline.lsp"));c:pline-str;
===================================================================|;
(defun kpblc-stretch-pline (/ break_point _osmode_ selset_oper)
  (setq _osmode_ (getvar "osmode")) ;_ end of setq
  (setvar "osmode" 512)
  (setq    break_point (getpoint "\nУкажите новую вершину : ")
    selset_oper (ssget break_point)
    ) ;_ end of setq
  (command "_.break" selset_oper break_point break_point)
  (command "_.pedit" "_M" "_C" break_point break_point "" "_join" 0 "")
  (command "_.stretch" "_C" break_point break_point "" break_point)
  (setvar "osmode" _osmode_)
  (princ)
  ) ;_ end of defun
(defun c:pline-str()
  (kpblc-stretch-pline)
  )

Вроде сейчас все нормально.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> kpblc
Вроде все нормально, только если в ответ на запрос:

Вторая точка перемещения или <считать перемещением первую точку>:

нажать правую кнопку мыши, то получается какая-то ерунда, IMHO.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> Владимир Громов
Я тоже на это внимание обратил, но как побороть, даже не представляю. Что самое интересное, если дать просто _.stretch (с ком.строки), то все работает предсказуемо.
С другой стороны, а смысл сделать просто дополнительную вершину полилинии? Ее же, по условиям > Azor (2005-08-30 09:46:09), надо сразу двигать (имхо). Можно, конечно, сделать дополнительный запрос на "двигать вершину или плюнуть?" перед _.stretch, но лишние телодвижения... Если надо, сделать не проблема - только сообщите ;)

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Всем спасибо, благодарствую :)

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> kpblc
весьма полезная программка, и именно со стретчем. не нарадуюсь :)

> Олег(jr.)
когда втыкаю одну вершину - все ок, а при попытке поставить вторую - получается абракадабра.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> kpblc
Товарищ kpblc. А что, если ты эту программу отправишь в раздел "Готовые программы"? Мне нравится, несмотря на бяку с нажатием правой кнопки мыши, моим коллегам-архитекторам тоже придется по душе. Им часто приходится менять планировку помещений, а площадь они определяют по моей программе (площадь замкнутого контура). Частенько приходится контур рисовать заново, потому что надо добавить углы помещения, а, следовательно, и вершины в контуре.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

imho перед "готовностью программы" надо дополнительно, во-первых, сделать вариант на правую кнопку мыши (см. > kpblc (2005-08-31 08:34:06)), провести проверку на досрочный выход, обработку ошибок, провести обработку нештатной ситуации - попытка обработки отрезка, 3д-полилинии, окружности эллипса, полилинии в блоке / xref-e - тут же до дури всего можно придумать. Сейчас просто времени, к сожалению, нет - может, к вечеру поближе что-то и получится.
По поводу площади: можно сюда же засунуть дополнительно проверку на замкнутость полученной полилинии (dxf = 70), преобразовать ее в vlax-object и оттуда вытащить площадь, запросить точку вставки (кстати, тоже надо проверять ввод) и на этой точке сделать либо текст через entmake, либо вставить блок с текстовым атрибутом. Т.е. варианты есть - их только прорабатывать надо.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> kpblc
Ну, я вижу, ты точно хочешь придерживаться буквы закона: "Готовая программа" - значит готовая программа. Может, все-таки, с мнимальными доработками, а? И не сей секунд, конечно. Ведь хорошая программа, даже в таком виде. Потом, позже, программу можно усовершенствовать. А то эта тема (ведь чисто Лисп'овская) находится в таком разделе, который пополняется со страшнлй силой, и скоро она ушла бы уже во вторую сотню, если бы я ее не поднял.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Ок, тогда надо определить объем этих минимальных доработок. Чего там сделать-то надобно?
Мои предложения:
1. дополнительные вершины можно вставлять либо для lwpolyline, либо для отрезков (кстати, вопрос - был отрезок, стал полилинией, обратно в отрезки делать или нет? Или запрос?) - для остального (circle, ellipse, spline, 3d-polyline, block, xref...) вываливается (alert).
2. Досрочный выход не обрабатывается.
3. Площадь не выводится - тут помимо замкнутости надо еще дополнительно по идее обрабатывать варианты совпадения начальной и конечной вершин, а также вариант с самопересечением - _boundary лично мне что-то не очень - если lwpolyline нормальная, то команда создает дубль объекта, который для качественной функции надо сносить - лишние телодвижения.
4. Правая кнопка - что с ней делать? Т.е. для варианта отмены _.stretch чего творим?

Re: Как добавить вершину в полилинию нажатием одной кнопки?

> kpblc
Я пока и сам не знаю. Знаю только, что я ее и в таком виде буду использовать. Не хотелось мне, чтобы тема утонула. Я бы ограничился просто таким названием: "Добавление вершины в полилинию" без площадей, отрезков и т.п. Эта программа может работать сама по себе, а на ее основе можно потом что-то дальше развивать. Универсальность мне не всегда нравится, начальная идея может раствориться в самой универсальности, IMHO.

Re: Как добавить вершину в полилинию нажатием одной кнопки?

Ну ладно. В общем, тут несколько моментов сделано:

;|=============================================================================
*    Функция разрыва полилинии и одновременной передвижки новой вершины.
* Полилиния не меняет следующих свойств: цвет, слой, тип.
*    Ограничения:
*    1. Не производится отлов ошибок ввода (никто не запрещает работать с арками и
*  окружностями)
*    2. Не производится отлов нажатия Esc - не выполняется восстановление
*  системных переменных. Обработчик ошибок писать просто некогда.
*    3. Не производится проверка usc, в которой работает пользователь.
*    4. Неправильное указание точки (не принадлежащей объекту) может свалить
*  функцию в ноль.
*    5. Не отслеживается "заморозка" слоя.
*    6. Не отслеживается вариант, когда указывается пересечение двух объектов -
*  в таком случае работа непредсказуема.
*    Функция тестировалась на ADT 2005, usc = world.
*
*    Функцию желательно сохранить в файл kpblc-stretch-pline.lsp. Файл должен
* быть сохранен в путях поддержки AutoCAD.
*    Возможный макрос для вызова:
^C^C(if (not "c:pline-str") (load "kpblc-stretch-pline.lsp"));c:pline-str;
=============================================================================|;
(defun kpblc-stretch-pline (/ break_point _osmode_ selset_oper break_ent break_ent_type)
  ;; Определения локальных функций
  ;; Собственно разрыв и дополнительный одновременный _.stretch.
  ;; Параметры:
  ;; ent_pline    - ссылка на разрываемый объект, аналог (entsel)
  ;; ent_type    - тип объекта: nil -> lwpolyline; t -> line
  ;; объект обратно в LINE не разбивается
  (defun _kpblc-break-pline (ent-pline ent-type break-point)
    (command "_.break" ent_pline break-point break-point)
    (command "_.pedit" "_M" "_C" break-point break-point "")
    ;; Здесь определяем по ent_type - чего делать дальше
    (if    ent-type
      (command "_yes")
      ) ;_ end of if
    (command "_join" 0 "")
    ;; вот этот кусок у меня что-то не получился по-человечески.
    ;; по идее тут надо делать попытку на получение точки, но у меня не вышло.
    ;; в результате надо два раза кликать мышой для задания второго положения
    ;; новой вершины.
    (if (vl-catch-all-error-p
      (command "_.stretch" "_C" break-point break-point "" break-point pause))
      (command "_.stretch" "_C" break-point break-point "" break-point break-point)
      (command "_.stretch" "_C" break-point break-point "" break-point pause)
      )
;| В принципе, его можно закомментировать, оставив только строку
(command "_.stretch" "_C" break-point break-point "" break-point pause)
- тогда получим старое поведение функции.
|;
    ) ;_ end of defun
  ;; Конец определения локальных функций
  (vl-load-com)
  (if (not *kpblc-activedoc*)
    (setq *kpblc-activedoc* (vla-get-activedocument (vlax-get-acad-object)))
    )
  (vla-endundomark *kpblc-activedoc*)
  (vla-startundomark *kpblc-activedoc*)
  (setq    _osmode_ (getvar "osmode")
    ) ;_ end of setq
  (setvar "osmode" 512)
  (setq    break_point (getpoint "\nУкажите точку разрыва : ")
    selset_oper (ssget break_point)
    ) ;_ end of setq
  ;; Теперь проверка на вшивость - в смысле, на правильность выбора
  ;; Вынесено специально в отдельный setq, а также введена дополнительная
  ;; локальная переменная определения типа разрываемого объекта
  (setq    break_ent      (ssname selset_oper 0)
    break_ent_type (cdr (assoc 0 (entget break_ent)))
    ) ;_ end of setq
  (cond
    ((= break_ent_type "LWPOLYLINE")
     (progn
       (_kpblc-break-pline break_ent nil break_point)
       ) ;_ end of progn
     )
    ((= break_ent_type "LINE")
     (_kpblc-break-pline break_ent t break_point)
     )
    (t (alert "Добавить вершину к выбранному примитиву невозможно!"))
    ) ;_ end of cond
  (setvar "osmode" _osmode_)
  (vla-endundomark *kpblc-activedoc*)
  (princ)
  ) ;_ end of defun
(defun c:pline-str ()
  (kpblc-stretch-pline)
  ) ;_ end of defun
;;; Конец файла kpblc-stretch-pline.lsp

Обратите внимание, что сейчас если не указывать вторую точку новой вершины, то все нормально. А вот если указывать, то надо два раза щелкать мышой. Сделал на всякий случай и так, как получилось. Если у кого-то выйдет лучше, будет совсем замечательно.