Тема: Алгоритм (не)вхождения точки в произвольный многоугольник.

Господа, пришла пора и мне задать вопрос. Дочки-математички ленятся и не хотят мне помочь.
Задача. Имеются координаты произвольной замкнутой ломаной линии (без дуг и сплайнов) и координата точки. Оба объекта, будем считать, не имеют Z координат.
Требуется ответить на вопросы:
- точка внутри многоугольника?
- точка снаружи?
- точка лежит на одном из отрезков многоугольника?
Кто подскажет путь решения (только без применения команд Acad)???

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

http://algolist.manual.ru/maths/geom/belong/

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

p.s. Только собрался дописать, что ссылку ShaggyDoc на algolist я видел (прежде форум пролистал насчет похожих тем), как он уже ее повторил, спасибо за оперативность.
Но! А ДРУГОГО метода нет? Только метод луча с анализом четности-нечетности пересечений, и так для всех отрезков многоугольника?
Может что-то есть через координаты, например, как решается площадь многоугольника, в старой книжке по геодезии лет 20 назад видел формулу (только координаты нужны).

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

ShaggyDoc-у:

Спасибо за действительно инересный (и полезный) сайт

KAI:

Есть еще метод "Подсчета суммы ориентаций пересечений", я пользуюсь уже около 10 лет - пока не подводил...

Комментарии минимальны, но думаю будет понятно...

;;;-----------------------------------------------------------------------
(defun My- (x y)
   (cond
     ((< x y) -1)
     ((> x y)  1)
     (t        0)))
;;;-----------------------------------------------------------------------
(defun My+ (x y)
   (or (zerop x) (zerop y) (zerop (+ x y)) ))
;;;-----------------------------------------------------------------------
(defun In_Figure (pt contur / pt1 pt2 pti ptl ptp ptc eps tmp)
;
; Тест - находится ли точка pt внутри контура contur.
; Алгоритм взят из статьи О.Р.Мусина в журнале
; "Программирование" 4, 91г.
; Выбран алгоритм "Сумма ориентаций пересечений"
;
; Аргументы :
;   contur - список координат точек образующих контур
;            в виде (pt1 pt2 ...ptn)
;   pt     - тестируемая точка
;
; Функции :
;   _locat - проверяет находится ли пара точек в квадрантах
;            ((1,4)(2,4)(1,3))
;   _kk    - вычисляет ориентацию отрезка
;
   (setq tmp nil
         pt1 (mapcar '- (car  contur) pt)
         ptp pt1)
;
; создается список отрезков
;
   (while contur
     (setq ptc    (mapcar '- (car contur) pt)
           contur (cdr contur))
     (if (_locat ptc ptp)
       (setq tmp (cons (list ptc ptp) tmp)))
     (setq ptp ptc))
   (if (_locat pt1 ptp)
     (setq tmp (cons (list pt1 ptp) tmp)))
;
; ищем точки пересечения L+ с контуром
;
   (setq pt  '(0 0 0)
         ptl '(1 0 0)
         eps 0)
;
   (while tmp
     (setq pt1 (caar  tmp)
           pt2 (cadar tmp)
           tmp (cdr   tmp)
           pti (inters pt1 pt2 pt ptl nil))
     (cond
       ((< (car pti) 0) nil)                  ; Отрезок пересекает L-
       (t (setq eps (+ (_kk pt1 pt2) eps))))) ;
;
; В eps - сформированный признак
;
   (not (zerop eps)))
;;;-----------------------------------------------------------------------
(defun _Locat (pt1 pt2);
;
; Допустимая ли комбинация четвертей ?
;
   (cond
     ((and (>= (car pt1) 0) (>= (cadr pt1) 0))           ; 1
      (or (and (>= (car pt2) 0) (< (cadr pt2) 0))        ; 1-4
          (and (<  (car pt2) 0) (< (cadr pt2) 0))))      ; 1-3
     ((and (<  (car pt1) 0) (>= (cadr pt1) 0))           ; 2
      (and (>= (car pt2) 0) (<  (cadr pt2) 0)))          ; 2-4
     ((and (<  (car pt1) 0) (<  (cadr pt1) 0))           ; 3
      (and (>= (car pt2) 0) (>= (cadr pt2) 0)))          ; 3-1
     (t                                                  ; 4
      (or (and (>= (car pt2) 0) (>= (cadr pt2) 0))       ; 4-1
          (and (<  (car pt2) 0) (>= (cadr pt2) 0)))) ))  ; 4-2
;;;-----------------------------------------------------------------------
(defun _Kk (pt1 pt2);
   (if (>= (cadr pt1) (cadr pt2)) 1 -1))

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

Есть книга: Компьютерная графика. Динамика, реалистические изображения. Е. В. Шикин, А. В. Боресков. М.: Диалог-МИФИ, 1995. Там этот и множество других полезных алгоритмов

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

Спасибо всем за добрые советы.
Программа г.Попадьина протестирована, прекрасно работает, но мне нужен был анализ еще и нахождения исходной точки на контуре, а данный алгоритм для точки на контуре выдает то nil то Т.
После сбора алгоритмов остановился все-таки на описанном в http://algolist.manual.ru/maths/geom/belong/, кое-какие идеи подкинули также дочь со товарищи.
Но к данному алгоритму пришлось добавить не описанный  никем анализ, когда имеем горизонтальный(е) участок(и), пересекаемые лучом от исходной точки, а участки до и после горизонта направлены в разные стороны.
Кому интересно можете скачать функцию http://geol-dh.narod.ru/spds/index.html (довольно большая получилась)
На входе: точка, список точек контура, точность сравнения координат
Возвращает список: флаг, координаты точки на контуре, описание точки на контуре

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

KAI:
Что есть - то есть, с границами описанный алгоритм обходится довольно вольно, правда дополнить алгоритм проверкой принадлежности точки отрезку, как мне кажется не так уж и сложно - это чистая математика, думаю за пол-часа можно добавить...

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

> "еще
и нахождения исходной точки на контуре"
Можно попробовать без математики:
(if (vl-catch-all-error-p
      (vl-catch-all-apply
        'vlax-safearray->list
        (list (vlax-variant-value
                (vla-intersectwith (vlax-ename->vla-object pt) (vlax-ename->vla-object pline) acextendnone)
              ) ;_  vlax-variant-value
        ) ;_  list
      ) ;_  vl-catch-all-apply
    ) ;_  vl-catch-all-error-p
  nil ;_ точка не лежит...
  t ;_ точка лежит...
) ;_  if
здесь функция vl-catch-all-apply вернет или список с координатами точки (в смысле пересечения точки и полилинии) или ошибку, если точка не на полилинии.

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

vk:
описанный прием работает, как я понимаю, только для РЕАЛЬНО существующего контура, заданного примитивами. В некоторых задачах существует ВИРТУАЛЬНЫЙ контур. Кроме того, не знаю как у кого у меня была большая проблема с vla-intersectwith, когда я пробовал искать пересечение отрезка с составными элементами (блоками например), кроме частенько вместо двух точек пересения функция может вернуть четыре - две чуть выше плоскости X0Y, и две чуть ниже - повидимому ошибки округления при передаче из Лиспа в ActiveX.
А математика на самом деле простейшая (тем более что контур состоит ТОЛЬКО из отрезков, без дуг) и работать будет по крайней мере не намного дольше, но зато точно!

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

> Сергей
Попадьин
Это действительно вариант решения для реальных объектов. Создать реальный контур - дело двух-трех строк программы. А вот как быть с ошибками?...

Re: Алгоритм (не)вхождения точки в произвольный многоугольник.

(defun ObjInters (ent1 ent2 flag / obj1 obj2 res lst)
  (if (and (and ent1 ent2)       
       (and (>= flag 0) (<= flag 3))
       (setq obj1 (vlax-ename->vla-object ent1))
       (setq obj2 (vlax-ename->vla-object ent2))
       (setq res  (vlax-variant-value (vla-IntersectWith obj1 obj2 flag)))
      )
    (progn
      (setq
        lst  (if (< (vlax-safearray-get-l-bound res 1)
            (vlax-safearray-get-u-bound res 1))
           (vlax-safearray->list res))
        res nil
      )
      (while lst
    (setq res (cons (list (car lst)(cadr lst)(caddr lst)) res)
          lst (cdddr lst))
      )
    )
  )
  res
)
но идея не моя - взял где-то на этом форуме,
а вот как по ВИРТУАЛЬНЫМ можно было бы:
(defun OnLine (pt ln1 ln2 / dx1 dx2 dy1 dy2)
  (setq dx1 (- (car ln1) (car pt))
    dx2 (- (car ln1) (car ln2))
    dy1 (- (cadr ln1) (cadr pt))
    dy2 (- (cadr ln1) (cadr ln2)))
  (cond ((zerop dy2) (and (zerop dy1) (equal dx1 dx2 1e-9)))
    ((zerop dy1) (zerop dx1))
    (t (equal (/ dx1 dy1) (/ dx2 dy2) 1e-9)))
)
Оба варианта почти не тестированы!!!