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

ADN Club => AutoLisp / VisualLISP и DCL => Тема начата: Macondo от 31-10-2015, 17:03:45

Название: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Macondo от 31-10-2015, 17:03:45
Обнаружил странности в работе vla-SelectAtPoint. Задача такая: найти все объекты с заданными свойствами (а именно линии, полилинии и вхождения блоков, имеющие расширенные данные), проходящие через указанную точку.
Сначала я думал, что получится вот такая конструкция:

Вот, что получилось:
Код - Auto/Visual Lisp [Выбрать]
  1. (if (= (type (setq pt (vl-catch-all-apply (function (lambda () (trans (getpoint "\nУкажите точку: ") 1 0)))))) 'list)
  2.     (progn
  3.       ;Создание набора (если есть, то создаём заново):
  4.       (setq ssets (vla-get-selectionsets actdoc))
  5.       (if (vl-catch-all-error-p (vl-catch-all-apply 'vla-item (list ssets "Set")))
  6.         (setq newSet (vla-add ssets "Set"))
  7.         (progn
  8.           (vla-delete (vla-item ssets "Set"))
  9.           (setq newSet (vla-add ssets "Set"))
  10.         );progn
  11.       );if
  12.       ;Помещение в набор всех линий и вхождений блоков с расширенными данными:
  13.       (setq filter_code (vlax-make-safearray vlax-vbinteger '(0 . 9)))
  14.       (setq filter_value (vlax-make-safearray vlax-vbvariant '(0 . 9)))
  15.       (vlax-safearray-fill filter_code '(-4 -4 0 -3 -4 -4 0 -3 -4 -4)); DXF-группы для фильтра
  16.       (vlax-safearray-fill filter_value '("<OR" "<AND" "*LINE" "'(\"MyApp\")" "AND>" "<AND" "INSERT" "'(\"MyApp\")" "AND>" "OR>"))
  17.       (vla-SelectAtPoint newSet (vlax-3d-point pt) filter_code filter_value)
  18.     ); progn
  19.     (princ)
  20.   )
Однако с -3 постоянно возникает ошибка (наверное, неправильно задаю список в строке).
Если убрать расширенные данные в фильтре, то всё равно возникает ошибка параметров метода (при этом vla-Select ошибку не выдаёт).
Более того, если всё полностью упростить и оставить в фильтре только INSERT, то (vla-get-count newSet) выдаст один элемент при указании точки на блоке:
Код - Auto/Visual Lisp [Выбрать]
  1. (if (= (type (setq pt (vl-catch-all-apply (function (lambda () (trans (getpoint "\nУкажите точку: ") 1 0)))))) 'list)
  2.     (progn
  3.       ;Создание набора (если есть, то создаём заново):
  4.       (setq ssets (vla-get-selectionsets actdoc))
  5.       (if (vl-catch-all-error-p (vl-catch-all-apply 'vla-item (list ssets "Set")))
  6.         (setq newSet (vla-add ssets "Set"))
  7.         (progn
  8.           (vla-delete (vla-item ssets "Set"))
  9.           (setq newSet (vla-add ssets "Set"))
  10.         );progn
  11.       );if
  12.       ;Помещение в набор всех линий и вхождений блоков с расширенными данными:
  13.       (setq filter_code (vlax-make-safearray vlax-vbinteger '(0 . 0)))
  14.       (setq filter_value (vlax-make-safearray vlax-vbvariant '(0 . 0)))
  15.       (vlax-safearray-fill filter_code '(0)); DXF-группы для фильтра
  16.       (vlax-safearray-fill filter_value '("INSERT"))
  17.       (vla-SelectAtPoint newSet (vlax-3d-point pt) filter_code filter_value)
  18.  
  19.       (vla-get-count newSet)
  20.     ); progn
  21.     (princ)
  22.   )

Но стоит только начертить отрезок от этой точки, как тот же самый код в итоге покажет 0 элементов в наборе!

Если кто-то сталкивался с этими особенностями и проблемами, прошу просветить  :)
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Александр Ривилис от 31-10-2015, 18:21:02
Я пожалуй дам хороший совет: "Забудь про SelectAtPoint". Если нужно выбрать все примитивы проходящие через точку - воспользуйся выбором по секущей рамке, задав её размеры порядка значения системной переменной APERTURE (или PICKBOX), пересчитанную в единицы чертежа.
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Macondo от 31-10-2015, 19:19:50
Я пожалуй дам хороший совет: "Забудь про SelectAtPoint"
Спасибо, запомню. Какие ещё функции-методы пометить красным крестиком? Кажется, Vla-IntersectWith иногда клинит?
задав её размеры порядка значения системной переменной APERTURE (или PICKBOX), пересчитанную в единицы чертежа
Это не очень понял. APERTURE 10, PICKBOX 3, единицы миллиметры. Отступить от точки указания в две противоположные стороны по 3 единицы?
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Александр Ривилис от 31-10-2015, 19:31:39
Это не очень понял. APERTURE 10, PICKBOX 3, единицы миллиметры. Отступить от точки указания в две противоположные стороны по 3 единицы?
Нет. Обе эти системных переменных в пикселях, а не в единицах чертежа. Так что нужно учесть масштабный коэффициент:
Код - Auto/Visual Lisp [Выбрать]
  1. (defun PIX2UNITS (pix) (* pix (/ (getvar "VIEWSIZE") (cadr (getvar "SCREENSIZE")))))
  2. (setq BOX (PIX2UNITS (getvar "PICKBOX"))) ;; Размер PICKBOX в единицах чертежа
Ну а дальше:
Код - Auto/Visual Lisp [Выбрать]
  1. (setq ss (ssget "_C" (mapcar '- p (list BOX BOX 0.0)) (mapcar '+ p (list BOX BOX 0.0)) ...)
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Александр Ривилис от 31-10-2015, 20:33:50
Кстати, что касается фильтра по расширенным данным, то:
Код - Auto/Visual Lisp [Выбрать]
  1. (ssget ... '((-3 ("MYAPP"))))
и никаких лишних скобок и апострофов, да еще и в строке.
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Macondo от 31-10-2015, 20:38:27
и никаких лишних скобок и апострофов, да еще и в строке
Это да, но только в случае ssget. Я рассчитывал на применение vla: они, вроде, более быстродействующие.
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Александр Ривилис от 31-10-2015, 21:36:14
Я рассчитывал на применение vla: они, вроде, более быстродействующие.
Очень сомневаюсь, что в данном случе будет какой-то выигрыш по времени, т.к. и та и другая функция используют одну и туже функцию из ObjectARX.
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Александр Ривилис от 31-10-2015, 22:40:02
Кстати, если фильтровать через vla-SelectXXX, то нужно для расширенных данных использовать группу 1001 (а не -3):
http://adndevblog.typepad.com/autocad/2012/05/making-a-filtered-selection-set-using-visual-lisp-activex-functions.html
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Macondo от 30-09-2016, 14:50:51
SSGET хорошо выполняет свою задачу, но только в пределах видимой части экрана. Допустим, пользователь ведёт длинный отрезок из точки А в точку B. Указав точку А, пользователь передвигает видимую область чертежа туда, где нужно поставить точку B, в результате чего в этот момент точка А не видна.
Как в этот момент узнать, какие объекты проходят через точку А? Я вижу вариант зумирования туда и обратно
Код - Auto/Visual Lisp [Выбрать]
  1. (vla-ZoomExtents (vlax-get-acad-object))
  2. ssget
  3. (vla-ZoomPrevious (vlax-get-acad-object))
Проблема в том, что если это массовые операции в цикле, то экран будет постоянно моргать от зума. Что тут можно сделать иначе?
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Александр Ривилис от 30-09-2016, 14:53:38
Что тут можно сделать иначе?
Ничего. Только не пользоваться ssget или терпеть "моргание"
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Macondo от 30-09-2016, 15:27:43
Очень жаль. В .NET тоже нет подобных методов, не зависящих от видимой области экрана?
Название: Re: Получение объектов, проходящих через точку (vla-SelectAtPont)
Отправлено: Александр Ривилис от 30-09-2016, 15:36:25
Очень жаль. В .NET тоже нет подобных методов, не зависящих от видимой области экрана?
Аналог (ssget)? Только такой же аналог. Но тут на форуме обсуждалось использование R-tree для быстрого поиска.