Сообщество программистов Autodesk в СНГ

ADN Club => AutoLisp / VisualLISP и DCL => Тема начата: 1958 от 06-06-2017, 13:52:46

Название: Проецирование точки
Отправлено: 1958 от 06-06-2017, 13:52:46
Не смог найти ответа на интересующий меня вопрос.
Имеется поверхность из 3DFACE на отдельном слое. Имеется точка с координатами x,y.
Как спроецировать точку на поверхность, чтобы получить отметку? Как это можно оформить лиспом?
Название: Re: Проецирование точки
Отправлено: Александр Ривилис от 06-06-2017, 13:55:15
Имеется поверхность из 3DFACE на отдельном слое.
Это один 3DFACE или их много и поверхность создана из них?
Название: Re: Проецирование точки
Отправлено: 1958 от 06-06-2017, 15:34:42
3DFACE целая сеть и поверхность создана из них
Название: Re: Проецирование точки
Отправлено: Александр Ривилис от 06-06-2017, 15:40:14
3DFACE целая сеть и поверхность создана из них
Значит сначала по координатам X и Y точки нужно найти ту 3DFACE, на которую эта точка проецируется, а затем выполнить проекцию, т.е. найти пересечение вертикальной прямой проходящей через точку (X,Y,0) и плоскости совпадающей с плоскостью 3DFACE (надеюсь, что у 3DFACE только три вершины, т.к. в противном случае она не плоская). Это элементарная задача аналитической геометрии. Специальных готовых алгоритмов для её решения в AutoLisp/VisualLisp нет. Так что нужно их самому написать или поискать в интернете.
Название: Re: Проецирование точки
Отправлено: 1958 от 06-06-2017, 15:41:02
В принципе у меня решение есть, но хотелось бы покороче.

Код - Auto/Visual Lisp [Выбрать]
  1. (defun c:z_3d (pt / 1_3d) ; Определение координат двухмерной точки pt
  2.  (setq x    (nth 0 pt)
  3.        y    (nth 1 pt)
  4.        1_3d nil
  5.        i    0
  6.        ii   0
  7.  )
  8.  (setq 1_3d (ssget "_X" '((0 . "3DFACE") (8 . "ТРИАНГУЛЯЦИЯ"))))
  9.  (while (and (< i (sslength 1_3d)) (= ii 0))
  10.   (setq pt1 (cdr (assoc 10 (entget (ssname 1_3d i))))
  11.         pt2 (cdr (assoc 12 (entget (ssname 1_3d i))))
  12.         pt3 (cdr (assoc 13 (entget (ssname 1_3d i))))
  13.         x1  (nth 0 pt1)
  14.         y1  (nth 1 pt1)
  15.         z1  (nth 2 pt1)
  16.         x2  (nth 0 pt2)
  17.         y2  (nth 1 pt2)
  18.         z2  (nth 2 pt2)
  19.         x3  (nth 0 pt3)
  20.         y3  (nth 1 pt3)
  21.         z3  (nth 2 pt3)
  22.   )
  23.   (if (> x2 x1)
  24.    (setq xmax x2
  25.          xmin x1
  26.    )
  27.    (setq xmax x1
  28.          xmin x2
  29.    )
  30.   )
  31.   (if (> x3 xmax)
  32.    (setq xmax x3)
  33.   )
  34.   (if (< x3 xmin)
  35.    (setq xmin x3)
  36.   )
  37.   (if (> y2 y1)
  38.    (setq ymax y2
  39.          ymin y1
  40.    )
  41.    (setq ymax y1
  42.          ymin y2
  43.    )
  44.   )
  45.   (if (> y3 ymax)
  46.    (setq ymax y3)
  47.   )
  48.   (if (< y3 ymin)
  49.    (setq ymin y3)
  50.   )
  51.   (if (and (> x xmin) (< x xmax))
  52.    (progn (if (and (> y ymin) (< y ymax))
  53.            (setq ii (+ ii 1))
  54.           )
  55.    )
  56.   )
  57.   (setq i (+ 1 i))
  58.  )
  59.  (setq A (+ (+ (* y1 (- z2 z3)) (* y2 (- z3 z1))) (* y3 (- z1 z2)))
  60.        B (+ (+ (* z1 (- x2 x3)) (* z2 (- x3 x1))) (* z3 (- x1 x2)))
  61.        C (+ (+ (* x1 (- y2 y3)) (* x2 (- y3 y1))) (* x3 (- y1 y2)))
  62.        D (* -1
  63.             (+ (+ (* x1 (- (* y2 z3) (* y3 z2)))
  64.                   (* x2 (- (* y3 z1) (* y1 z3)))
  65.                   (* x3 (- (* y1 z2) (* y2 z1)))
  66.                )
  67.             )
  68.          )
  69.  )
  70.  (setq z (/ (- (- (* -1 D) (* A x)) (* B y)) C)
  71.        pt (list (nth 0 pt) (nth 1 pt) z)) ;трехмерная точка
  72. )
Название: Re: Проецирование точки
Отправлено: Александр Ривилис от 06-06-2017, 16:15:25
1. Напоминаю про правила форматирования кода на форуме (у меня в подписи).
2. Короче не будет, так как встроенного алгоритма (в отличие от ObjectARX/AutoCAD .NET API нет).
Название: Re: Проецирование точки
Отправлено: 1958 от 07-06-2017, 09:15:06
Ладно, а если я предварительно создам список координат треугольников в виде ((x y) z), например список координат трех треугольников:

((((1.22039e+007 4.28423e+006) 336.62) ((1.22038e+007 4.28422e+006) 336.65) ((1.22038e+007 4.2842e+006) 336.71))
(((1.22039e+007 4.28419e+006) 336.74) ((1.22039e+007 4.28423e+006) 336.62) ((1.22038e+007 4.2842e+006) 336.71))
(((1.22039e+007 4.2842e+006) 336.68) ((1.22039e+007 4.28423e+006) 336.62) ((1.22039e+007 4.28419e+006) 336.74))),

как узнать в какой треугольник попадает выбранная точка (x y)?
Т.е. нужен короткий алгоритм:
1. Выбираем из списка первый треугольник ((1.22039e+007 4.28423e+006) 336.62) ((1.22038e+007 4.28422e+006) 336.65) ((1.22038e+007 4.2842e+006) 336.71))
2. Определяем попадает ли точка в этот треугольник
3. Если попадает, вычисляем отметку точки, если нет - переход к пункту 1 со следующим треугольником.

Вся загвоздка в пункте 2.
Название: Re: Проецирование точки
Отправлено: trir от 07-06-2017, 12:12:53
Есть куча алгоритмов определения принадлежности точки полигону, но в данном случае можно по формуле  sign((ax + by + c)/sqrt(a^2+b^2)) определить положение точки относительно рёбер треугольника (совпадает для всех рёбер, если точка внутри), тут важен порядок обхода рёбер
Название: Re: Проецирование точки
Отправлено: 1958 от 07-06-2017, 12:44:01
Наверно, лучше использовать набор.
Т.е. рисуем точку, потом выбираем ее (setq ptn (ssget "_CP" pt_list)).  pt_list - список плоских (x y) координат вершин текущего треугольника.
Если ptn не nil, то точка попала в текущий треугольник.
Название: Re: Проецирование точки
Отправлено: Алексей Кулик от 07-06-2017, 14:46:44
И каждый раз выполнять зум, панорамирование и регенерацию экрана - чтобы точки контура гарантированно в него попали?
Название: Re: Проецирование точки
Отправлено: Александр Ривилис от 07-06-2017, 14:51:36
Наверно, лучше использовать набор.
Т.е. рисуем точку, потом выбираем ее (setq ptn (ssget "_CP" pt_list)).  pt_list - список плоских (x y) координат вершин текущего треугольника.
Если ptn не nil, то точка попала в текущий треугольник.
Не обижайтесь, но это самый худший алгоритм из всех, которые можно было бы придумать. Даже объяснять не буду насколько он будет ненадежный, медленный и т.д.
Посмотрите вот этот алгоритм для определения находится ли точка внутри контура (треугольник - это тоже контур из трёх вершин): http://forum.dwg.ru/showpost.php?p=1538777&postcount=62
Или этот: http://www.cadtutor.net/forum/showthread.php?39199-Identify-a-polyline-by-a-point-inside-this-polyline&p=263330&viewfull=1#post263330
Название: Re: Проецирование точки
Отправлено: trir от 07-06-2017, 14:55:35
Откуда уши:
Цитировать
По книге Ласло,
"Вычислительная геометрия и компьютерная графика на С++"

Если надо найти треугольник в который попадает точка, то лучше сначала искать в r-дереве...
Название: Re: Проецирование точки
Отправлено: Александр Ривилис от 07-06-2017, 15:15:45
Если надо найти треугольник в который попадает точка, то лучше сначала искать в r-дереве...
Согласен, но не видел готового алгоритма R-Tree на Autolisp, что означает или необходимость его написать (вряд ли эта задача по плечу 1958) или использовать готовые алгоритмы на .NET или ObjectARX.
Название: Re: Проецирование точки
Отправлено: 1958 от 07-06-2017, 16:42:02
http://www.cadtutor.net/forum/showthread.php?39199-Identify-a-polyline-by-a-point-inside-this-polyline&p=263330&viewfull=1#post263330 (http://www.cadtutor.net/forum/showthread.php?39199-Identify-a-polyline-by-a-point-inside-this-polyline&p=263330&viewfull=1#post263330)

Это решение мне нравится!
Будем думать.
Название: Re: Проецирование точки
Отправлено: 1958 от 07-06-2017, 17:15:04
Код - Auto/Visual Lisp [Выбрать]
  1. (defun c:coor_3df (/)
  2.  (vl-cmdf "_.-layer" "_SET" "ИИ_ТРИАНГУЛЯЦИЯ_025" "")
  3.  (setq ptn (reverse (cdr (reverse (getpoint "Укажите точку")))) ;координаты точки (x y)
  4.        i   0
  5.  )
  6.  (vl-cmdf "_point" ptn) ;рисуем точку
  7.  (setq ss      (ssget "_X" '((0 . "3DFACE") (8 . "ИИ_ТРИАНГУЛЯЦИЯ_025"))) ;набор 3Д-граней
  8.        ss_3d   nil
  9.        i_trian nil
  10.  )
  11.  (repeat (setq in (sslength ss))
  12.   (setq 1_3d  (ssname ss (setq in (1- in))) ;выбираем треугольник
  13.         1_3   (cdr (assoc 10 (entget 1_3d))) ;координаты (x y z) 1-ой вершины треугольника
  14.         2_3   (cdr (assoc 12 (entget 1_3d))) ;координаты (x y z) 2-ой вершины треугольника
  15.         3_3   (cdr (assoc 13 (entget 1_3d))) ;координаты (x y z) 3-ой вершины треугольника
  16.         s_3d  (list 1_3 2_3 3_3) ;список координат треугольника
  17.         ss_3d (cons s_3d ss_3d) ;добавляем в общий список
  18.   )
  19.  )
  20.  (while (< i (1- (length ss_3d)))
  21.   (setq i_trian (nth i ss_3d)) ;вытаскиваем i-ый треугольник
  22.   (setq i_1 (reverse (cdr (reverse (nth 0 i_trian)))) ; x,y 1-ой вершины
  23.         i_2 (reverse (cdr (reverse (nth 1 i_trian)))) ; x,y 2-ой вершины
  24.         i_3 (reverse (cdr (reverse (nth 2 i_trian)))) ; x,y 3-ой вершины
  25.   )
  26.   (setq pt_list (list i_1 i_2 i_3)) ;список вершин треугольника
  27.   ;выбираем точку многоугольником:
  28.   (setq pt (ssget "_CP" pt_list '((0 . "POINT") (8 . "ИИ_ТРИАНГУЛЯЦИЯ_025"))))
  29.   (if (= (sslength pt) 0) ;если набор пустой
  30.    (setq i (1+ i)) ;переходим к следующему треугольнику
  31.    (setq i (1+ (length ss_3d))) ;нужный треугольник найден, выходим из цикла
  32.   )
  33.  )
  34.  (alert (strcat "вершины треугольника\n" (vl-prin1-to-string i_trian)))
  35.  (entdel (entlast)) ;удаляем точку
  36.  (vl-cmdf "_.-layer" "_SET" "0" "")
  37.  (princ)
  38. )


Если я указываю точку в первом треугольнике, всё нормально. Иначе - ошибка. В чём дело, не пойму.
Название: Re: Проецирование точки
Отправлено: Алексей Кулик от 07-06-2017, 18:06:00
А ведь дали уже готовые решения, что их не использовать?
Off-Topic: показать
За сохранение форматирования в коде готов иногда убивать!
Название: Re: Проецирование точки
Отправлено: Александр Ривилис от 07-06-2017, 18:09:48
1958
Второе предупреждение по поводу форматирования кода! Третье предупреждение будет последним.
Внимательно прочтите мою подпись.
Название: Re: Проецирование точки
Отправлено: 1958 от 07-06-2017, 21:58:30
Прошу прощения.
Пять раз просмотрел ваше видео про форматирование, но ничего не разглядел. Лучше бы вы дополнительно дали текстовое описание.
Название: Re: Проецирование точки
Отправлено: Александр Ривилис от 07-06-2017, 22:10:40
Пять раз просмотрел ваше видео про форматирование, но ничего не разглядел.
Вы первый. :)
Выделяете код и из выпадающего меню выбираете язык и получаете такое форматирование:

Код - Auto/Visual Lisp [Выбрать]
  1.  (setq x    (nth 0 pt)
  2.        y    (nth 1 pt)
  3.        1_3d nil
  4.        i    0
  5.        ii   0
  6.  )

 
(https://farm5.staticflickr.com/4206/34997726262_000ab5bbb8_o.png)

Название: Re: Проецирование точки
Отправлено: trir от 09-06-2017, 06:55:32
Off-Topic: показать
А зачем вообще нужно дублировать функционал Civil 3D и именно на lisp'е? 
Название: Re: Проецирование точки
Отправлено: Алексей Кулик от 09-06-2017, 07:17:02
trir, у человека может и не быть Civil3D.