1. ВНИМАНИЕ! В течении пары дней +- будет переезд форума на более защищённый сервер. Возможны перебои в работе.
    Скрыть объявление

Средняя точка (центр) для набора точек.

Тема в разделе "Autocad", создана пользователем zvezdochiot, 15 июн 2025.

  1. zvezdochiot

    zvezdochiot Форумчанин

    Привет всем.

    Для некоторых задач желательно иметь простенький lisp создающий среднюю точку (точку со средними координатами) для набора точек. Желательно, чтобы он соединял полученную точку с точками набора одной полилинией.
    Вполне возможно, что такой lisp давным-давно уже есть, но найти через яндексы не получается.

    Пример:
     

    Вложения:

    • 2midpoint.dwg
      Размер файла:
      162,6 КБ
      Просмотров:
      9
    Последнее редактирование: 15 июн 2025
    кит и wolodya нравится это.
  2. sokkol

    sokkol Форумчанин

    Работает только с точками (2D/3D), находит и создаёт среднюю точку, соединяет 3д полилиниями выбранные точки с средней точкой
    Код:
    (defun c:PointStar (/ ss ptList cnt sum midpt)
      (prompt "\nSelect POINT objects to connect: ")
      (setq ss (ssget '((0 . "POINT"))))
      
      (cond
        ((not ss) (princ "\nNo points selected."))
        ((< (sslength ss) 2) (princ "\nSelect at least 2 points."))
        (T
          (setq ptList 
            (vl-remove-if-not
              '(lambda (x) (eq (car x) 10))
              (apply 'append 
                (mapcar 'entget 
                  (vl-remove-if 'listp 
                    (mapcar 'cadr (ssnamex ss))
                  )
                )
              )
            )
          )
          
          (setq ptList (mapcar 'cdr ptList)
                cnt (length ptList)
                sum (apply 'mapcar (cons '+ ptList))
                midpt (mapcar '/ sum (list cnt cnt cnt)))
          
          (entmakex (list '(0 . "POINT") (cons 10 midpt)))
          
          (foreach pt ptList
            (entmakex
              (list
                '(0 . "POLYLINE")
                '(100 . "AcDb3dPolyline")
                '(66 . 1)
                '(10 0.0 0.0 0.0)
                '(70 . 8)
              )
            )
            (entmakex (list '(0 . "VERTEX") '(100 . "AcDb3dPolylineVertex") (cons 10 pt) '(70 . 32)))
            (entmakex (list '(0 . "VERTEX") '(100 . "AcDb3dPolylineVertex") (cons 10 midpt) '(70 . 32)))
            (entmakex '((0 . "SEQEND")))
          )
          (princ (strcat "\nCreated " (itoa cnt) " connections to midpoint."))
        )
      )
      (princ)
    )
    Сгенерировано Deepseek-ом, работоспособность проверена.
     
    chehoff и zvezdochiot нравится это.
  3. zvezdochiot

    zvezdochiot Форумчанин

    Попробовал на DWG.RU задать этот же вопрос, с ссылкой на этот. Чтобы посмотреть другие решения. Отказали, мол ответ уже есть.
    По-моему это как то "слегка" дурниной и тухлятиной попахивает: Ответ только один и другого быть не может? И DWG.RU такие рецепты не нужны?
    Возможно я не прав, но.... не уверен.

    Прикреплю lisp от @sokkol на всякий:
     

    Вложения:

    • PointStar.lsp
      Размер файла:
      1,3 КБ
      Просмотров:
      7
    chehoff нравится это.
  4. sokkol

    sokkol Форумчанин

    Алгоритм нахождения средней точки прост - суммируем отдельно X координаты и Y координаты выбранных точек и делим на их количество - получаем X и Y координаты усреднённой точки. Остальное дело техники / знания языка программирования. Таки да, для решения этой задачи не так уж и много вариантов :)
     
  5. zvezdochiot

    zvezdochiot Форумчанин

    Не так.
    То, что надо найти среднее - это в самом условии задачи сказано. Это не суть задачи.
    Ежели бы нахождение среднего было бы сутью, то бери калькулятор и считай среднее. Вот и вся задача.
    Суть задачи: Как взять точки? Как извлечь из них координаты? Как нарисовать посчитанную точку? Как нарисовать полилинию?
    Что то можно сделать строго определённым образом, а что то совершенно по разному.
     
  6. sokkol

    sokkol Форумчанин

    Перечисленные вами вопросы являются чисто техническими, с точки зрения программиста, и требуют знания методов, коими LISP обращается к примитивам AutoCad-а.

    Вот например;
    (prompt "\nSelect POINT objects to connect: ") - тут просто выводится сообщение
    (setq ss (ssget '((0 . "POINT")))) - создаётся переменная (список) ss и командой ssget пользователю даётся возможность выбрать примитивы в модели, при этом примитивы фильтруются - выбираются только точки AutoCad-а. и т.д.

    Довольно просто освоить LISP для решения простейших задач, и когда-то давно, приходилось писать мини утилиты для решения рутинных и повторяющихся действий, иногда пара-тройка часов требовалась для написания и отладки программы, чтобы за 10-20 минут сделать работу на которую потребовалось бы 2 дня ручной работы.
     
    sergtor, flareon и Negaday нравится это.
  7. zvezdochiot

    zvezdochiot Форумчанин

    Понадобилось время для тестирования и оценки. Всё гуд, но!...
    Для многих задач _PLINE (0 . "POLYLINE") - то что нужно, но для некоторых задач было бы желательно использование _3DPOLY (???). Не стоит ли дополнить лисп модификацией _PointStar3D, использующей _3DPOLY вместо _PLINE?

    Ещё раз спасибо за решение.
     
  8. zvezdochiot

    zvezdochiot Форумчанин

    Извиняюсь. Оказалось, что я не разобрался и написал напраслину. В лиспе уже используется _3DPOLY.
     
    sokkol нравится это.
  9. zvezdochiot

    zvezdochiot Форумчанин

    Модифицировал лисп, чтобы он создавал одну "звезду", а не набор отрезков. Как это собственно и ставилось в исходной задаче:
    Код:
    (defun c:PointStar (/ ss ptList cnt sum midpt)
      (prompt "\nSelect POINT objects to connect: ")
      (setq ss (ssget '((0 . "POINT"))))
      
      (cond
        ((not ss) (princ "\nNo points selected."))
        ((< (sslength ss) 2) (princ "\nSelect at least 2 points."))
        (T
          (setq ptList 
            (vl-remove-if-not
              '(lambda (x) (eq (car x) 10))
              (apply 'append 
                (mapcar 'entget 
                  (vl-remove-if 'listp 
                    (mapcar 'cadr (ssnamex ss))
                  )
                )
              )
            )
          )
          
          (setq ptList (mapcar 'cdr ptList)
                cnt (length ptList)
                sum (apply 'mapcar (cons '+ ptList))
                midpt (mapcar '/ sum (list cnt cnt cnt)))
          
          (entmakex (list '(0 . "POINT") (cons 10 midpt)))
          
          (entmakex
            (list
              '(0 . "POLYLINE")
              '(100 . "AcDb3dPolyline")
              '(66 . 1)
              '(10 0.0 0.0 0.0)
              '(70 . 8)
            )
          )
          (entmakex (list '(0 . "VERTEX") '(100 . "AcDb3dPolylineVertex") (cons 10 midpt) '(70 . 32)))
          (foreach pt ptList
            (entmakex (list '(0 . "VERTEX") '(100 . "AcDb3dPolylineVertex") (cons 10 pt) '(70 . 32)))
            (entmakex (list '(0 . "VERTEX") '(100 . "AcDb3dPolylineVertex") (cons 10 midpt) '(70 . 32)))
          )
          (entmakex '((0 . "SEQEND")))
          (princ (strcat "\nCreated " (itoa cnt) " connections to midpoint."))
        )
      )
      (princ)
    )
    
    Так гораздо сподручнее. Вот вам и одно единственное решение. ;)
     

    Вложения:

    • PointStar.lsp
      Размер файла:
      1,4 КБ
      Просмотров:
      4
    chehoff и sergtor нравится это.
  10. zvezdochiot

    zvezdochiot Форумчанин

    sokkol, есть ли способ модификации скрипта, чтоб он работал не с точками, а с окружностями?

    Почему окружностями?

    Суть новой задачи - использовать площади окружностей в качестве весов. Потому как веса должны быть представлены графически и представлены в удобном виде. Или наоборот использовать окружность как представление некой "погрешности" точки, а веса брать как величину обратную площади данной окружности.

    В такой постановке недостаточно заменить "POINT" на "CIRCLE", но надо ещё извлекать площадь и использовать её в суммировании:

    w = 1.0 / s

    {xw,yw,hw} = sum(w * {x,y,h}) / sum{w)

    Желательно также использовать величину:

    wm = sum(w) / sqrt(n)

    sm = 1.0 / wm

    как вес средневзвешанной точки и рисовать окружность в этой точке согласно данного веса.
     
    Последнее редактирование: 4 окт 2025
    Yuri V. нравится это.
  11. Yuri V.

    Yuri V. Форумчанин

    Действительно, народ в нашей отрасли делиться на понимающих таблицы или графики. Последних большинство.
    Ваш цветной треугольник неровностей декартовой системы по цвету невязок - на мой взгляд треть пути.
    Вторая треть - это веса, на основе ковариации - такие овалы, оси которых направлены вдоль максимальных ошибок.
    И третья доля - Гауссов сплаттинг. А чего испугались? Сложных расчётов? Да, там трындец. Говорят технология на передовой, только насыпай
    --- Сообщения объединены, 11 окт 2025, Оригинальное время сообщения: 11 окт 2025 ---
    На передовой в смысле на переднем крае науки отображения пространства в декартовой системе.
    Следующая революция в многослойной матрице, в изображении которой можно будет управлять фокусом пост фактум.
    И тем более поиска средней точки.
     
  12. zvezdochiot

    zvezdochiot Форумчанин

    Испугался?
    Скорее имеет место быть недовольство. Причём сильное.
    В чём недовольство?
    В русских вычислениях уже как век используется критерий [pvv]->min.
    Но!
    Снова здарова. В буржуйских реализациях снова наблюдаем примитивный нерегулируемый [vv]->min. Речь за тарелки, в которых можно только полностью отключить отдельные спутники, без плавного весового регулирования.
    В то же время в Таблицы MS Excel для преобразования координат: [conformaltrans]: helmert3d.xls показано, что использование весов для таких задач вообще не представляет проблем.
    Вот и хотелось бы иметь некоторые простые инструменты, возвращающие русский критерий на своё законное место.
    Такие вот дела.
     
  13. sokkol

    sokkol Форумчанин

    Ок. В зависимости от выбора, работает с точками, с центрами окружностей как с точками и с центрами окружностей учитывая площадь окружности:
    Практически всю работу проделал ИИ Copilot в браузере Edge. Скрипт рисует весовую окружность в центре, если выбран режим WEIGHTED. Радиус окружности рассчитывается как обратная величина от среднего веса, с нормировкой по корню из количества точек.
    Радиус — обратно пропорционален среднему весу: чем выше вес, тем меньше окружность, если не видите весовую окружность - масштабируйте (зумируйте) окно.
    По ходу общения, ИИ Copilot предлагает варианты развития скрипта (цитирую):
    "Хочешь, чтобы окружность была не просто кругом, а эллипсом, ориентированным по ковариационной матрице? Или добавить подпись с весом? Можем превратить это в полноценную визуализацию погрешностей." и т.д.
    Сам код, запуск командой PointStarX3
    Код:
    (defun get-objects-by-mode (mode / ss)
      (cond
        ((eq mode "POINT") (ssget '((0 . "POINT"))))
        ((member mode '("CIRCLE" "WEIGHTED"))
         (ssget '((0 . "CIRCLE")))
        )
        ((eq mode "LOGGING") (ssget '((0 . "POINT"))))
        (T nil)
      )
    )
     
    (defun extract-coords-and-weights
           (ss mode / entList ptList weightList obj pt rad area w)
      (setq ptList '()
    weightList
     '()
      )
      (repeat (setq i (sslength ss))
        (setq i (1- i))
        (setq obj (vlax-ename->vla-object (ssname ss i)))
        (cond
          ((eq mode "POINT")
           (setq pt (vlax-get obj 'Coordinates))
           (setq ptList (cons pt ptList))
          )
          ((eq mode "CIRCLE")
           (setq pt (vlax-get obj 'Center))
           (setq ptList (cons pt ptList))
          )
          ((eq mode "WEIGHTED")
           (setq pt   (vlax-get obj 'Center)
         rad  (vlax-get obj 'Radius)
         area (* pi rad rad)
         w   (/ 1.0 area)
           )
           (setq ptList (cons pt ptList))
           (setq weightList (cons w weightList))
          )
        )
      )
      (list ptList weightList)
    )
     
    (defun compute-midpoint (ptList weightList mode / sum cnt wsum midpt)
      (cond
        ((eq mode "WEIGHTED")
         (setq sum '(0 0 0)
       wsum 0
         )
         (foreach pair (mapcar 'list ptList weightList)
           (setq sum
          (mapcar '+
          sum
          (mapcar '(lambda (x) (* (cadr pair) x)) (car pair))
          )
           )
           (setq wsum (+ wsum (cadr pair)))
         )
         (setq midpt (mapcar '/ sum (list wsum wsum wsum)))
        )
        (T
         (setq cnt  (length ptList)
       sum  (apply 'mapcar (cons '+ ptList))
       midpt (mapcar '/ sum (list cnt cnt cnt))
         )
        )
      )
      midpt
    )
     
    (defun draw-3dpolyline (ptList midpt)
      (setq allPts (cons midpt ptList))
      (entmakex
        (list
          '(0 . "POLYLINE") '(100 . "AcDb3dPolyline") '(66 . 1) '(10 0.0 0.0 0.0)
          '(70 . 8))
      )
     
     
      (foreach pt allPts
        (entmakex (list '(0 . "VERTEX")
        '(100 . "AcDb3dPolylineVertex")
        (cons 10 pt)
        '(70 . 32)
          )
        )
        (entmakex (list '(0 . "VERTEX")
        '(100 . "AcDb3dPolylineVertex")
        (cons 10 midpt)
        '(70 . 32)
          )
        )
      )
      (entmakex '((0 . "SEQEND")))
    )
     
    (defun draw-weight-circle (midpt weightList / wm sm)
      (setq wm (/ (apply '+ weightList) (sqrt (length weightList))))
      (setq sm (/ 1.0 wm)) ; радиус окружности
      (entmakex
        (list
          '(0 . "CIRCLE")
          (cons 10 midpt)
          (cons 40 sm)
          '(62 . 3) ; зелёный цвет
        )
      )
    )
     
    (defun c:PointStarX3 (/ mode ss ptList weightList midpt)
      (initget "POINT CIRCLE WEIGHTED LOGGING")
      (setq
        mode (getkword "\nSelect mode [POINT/CIRCLE/WEIGHTED]: ")
      )
      (setq ss (get-objects-by-mode mode))
      (if (not ss)
        (princ "\nNo valid objects selected.")
        (progn
          (setq data       (extract-coords-and-weights ss mode)
        ptList     (car data)
        weightList (cadr data)
        midpt      (compute-midpoint ptList weightList mode)
          )
          (entmakex (list '(0 . "POINT") (cons 10 midpt)))
          (if (eq mode "WEIGHTED")
    (draw-weight-circle midpt weightList)
          )
          (draw-3dpolyline ptList midpt)
          (princ (strcat "\nCreated 3D polyline with "
         (itoa (length ptList))
         " points from midpoint."
         )
          )
        )
      )
      (princ)
    )
    
    лисп файл PointStarX3:
     

    Вложения:

    Последнее редактирование: 13 окт 2025
    zvezdochiot нравится это.
  14. zvezdochiot

    zvezdochiot Форумчанин

    Не совсем корректно. Площадь круга - обратно пропорциональна среднему весу.
    Но это уже я подзапутал.
    Всё проще. Исправлюсь:
    Вес средневзвешанной точки: wmp = sum(w)
    Площадь "погрешности" средневзвешанной точки: smp = 1.0 / wmp
    Радиус "погрешности" средневзвешанной точки: rmp = sqrt(smp / pi)

    Проверяем на обычной средней точке из четырёх точек (для обычного среднего веса условно равны 1.0). Для доскональности возьмём радиус "погрешности" всех точек 0.01м:

    s = 3.14*0.01*0.01 = 0.000314
    w = 1.0/0.000314 = 3184.71
    wmp = 3184.71+3184.71+3184.71+3184.71 = 12738.85
    smp = 1.0/12738.85 = 0.0000785
    rmp = sqrt(0.0000785/3.14) = 0.005

    То есть есё по классике: mmp = m/sqrt(n) == 0.01 / 2

    Но это я сам допилю и отпишусь. Спасибо @sokkol .
     
    Последнее редактирование: 13 окт 2025
    sokkol нравится это.
  15. zvezdochiot

    zvezdochiot Форумчанин

    Допилил. Особо допиливать то не так и много, выше всё объяснил:
    Код:
    (defun get-objects-by-mode (mode / ss)
      (cond
        ((eq mode "POINT") (ssget '((0 . "POINT"))))
        ((member mode '("CIRCLE" "WEIGHTED"))
         (ssget '((0 . "CIRCLE")))
        )
        ((eq mode "LOGGING") (ssget '((0 . "POINT"))))
        (T nil)
      )
    )
    
    (defun extract-coords-and-weights
           (ss mode / entList ptList weightList obj pt rad area w)
      (setq ptList '()
            weightList
             '()
      )
      (repeat (setq i (sslength ss))
        (setq i (1- i))
        (setq obj (vlax-ename->vla-object (ssname ss i)))
        (cond
          ((eq mode "POINT")
           (setq pt (vlax-get obj 'Coordinates))
           (setq ptList (cons pt ptList))
          )
          ((eq mode "CIRCLE")
           (setq pt (vlax-get obj 'Center))
           (setq ptList (cons pt ptList))
          )
          ((eq mode "WEIGHTED")
           (setq pt   (vlax-get obj 'Center)
                 rad  (vlax-get obj 'Radius)
                 area (* pi rad rad)
                 w    (/ 1.0 area)
           )
           (setq ptList (cons pt ptList))
           (setq weightList (cons w weightList))
          )
        )
      )
      (list ptList weightList)
    )
    
    (defun compute-midpoint (ptList weightList mode / sum cnt wsum midpt)
      (cond
        ((eq mode "WEIGHTED")
         (setq sum  '(0 0 0)
               wsum 0
         )
         (foreach pair (mapcar 'list ptList weightList)
           (setq sum
                  (mapcar '+
                          sum
                          (mapcar '(lambda (x) (* (cadr pair) x)) (car pair))
                  )
           )
           (setq wsum (+ wsum (cadr pair)))
         )
         (setq midpt (mapcar '/ sum (list wsum wsum wsum)))
        )
        (T
         (setq cnt   (length ptList)
               sum   (apply 'mapcar (cons '+ ptList))
               midpt (mapcar '/ sum (list cnt cnt cnt))
         )
        )
      )
      midpt
    )
    
    (defun draw-3dpolyline (ptList midpt)
      (setq allPts (cons midpt ptList))
      (entmakex
        (list
          '(0 . "POLYLINE") '(100 . "AcDb3dPolyline") '(66 . 1) '(10 0.0 0.0 0.0)
          '(70 . 8))
      )
    
      (foreach pt allPts
        (entmakex (list '(0 . "VERTEX")
                        '(100 . "AcDb3dPolylineVertex")
                        (cons 10 pt)
                        '(70 . 32)
                  )
        )
        (entmakex (list '(0 . "VERTEX")
                        '(100 . "AcDb3dPolylineVertex")
                        (cons 10 midpt)
                        '(70 . 32)
                  )
        )
      )
      (entmakex '((0 . "SEQEND")))
    )
    
    (defun draw-weight-circle (midpt weightList / wm sm)
      (setq wm (apply '+ weightList))
      (setq sm (/ 1.0 wm))
      (setq rm (sqrt (/ sm pi)))            ; радиус окружности
      (entmakex
        (list
          '(0 . "CIRCLE")
          (cons 10 midpt)
          (cons 40 rm)
          '(62 . 3)                         ; зелёный цвет
        )
      )
    )
    
    (defun c:PointStarX3 (/ mode ss ptList weightList midpt)
      (initget "POINT CIRCLE WEIGHTED LOGGING")
      (setq
        mode (getkword "\nSelect mode [POINT/CIRCLE/WEIGHTED]: ")
      )
            (setq data nil
                    ptList nil
                    weightList nil
                    midpt nil
            )
      (setq ss (get-objects-by-mode mode))
      (if (not ss)
        (princ "\nNo valid objects selected.")
        (progn
          (setq data       (extract-coords-and-weights ss mode)
                ptList     (car data)
                weightList (cadr data)
                midpt      (compute-midpoint ptList weightList mode)
          )
          (entmakex (list '(0 . "POINT") (cons 10 midpt)))
          (if (eq mode "WEIGHTED")
            (draw-weight-circle midpt weightList)
          )
          (draw-3dpolyline ptList midpt)
          (princ (strcat "\nCreated 3D polyline with "
                         (itoa (length ptList))
                         " points from midpoint."
                 )
          )
        )
      )
      (princ)
    )
    
    Доктринально проверяется на 4, 9 и т.д. окружностях одинакового радиуса (например, 0.01). В этом случае "звезда" в режиме "WEIGHTED", совпадает с обычным средним (два первых режима), а в центральной точке строится окружность по ТМОГИ: Rm = R1 / sqrt(n) (для примера с окружностями 0.01 для 4 и 9 окружностей будет рисоваться 0.005 и 0.0033).

    После проверки доктрин можно изучать "сложные" случаи (все окружности разные). В этих случаях средневесовые "звёзды" не будут совпадать с "звездой" обычного среднего.
     

    Вложения:

    • PointStarX3.lsp
      Размер файла:
      3,3 КБ
      Просмотров:
      3
    sergtor и sokkol нравится это.
  1. Этот сайт использует файлы cookie. Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie.
    Скрыть объявление
  1. Этот сайт использует файлы cookie. Продолжая пользоваться данным сайтом, Вы соглашаетесь на использование нами Ваших файлов cookie.
    Скрыть объявление