Re: вычисление списка точек на объекте расстояния между которыми равны

> Евгений Елпанов
Метод бисекции

Re: вычисление списка точек на объекте расстояния между которыми равны

> Евгений Елпанов

> CB
Опробовал ваши варианты -
восхитился превосходству в скорости !!!
правда у кого лучше у Евгения Елпанова или CB понять так и не смог (((
Спасибо!

Re: вычисление списка точек на объекте расстояния между которыми равны

Господа профессионалы, а не сможете ли подкорректировать код таким образом, чтобы вместо одного фиксированного расстояния был бы список расстояний через которые нужно размечать выбранный объектну например (1000 200 100)?

Re: вычисление списка точек на объекте расстояния между которыми равны

(defun test (/ test test1 pl)
  (defun test (a b f d p)
    (if (= a b)
      nil
      ((lambda (r)
         (if (equal (f r p) 0. d)
           r
           (if (minusp (* (f a p) (f r p)))
             (test a r f d p)
             (test r b f d p)
           ) ;_  if
         ) ;_  if
       ) ;_  lambda
        (/ (+ a b) 2.)
      )
    ) ;_  if
  ) ;_  defun
  (defun test1 (par step)
    (if par
      (cons (vlax-curve-getPointAtParam pl par)
            (test1 (test
                     par
                     (vlax-curve-getEndParam pl)
                     (lambda (x y)
                       (- (car step)
                          (distance (vlax-curve-getPointAtParam pl y)
                                    (vlax-curve-getPointAtParam pl x)
                          ) ;_ end of distance
                       ) ;_ end of -
                     ) ;_ end of lambda
                     1e-6
                     par
                   ) ;_ end of test
                   (if (cdr step)
                     (cdr step)
                     lst-step
                   ) ;_ end of if
            ) ;_ end of test1
      ) ;_ end of cons
    ) ;_ end of if
  ) ;_ end of defun
  (if (and
        (setq pl (vlax-ename->vla-object
                   (car (entsel "\nВыберите pline: "))
                 ) ;_ end of vlax-ename->vla-object
        ) ;_ end of setq
;;;        (setq step (getreal "\nВедите шаг: "))
      ) ;_ end of and
    (test1 (vlax-curve-getStartParam pl) lst-step)
  ) ;_ end of if
) ;_ end of defun
;;;(setq lst-step '(5 10 5))
;;;(test)

Re: вычисление списка точек на объекте расстояния между которыми равны

Плохо, что на этом форуме нельзя корректировать свои сообщения, поэтому новый, более корректный вариант:

(defun test (lst / test test1 pl)
  (defun test (a b f d p)
    (if (= a b)
      nil
      ((lambda (r)
         (if (equal (f r p) 0. d)
           r
           (if (minusp (* (f a p) (f r p)))
             (test a r f d p)
             (test r b f d p)
           ) ;_  if
         ) ;_  if
       ) ;_  lambda
        (/ (+ a b) 2.)
      )
    ) ;_  if
  ) ;_  defun
  (defun test1 (par step)
    (if par
      (cons (vlax-curve-getPointAtParam pl par)
            (test1 (test
                     par
                     (vlax-curve-getEndParam pl)
                     (lambda (x y)
                       (- (car step)
                          (distance (vlax-curve-getPointAtParam pl y)
                                    (vlax-curve-getPointAtParam pl x)
                          ) ;_ end of distance
                       ) ;_ end of -
                     ) ;_ end of lambda
                     1e-6
                     par
                   ) ;_ end of test
                   (if (cadr step)
                     (cdr step)
                     lst
                   ) ;_ end of if
            ) ;_ end of test1
      ) ;_ end of cons
    ) ;_ end of if
  ) ;_ end of defun
  (if (and (setq pl (car (entsel "\nВыберите pline: ")))
           (setq pl (vlax-ename->vla-object pl))
      ) ;_ end of and
    (test1 (vlax-curve-getStartParam pl) lst)
  ) ;_ end of if
) ;_ end of defun
;;;(test '(5 10 5))

Re: вычисление списка точек на объекте расстояния между которыми равны

> CB
Проверил, работает !!
Супер !!!
Единственное, окончательный список точек пришлось преобразовать функцией trans в текущую систему координат.
Все выше приведенные программы размечают выбранные объекты по методу "MEASURE" вот бы добавить еще одну по методу "DIVIDE"
т. е. функцию в которой в качестве аргумента было бы задано колическтво частей, а на выходе список координат точек деления, расстояния между которыми равны.
Конечно если это возможно.
Тогда наверное тема была бы полностью закрыта.

Re: вычисление списка точек на объекте расстояния между которыми равны

> Student
нарисуй сплайн змейкой, подели его на несколько частей методом "DIVIDE", хотя бы на три части и расскажи, как ты это сделал. Единственное условие, части должны быть равные до некоторой точности. Потом можно будет говорить о программах...
Все дело в том, что во многих случаях, такая задача не имеет решений.

Re: вычисление списка точек на объекте расстояния между которыми равны

> Student
вот немного измененный вариант от ЕЕ и мой кусок

(vl-load-com)
(defun test (e b f i / D D1 ED L)
  (setq    d1 b
    l  (cons (vlax-curve-getStartPoint e) l)
    ed (vlax-curve-getDistAtParam e (vlax-curve-getEndParam e))
  )
  (while (and (< d1 ed) (< (length l) i))
    (while (and    (< d1 ed)
        (> (setq d
              (- b (distance (car l) (vlax-curve-getPointAtDist e d1)))
           )
           f
        )
       )
      (setq d1 (+ d d1))
    )
    (setq l  (cons (vlax-curve-getPointAtDist e (+ d d1)) l)
      d1 (+ d1 b)
    )
  )
  l
)
(defun test1 (EntName Count / Dist EndPoint OutList Step OK)
  (setq    Step     0.01
    Dist     0.0
    EndPoint (vlax-curve-getEndPoint EntName)
  )
  (print
    (while (and    (= (length (setq OutList (test EntName
                           (setq Dist (+ Dist Step))
                           1e-6
                           Count
                     )
               )
           )
           Count
        )
        (not (setq OK (equal (distance (car OutList) EndPoint)
                     Dist
                     (* Count Step)
                  )
             )
        )
       )
    )
  )
  (if OK
    (cons EndPoint OutList)
  )
)

у вас какая частота процессора? надо побольше :)
или нужно оптимизировать мой код.

> Евгений Елпанов
очень долго не мог нарисовать полилинию, на которой сработал бы мой лисп :)
вот она любимая/единственная:

(entmake '((0 . "LWPOLYLINE")
       (100 . "AcDbEntity")
       (100 . "AcDbPolyline")
       (90 . 5)
       (70 . 0)
       (10 182.073 250.062)
       (10 220.283 214.23)
       (10 251.215 221.324)
       (10 287.788 205.5)
       (10 327.818 219.323)
    
      )
)
(foreach p (test1 (entlast) 3)
  (entmake (list (cons 0 "POINT") (cons 10 p)))
)

>Student
бросайте вы это дело :)

Re: вычисление списка точек на объекте расстояния между которыми равны

> Vovka
Программа задумалась, но отработала!
" у вас какая частота процессора? надо побольше :)
или нужно оптимизировать мой код.
"
Может у Евгения или СВ получится оптимизировать.

> Евгений Елпанов
" нарисуй сплайн змейкой, подели его на несколько частей методом "DIVIDE", хотя бы на три части и расскажи, как ты это сделал."
Обычно я просто применяю команду Divide.
" Все дело в том, что во многих случаях, такая задача не имеет решений. "
Но у ведь программа от Vovka (2008-10-09 00:51:18)справилась, только не быстро(((
А алгоритм наверное сл.:
- поделить общую длину объекта на кол-во частей получив отсчетный шаг.
- Этим шагом разметить объект предыдущим алгоритмом и если последняя вычисленная точка не совпадает с конечной точкой объекта то откорректировать шаг и поновой пока последняя вычесленная точка не совпадет с конечной точкой объекта.
Важно наверное только правильно применить метод бисекции, чтобы как и в предыдущем алгоритме реализовалась высокая скорость выполнения программы.

Re: вычисление списка точек на объекте расстояния между которыми равны

> Student
а можно поинтерисоваться для каких прикладных целей вы используете эти функции?
если точность не важна а нужна скорость, то вместо 1e-6 можно написать что-то побольше (быстрее для дуг и сплайнов), и значение Step можно увеличить.
в случае оптимизации ее значение вожно брать изначально большое, а при приближении к желаемому (изменения длины OutList) результату уменьшать и переключать знак.
p.s. print нужно убрать, использовался для тестирования, недоглядел :(

Re: вычисление списка точек на объекте расстояния между которыми равны

p.p.s. то что моя функция "справилась" - это скорее счастливое исключение :)

Re: вычисление списка точек на объекте расстояния между которыми равны

Student пишет:

Обычно я просто применяю команду Divide.

Попробуй на таком примере

(entmakex '((0 . "LWPOLYLINE")
           (100 . "AcDbEntity")
           (100 . "AcDbPolyline")
           (90 . 3)
           (90 . 3)
           (70 . 0)
           (10 406.78 363.185)
           (10 911.002 493.005)
           (10 515.048 493.005)
          )
)

Подели на две равные части, про точность не говорю, хотя бы на глазок...

Re: вычисление списка точек на объекте расстояния между которыми равны

> Vovka
"а можно поинтерисоваться для каких прикладных целей вы используете эти функции?"
например для ограждений - есть стандартные секции ограждения определенной длины и необходимо их расставить по криволинейному пути.
Для распределения отделочных стеновых панелей по криволинейным стенам.
если панели или секции определяются типоразмером то использую метод "Measure", если может быть любой но желательно равный то "Divide"

Re: вычисление списка точек на объекте расстояния между которыми равны

> Евгений Елпанов
"Подели на две равные части, про точность не говорю, хотя бы на глазок..."
Поделилась!!!  На две части )))
Но на 3, 4 не стала (((
тестировал -

(defun c:ttt ()
   (princ "\nДля преобразование кривой в 3DPolyline с равными сегментами ")
   (setq _e  (car(entsel))  )
   (setq
       _s (getint "\nКоличество сегментов? ")
   )
   (setq _sp (test1 _e _s ))
   (print _sp)
   (command "_3dpoly")
   (foreach XXX _sp (command XXX))
   (command "")
)

результат -

Command: ttt
Для преобразование кривой в 3DPolyline с равными сегментами
Select object:
Количество сегментов? 2
nil
((515.048 493.005 0.0) (507.602 389.143 0.0) (406.78 363.185 0.0)) nil
Command: ttt
Для преобразование кривой в 3DPolyline с равными сегментами
Select object:
Количество сегментов? 3
*Cancel*
bad argument type: 2D/3D point: nil
Command: ttt
Для преобразование кривой в 3DPolyline с равными сегментами
Select object:
Количество сегментов? 4
nil
nil
Invalid point.

> Vovka
p.p.s. то что моя функция "справилась" — это скорее счастливое исключение :)
У меня большинстве случаев справилась.
Уже приятно ))))
Неужели действительно нет 100%го решения?

Re: вычисление списка точек на объекте расстояния между которыми равны

> Student
А ты посмотрел, что получилось? Тебя этот результат устраивает?

Re: вычисление списка точек на объекте расстояния между которыми равны

> Евгений Елпанов
А ты посмотрел, что получилось?
получилось два сегмента
один 104.11
другой 104.1285
точка деления лежит на исходной полилинии
Тебя этот результат устраивает?
если работаешь в милиметрах (проектирование зданий, сооружений, интерьеров)
несовпадения длин составляет 0.0185 мм
если работаешь в метрах (генплан)
несовпадения длин составляет 18.5 мм
по точности устраивает
раз точка деления на исходном объекте значит требование к делению выполнено значит то же устраивает
А то, что полученная полилиния сильно отличается от исходной так это ничего страшного
при проектировании или исходную кривую (полилинию, сплайн, дугу, эллипс) придется откорректировать или манипулировать количеством сегментов, исходя из эстетических или каких либо других соображений

Re: вычисление списка точек на объекте расстояния между которыми равны

Student пишет:

получилось два сегмента
один 104.11
другой 104.1285

И не смущает, что если поделить этот контур на одинаковые сегменты с длинной 104.11 то получится девять, а не два сегмента?

Re: вычисление списка точек на объекте расстояния между которыми равны

> Евгений Елпанов
" И не смущает, что если поделить этот контур на одинаковые сегменты с длинной 104.11 то получится девять, а не два сегмента? "
Поскольку количество сегментов задает пользователь то естественно если нужно разделить примерно через 104 то вводиться будет 9 а не 2.
но при 9 функция не работает (видимо из-за несовершенства алгоритма (((
Что заметил -
если правую вершину полилинии сместить в середину горизонтального сегмента функция отработает для 2х и 3х сегментов
если еще на половину то для 2,3,4
вывод
- функция имеет ограничения по выполнению, которые можно обойти экспериментальным путем.
Хотелось бы конечно более совершенный алгоритм или сообщения функции о невозможности выполнения по тем или иным причинам.
Одно пока ясно, что функцию от Vovka буду применять до появления более совершенной.

Re: вычисление списка точек на объекте расстояния между которыми равны

> Student
Одно пока ясно, что функцию от Vovka буду применять до появления более совершенной.

Ты упорно отказываешься объяснить, что надо и как, в моем понимании, результат с моим примером недопустим, а для тебя он подходит...
Лучше расскажи, как должна работать программа в общем случае и в частных тоже.
Про однозначный результат, я уже писал, он не всегда возможен.

Re: вычисление списка точек на объекте расстояния между которыми равны

> Евгений Елпанов
Беру тайм-аут до завтра.

Re: вычисление списка точек на объекте расстояния между которыми равны

> Евгений Елпанов
" Лучше расскажи, как должна работать программа в общем случае и в частных тоже. "
Одна из практических задач.
Исходные данные -
1. Инеются два типа отделочных стеновых панелей
первый тип панелей имеет фиксированную длину (например 1000м.) и укорачивать ее нелья
второй тип панелей не привязан к фиксированной длине (они могут нарезаться в зависимости от требуемой длины)
2. имеется на чертеже сложный контур проектируемой стены (с линейными и криволинейными участками)
Задача 1
Распределить отделочные панели первого типа с фиксированной длиной (1000м.) вдоль контура стены.
при этом можно игнорировать последний участок стены если он не равен 1000 м. (т.к. он будет отделан индивидуальной панелью)
Задача 2
Распределить отделочные панели второго типа с примерной длиной (1000м.) вдоль контура стены.
----------------
Учитывая, что стена(перегородка) проектируемая,
проектировщик может изменять ее контур в зависимости от характера распределения панелей
----------------
Первая задача решается, мне кажется "на ура", при помощи функций от Евгения и СВ
А вторая в ряде случаев решается при помощи функции от Vovka. Если контур без сильных изломов, то пока все срабатывает. Попробовал поделить эллипс (как полилинейный так и математический) получилось что-то непонятное ((
Отрезал половину сработало как надо.
--------------------

Re: вычисление списка точек на объекте расстояния между которыми равны

> Евгений Елпанов
" Все дело в том, что во многих случаях, такая задача не имеет решений. "
похоже это действительно так (((
Попробовал на вашей полилинии добиться деления на 9 равных частей используя вашу функцию и функцию СВ пытаясь манипулировать длиной сегмента, ничего не получилось (((

Re: вычисление списка точек на объекте расстояния между которыми равны

> Student
Если углубиться в математику, то можно пойти другим путем - можно заранее вычислить график возможных решений. Это сложная система уравнений с размерностью, равной количеству прямолинейных сегментов. Дуговые, нужно будет заранее аппроксимировать с необходимой точностью но максимальной длинной...
ps. Данную задачку никогда не решал.

Re: вычисление списка точек на объекте расстояния между которыми равны

> [Re:] Student
Изменил алгоритм для задачи 1. Я думаю, что теперь функция справится с любой конфигурацией полилинии или сплайна, но увы... за счет потери скорости, причем на порядок...

(defun test (step / test test1 f pl EndParam)
  (vl-load-com)
  (defun test (a b f d x)
    (if (= a b)
      nil
      ((lambda (r)
         (if (equal (f r x) 0. d)
           r
           (if (minusp (* (f a x) (f r x)))
             (test a r f d x)
             (test r b f d x)
           ) ;_ end of if
         ) ;_ end of if
       ) ;_ end of lambda
        (/ (+ a b) 2.)
      )
    ) ;_ end of if
  ) ;_ end of defun
  (defun test1 (par dist c n)
    (cond
      ((equal par c)
       (test1 (test par n f 1e-6 par) step par n)
      )
      (par
       (cons
         (vlax-curve-getPointAtParam pl par)
         (test1 (test par n f 1e-6 par) step par n)
       ) ;_ end of cons
      ) ;_ end of par
      ((equal n EndParam) nil)
      (t (test1 c step c (if (> (1+ n) EndParam) EndParam (1+ n))))
    ) ;_ end of cond
  ) ;_ end of defun
  (setq f
         (lambda (x y)
           (- step
              (distance
                (vlax-curve-getPointAtParam pl y)
                (vlax-curve-getPointAtParam pl x)
              ) ;_ end of distance
           ) ;_ end of -
         ) ;_ end of lambda
  ) ;_ end of setq
  (if (and
        (setq pl (vlax-ename->vla-object
                   (car (car (entsel "\nВыберите pline: "))
                 ) ;_ end of vlax-ename->vla-object
        ) ;_ end of setq
        (setq EndParam (vlax-curve-getEndParam pl))
      ) ;_ end of and
    (test1 0.0 step 1. 1.)
  ) ;_ end of if
) ;_ end of defun
;;;Проверка
(mapcar
  '(lambda (x)
     (entmakex
       (list '(0 . "CIRCLE") '(62 . 1) (cons 10 x) '(40 . 1.0))
     ) ;_ end of entmakex
   ) ;_ end of lambda
  (test 10)
) ;_ end of mapcar

Проверка на скорость

#<VLA-OBJECT IAcadSpline 0106cc24>
(vlax-curve-getEndParam pl) -> 170.154
    (TEST-OLD PL)......1993 / 20.54 <fastest>
    (TEST 10 PL)......40929 / 1 <slowest>
#<VLA-OBJECT IAcadLWPolyline 0106b5d4>
(vlax-curve-getEndParam pl) -> 128.0
    (TEST-OLD PL)......1282 / 12.69 <fastest>
    (TEST 10 PL)......16273 / 1 <slowest>

По задаче 2, что то даже алгоритм решения пока смутно представляю...