Автоматизация проектирования. Отвод.

В этой статье мы продолжим процесс автоматизации проектирования систем вентиляции.

Напомню, что в предыдущих уроках мы создали диалоговое окно, которое позволяет нам:

  • легко менять форму сечения воздуховода;
  • задавать расход воздуха;
  • и выбирать размер сечения воздуховода,  ориентируясь на скорость движения воздуха.

См. Рис. 1.

Автоматизация проектирования

Рис. 1.  Диалоговое окно.

Уроки, в которых об этом подробно рассказано:

«Диалоговое окно Автокад».

«Управление диалоговым окном».

Затем, мы добавили в нашу программу полезные функции.

Программа стала:

  • Стоить серию одинаковых воздуховодов;
  • Помнить, последний построенный воздуховод;
  • Сам воздуховод стал хранить в себе дополнительные данные.

См. Рис. 2.

Автоматизация проектирования

Рис. 2. Сеть воздуховодов.

Подробнее об этом Вы можете посмотреть в уроке: «Автоматизация проектирования».

Очевидно, что нашей серии воздуховодов не хватает отводов.

Отводы встречаются в системах вентиляции, теплоснабжения и холодоснабжения. Рисование их стандартными методами Автокад, часто занимает  много времени.

Давайте попробуем автоматизировать этот процесс.

Cпособов автоматизации может быть несколько. Поэтому перед началом давайте сформулируем, чего в результате хотим получить мы:

  1. Мы будем строить отводы, для прямоугольных воздуховодов.
  2. Отводы должны строится для любого сечения и под любым углом.
  3. На чертеже отводы должны быть представлены в виде блоков.

И так приступим.

Откройте Автокад.

Запустите редактор Visual LISP (наберите в командной строке VLIDE и нажмите <Enter>).

Откройте в нем программу pr_ush2.lsp.

Нажмите на кнопку «Загрузить активное окно редактора»

См. Рис. 3.

Автоматизация проектирования

Рис. 3. Программа pr_ush.lsp

Перейдите в AutoCAD.

В командной строке наберите: pr_uch и нажмите <Enter>

Появится диалоговое окно. См. Рис. 4.

Автоматизация проектирования

Рис. 4. Диалоговое окно.

Поменяйте форму сечения на «Прямоугольный».

Выберите размер сечения: «200х100» и нажмите ОК.

Постойте два воздуховода: один вдоль оси Х, другой с отклонением на 45 градусов. См. рис. 5.

Автоматизация проектирования

Рис. 5. Воздуховоды

В данном, конкретном случаи будем строить отвод 45 градусов

Создайте новый файл.

В начале, нам нужно получить координаты начальных и конечных точек воздуховодов.

Извлечение координаты точек.

При помощи функции entsel  просим указать воздуховод:

(entsel "\nВыберите воздуховод 1: ")

Строка вернет (Имя объекта и точку указания):

(<Имя объекта: 7ef046b0> (925.982 748.286 0.0))

Применим функцию car, чтобы оставить только имя:

(car (entsel "\nВыберите воздуховод 1: "))

Строка вернет:

<Имя объекта: 7ef046b0>

Сохраняем имя в переменной obj1:

(setq obj1 (car (entsel "\nВыберите воздуховод 1: ")))

Чтобы, пользователь видел, какой воздуховод он выбрал, в начале создадим пустой набор obj_set:

(setq obj_set (ssadd))
(ssadd) – создает пустой набор

Затем добавляем выбранный объект (воздуховод) в набор:

(ssadd obj1 obj_set)
obj1 – имя добавляемого объекта;
obj_set – имя набора.

И подсвечиваем элементы набора при помощи функции sssetfirst:

(sssetfirst nil (ssadd obj1 obj_set))

При помощи функции entget, получим список с характеристиками мультилинии (воздуховода). Сохраним его в переменной lst_ml1:

(setq lst_ml1 (entget obj1))

Строка вернет:

((-1 . <Имя объекта: 7ef046b0>) (0 . "MLINE") (5 . "2D6") 
(102 . "{ACAD_XDICTIONARY") (360 . <Имя объекта: 7ef046b8>) (102 . "}") 
(330 . <Имя объекта: 7ef05cf8>) (100 . "AcDbEntity") (67 . 0) 
(410 . "Model") (8 . "0") (100 . "AcDbMline") (2 . "VENP") 
(340 . <Имя объекта: 7ef04648>) (40 . 200.0) (70 . 1) (71 . 1) (72 . 2) 
(73 . 3) (10 142.558 646.25 0.0) (210 0.0 0.0 1.0) (11 142.558 646.25 0.0) 
(12 1.0 0.0 0.0) (13 -3.67321e-006 1.0 0.0) (74 . 2) (41 . 100.0) (41 . 0.0) 
(75 . 0) (74 . 2) (41 . 0.0) (41 . 0.0) (75 . 0) (74 . 2) (41 . -100.0) 
(41 . 0.0) (75 . 0) (11 1101.7 646.25 0.0) (12 1.0 0.0 0.0) 
(13 -3.67321e-006 1.0 0.0) (74 . 2) (41 . 100.0) (41 . 0.0) (75 . 0) (74 . 2) 
(41 . 0.0) (41 . 0.0) (75 . 0) (74 . 2) (41 . -100.0) (41 . 0.0) (75 . 0))

Координаты точек начала и конца воздуховода расположены в списке под Dxf-кодом 11.

Давайте извлечем их оттуда.  Создадим пользовательскую функцию lambda, внутри которой будем использовать функцию car, которая извлекает первый элемент из списка или из точечной пары (т. е.  Dxf-код):

(lambda (x) (= (car x) 11))
Lambda –  создание пользовательской функции;
Х – аргумент функции;
(car x) – пользовательская функция (извлекает первый Dxf-код из элемента);
11 – значение аргумента (если Dxf-код равен 11, функция lambda вернет T (True), в остальных случаях nil.

Чтобы применить нашу пользовательскую функции ко всем элементам списка и отбросить все не нужные, используем  vl-remove-if-not

(vl-remove-if-not '(lambda (x) (= (car x) 11)) lst_ml1)

vl-remove-if-not – применить  функцию (lambda (x) (= (car x) 11)) ко всем элементам списка:

Элементы списка, которые после применения функции (lambda (x) (= (car x) 11)), возвращают nil, будут исключены из списка lst_ml1

В списке останутся только элементы с Dxf-кодом 11. Строка вернет:

((11 142.558 646.25 0.0) (11 1101.7 646.25 0.0))

Чтобы избавится от кода 11, используя mapcar, ко всем оставшимся элементам применим функцию cdr

(mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 11)) lst_ml1))

Строка вернет:

((142.558 646.25 0.0) (1101.7 646.25 0.0))

Сохраним список координат в переменной coor1:

(setq coor1 (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 11)) lst_ml1)))

Чтобы получиn координаты начальной точки, используем функцию nth

(nth 0 coor1)

Функция nth извлекает из списка coor1 элемент с порядковым номером 0 (первый элемент списка)

Строка вернет:

(142.558 646.25 0.0)

Сохраним координаты начальной точки воздуховода в переменной pm11:

(setq pm11 (nth 0 coor1))

Аналогичным способом извлекаем координаты, второй (конечной) точки и сохраняем их в переменной pm12:

(setq pm12 (nth 1 coor1))

Добавляем все вышесказанное в программу. См. Рис. 6.

Автоматизация проектирования

Рис. 6. Извлечение координат точек.

Выделите весь текст и нажмите на кнопку «Загрузить выделенный фрагмент».

Программа переведет Вас в AutoCAD, где нужно выбрать воздуховод.

После этого программа вернет Вас в Редактор Visual LISP.

Мы видим на рис 6, что последние строки возвращают координаты нужных нам точек.

Если сейчас перейти в AutoCAD, то Вы уведите, что выбранный воздуховод подсвечен. См. Рис. 7.

Автоматизация проектирования

Рис. 7. Выбранный воздуховод подсвечен.

Определяем угол наклона воздуховода.

Давайте определим угол наклона нашего воздуховода, относительно оси Х. Значение угла сохраняем в переменной alf1:

(setq alf1 (angle pm11 pm12))
Angle – функция возвращающая угол наклона прямой;
pm11 – начальная точка прямой;
pm12 – конечная точка прямой;

Строка вернет: значение угла в радианах.

Углы между различными направлениями и осью Х в градусах и радианах Вы можете на рис. 8.

Автоматизация проектирования

Рис. 8. Углы наклона прямой.

Аналогичные действия выполняем и со вторым воздуховодом:

(setq obj2 (car (entsel "\nВыберите воздуховод 2:")))
(sssetfirst nil (ssadd obj2 obj_set))
(setq lst_ml2 (entget obj2))
(setq coor2 (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 11)) lst_ml2)))
(setq pm21 (nth 0 coor2))
(setq pm22 (nth 1 coor2))
(setq alf2 (angle pm21 pm22))

Теперь наша программа выглядит так. См. рис. 9.

Автоматизация проектирования

Рис. 9. Извлечение координат второго воздуховода.

Угол поворота отвода.

Чтобы определить угол поворота отвода отнимаем от alf2  alf1

(- alf2 alf1)

Чтобы, значение всегда было положительным, берем от разности модуль:

(abs(- alf2 alf1))

Сохраняем значение в переменной alf :

(setq alf (abs(- alf2 alf1)))

Но между двумя направлениями, могут быть определены два угла.

См. Рис. 10

Автоматизация проектирования

Рис. 10. Два угла.

Что бы исключить угол, который больше (Pi) 180 градусов, добавляем следующее условие:

(if (> alf pi) (setq alf (- (* pi 2) alf)))

Если alf больше pi, то пересчитываем его. Новый угол получается путем отнимания от 360 градусов, старого угла.

Чтобы перевести радианы в градусы и узнать, чему наш угол равен в градусах. Угол в радианах умножаем на 180 и делим на pi. Результат сохраняем в переменной alfg.

(setq alfg (/ (* alf 180) pi))

Добавляем вышесказанное в программу. См. Рис. 11.

Автоматизация проектирования

Рис. 11. Угол поворота отвода

Определение ширины воздуховода.

Мы помним, что наш воздуховод хранит в себе дополнительные данные. Чтобы их извлечь, загружаем функции расширения:

(vl-load-com)

Преобразуем первый воздуховод в VLA-объект:

(setq vla_puch (vlax-ename->vla-object obj1))

Извлекаем из него данные под кодом «Razmer»:

(vlax-ldata-get  vla_puch "Razmer")

Строка вернет:

"200x100"

Сохраняем размер в переменной RazP

(setq RazP (vlax-ldata-get vla_puch "Razmer"))

Определяем место нахождение «х» и сохраняем его в переменной n:

(setq n (vl-string-search "x" RazP))

Строка вернет: 3

Определяем ширину воздуховода и сохраняем ее в переменной Raz:

(setq Raz (atoi (substr RazP 1 n)))

Строка вернет: 200

Определение координат точек для построения отвода.

Давайте определим координаты точек для построения отвода.

В начале, зададим радиус закругления:

(setq ra 150)

Затем определим координаты точку пересечения осей воздуховодов рр. См. Рис. 12

Автоматизация проектирования

Рис. 12. Точки для построения отвода.

(setq pp (inters pm11 pm12 pm21 pm22 nil))

Функция inters вычисляет координаты точки пересечения двух прямых, одна из которых задана точками  pm11 pm12, другая точками pm21 pm22.

Определяем расстояние между точками pt1 и pt3 (См. Рис. 12), которое равно половине ширины воздуховода:

(setq R (/ Raz 2))

После чего, мы можем определить расстояние между точками pt1 и pt (См. Рис. 12):

(+ R ra)

Рассмотрим треугольник pt pt1 рр (См. Рис. 12). Мы видим, что если расстояние pt pt1, умножить на котангенс половины угла alf, то мы определим длину между точками pt1 рр. Сохраним значение этого расстояния в переменной AB:

(setq AB (* (+ R ra) (/ (sin (/ alf 2)) (cos (/ alf 2)))))
(+ R ra) – расстояние между точками pt и pt1;
(/ (sin (/ alf 2)) (cos (/ alf 2))) - котангенс половины угла alf.

Далее определяем, координаты точки ot1 относительно точки рр (См. Рис. 12):

(setq ot1 (polar pp pi AB))

Координаты точек ot2 и ot3 относительно точки ot1 (См. Рис. 12):

(setq ot2 (polar ot1 (/ pi 2) R))
(setq ot3 (polar ot1 (/ pi 2) (- R)))

Координаты точки ot относительно точки ot3 (См. Рис. 12):

(setq ot (polar ot3 (/ pi 2) (- ra)))

И координаты точек ot4 и ot5 относительно точки ot (См. Рис. 12):

(setq ot4 (polar ot (- (/ pi 2) alf) ra))
(setq ot5 (polar ot (- (/ pi 2) alf) (+ Raz ra)))

Чтобы проверить, что точки определены верно, рисуем два отрезка:

Между точками ot2 ot3

(command  "_line" ot2 ot3 "")

И точками ot4 ot5

(command  "_line" ot4 ot5 "")

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

Для этого:

Запоминаем в переменной osm привязки пользователя:

(setq osm (getvar "osmode"))

Выключаем привязки:

(setvar "osmode" 0)

И когда, построение завершены, возвращаем привязки пользователя:

(setvar "osmode" osm)

Добавляем все вышесказанное в программу. См. Рис. 13.

Автоматизация проектирования

Рис. 13. Точки для построения отвода.

Нажмите на кнопку «Загрузить активное окно редактора».

Программа переведет Вас в AutoCAD, где нужно указать два воздуховода.

После чего, программа вас снова вернет в редактор Visual LISP.

Снова переедите в AutoCAD. Мы видим, что наши отрезки нарисованы правильно. См. рис. 14.

Автоматизация проектирования

Рис. 14. Проверка.

Удалите отрезки с чертежа и из программы. Теперь можно приступить к построению отвода и созданию блока.

Построение отвода и создание блока.

Созданию блока программным  путем уже посвящены две статьи. Более подробно с этим вопросом Вы можете ознакомиться в уроках:

«AutoLISP. Создание блока».

«LISP. Создание блока».

Здесь мы создадим блок вторым способом с помощью функций расширения ActiveX и осветим этот вопрос кратко.

Добираемся до указателя пространства модели

(setq acad_application (vlax-get-acad-object))
(setq active_document (vla-get-activedocument acad_application))
(setq model_space (vla-get-modelspace active_document))

Зададим имя блока:

(setq bl_name (STRCAT "otv" RazP "_" (rtos alfg 2 0)))

Строка вернет:

"otv200x100_45"
Otv – отвод;
200x100 – размер сечения;
45 – угол поворота.

Проверяем существования блока с таким именем:

(if (not (tblsearch "block" bl_name))
  <Создание блока>
)

Если нет, то создаем.

Чтобы блок менял свой цвет, согласно слою, на котором он находится, его нужно создавать на слое «0».

Запоминаем текущий слой:

(setq lay (getvar "CLAYER"))

Делаем текущим слой «0»

(setvar "CLAYER" "0")

После того как блок создан, возвращаем слой, который был текущим до создания блока.

(setvar "CLAYER" lay)

Добавляем новый блок:

(setq blk_otv(vla-add(vla-get-blocks active_document)(vlax-3d-point pp)bl_name))
(vla-add (vla-get-blocks active_document) – добавляем в словарь блоков 
активного документа;
(vlax-3d-point pp) – базовая точка блока;
bl_name – имя блока.

Строим внутри блока отрезки между точками  ot2 и ot3:

(vla-addline blk_otv (vlax-3d-point ot2) (vlax-3d-point ot3))

И точками  ot4 и ot5:

(vla-addline blk_otv (vlax-3d-point ot4) (vlax-3d-point ot5))

Строим внутри блока дуги:

Внешняя дуга отвода:

(vla-addarc blk_otv (vlax-3d-point ot) (+ Raz ra) (- (/ pi 2) alf) (/ pi 2))
(vlax-3d-point ot) – центр дуги;
(+ Raz ra) –радиус дуги;
(- (/ pi 2) alf) – угол начало дугу;
(/ pi 2) – угол окончания дуги

Внутренняя дуга отвода:

(vla-addarc blk_otv (vlax-3d-point ot) ra (- (/ pi 2) alf) (/ pi 2))

Дуга оси отвода:

(setq d_o (vla-addarc blk_otv (vlax-3d-point ot)(+ R ra)(-(/ pi 2) alf)(/ pi 2)))

Имя оси отвода сохраняем в переменной d_o.

Меняем цвет дуги отвода:

(vlax-put-property d_o 'Color 3)
vlax-put-property – функция меняющая свойство Vla-объекта;
d_o – переменная, в которой храниться имя Vla-объекта;
Color – свойство, которое изменяем;
3 – новое значение свойства.

Вставка блока:

(setq vla_bl(vla-insertblock model_space(vlax-3d-point pp) bl_name 1. 1. 1. alf1))
vla-insertblock –функция вставки блока;
model_space – место, куда вставляем блок (пространство модели);
(vlax-3d-point pp) – точка вставки;
1. 1. 1. – масштаб по осям X, Y и Z;
alf1 – угол поворота блока.

Добавляем все вышесказанное в программу. См. Рис. 15.

Автоматизация проектирования

Рис. 15. Построение отвода и создание блока.

В результате, перед вставкой отвода, программа проверяет, существует ли нужный отвод:

Если существует, то вставляет его;

Если нет, создает новый и вставляет только, что созданный блок.

Все блоки создаются на «0» слое с углом поворота 0 градусов. Угол вставки блока зависит от угла прямого участка воздуховода, выбранного при запросе первым.

Нажмите на кнопку «Загрузить активное окно редактора».

Программа переведет Вас в AutoCAD, где нужно указать два воздуховода.

После чего, программа  снова вернет Вас в редактор Visual LISP.

Снова переедите в AutoCAD. Мы видим, что программа построила отвод. См. рис. 16

Автоматизация проектирования

Рис. 16. Отвод.

И нам остается лишь отредактировать прямые участки воздуховода.

Если заглянуть в диалоговое окно вставки блока, Вы обнаружите, что там появился новый блок «otv200x100_45″. См.Рис. 17.

Автоматизация проектирования

Рис. 17. Диалоговое окно «Вставки блока»

Редактирование прямых участков воздуховода.

Определяем координаты точек np1 и np2. См. Рис. 18.

Автоматизация проектирования

Рис.18. Расположение точек np1 и np2

Определяем координаты точки np1.

(setq np1 (polar pp alf1 (- AB)))

Строка вернет: координаты точки

(998.15 646.25 0.0)

Определяем координаты точки np2.

(setq np2 (polar pp alf2 AB))

Строка вернет: координаты точки

(1174.93 573.027 0.0)

Даже имея координаты нужных точек, отредактировать воздуховод (мультилинию), не так уж просто. Легче удалить его и построить по новым точкам, новую мультилинию. Тем более мы уже научились делать это в предыдущих уроках.

И тем, немее давайте попытаемся это сделать.

Преобразуем первый воздуховод в Vla-oбъект:

(setq vla_obj1 (vlax-ename->vla-object obj1))

Строка вернет: Имя Vla-oбъекта

Сложность редактирования Vla-oбъекта мультилинии заключается в том, что координаты начальной и конечной точек должны быть  представлены в особом виде.

Давайте приведем наши координаты к этому виду:

Объединим координаты  точек  pm11  и np1 в единый список:

(setq coord (append pm11 np1))

Строка вернет: объединенный список

(142.558 646.25 0.0 998.15 646.25 0.0)

Создадим безопасный массив saf_ar, с количеством элементов равным 6:

(setq saf_ar (vlax-make-safearray vlax-vbDouble '(1 . 6)))
vlax-make-safearray – создает безопасный массив;
vlax-vbDouble – тип данных, которые будут храниться в безопасном массиве 
(вещественное число с двоичной точностью);
(1 . 6) – размер безопасного массива 
(массив начинается с элемента 1; заканчивается элементом 6).

Заполним безопасный массив saf_ar данными из списка coord

(vlax-safearray-fill saf_ar coord)

Количество элементов в списке должно совпадать с количеством элементов в безопасном массиве.

Приведем безопасный массив к типу variant:

(vlax-make-variant (vlax-safearray-fill saf_ar coord))

Сохраним variant, в котором хранятся координаты точек, в переменной var_coord:

(setq var_coord (vlax-make-variant (vlax-safearray-fill saf_ar coord)))

Меняем координаты у первого воздуховода:

(vlax-put-property vla_obj1 'coordinates var_coord)
vlax-put-property – функция меняющая свойство Vla-объекта;
vla_obj1  – переменная, в которой храниться имя Vla-объекта;
coordinates – свойство, которое изменяем;
var_coord – переменная, в которой хранится новое значение свойства.

Обновляем данные в Vla-объекте:

(vla-update vla_obj1)

Добавляем все вышесказанное в программу. См. Рис. 19.

Автоматизация проектирования

Рис. 19. Редактирование прямых участков воздуховода.

Выделите только, что добавленные строки и нажмите на кнопку «Загрузить выделенный фрагмент».

Перейдите AutoCAD. Мы видим, что произошло редактирование первого воздуховода. См. Рис. 20.

Автоматизация проектирования

Рис. 20. Первый прямой участок.

Аналогично, редактируем второй воздуховод:

(setq vla_obj2 (vlax-ename->vla-object obj2))
(setq coord (append np2 pm22))
(setq var_coord (vlax-make-variant (vlax-safearray-fill saf_ar coord)))
(vlax-put-property vla_obj2 'coordinates var_coord)
(vla-update vla_obj2)

Вы наверное заметили, что наши воздуховоды все еще выделены.

Давайте, снимаем с них выделение:

(sssetfirst nil nil)

Добавляем строки в программу. См. Рис. 21.

Автоматизация проектирования

Рис. 21. Редактирование второго участка.

Выделите только, что добавленные строки и нажмите на кнопку «Загрузить выделенный фрагмент».

Перейдите AutoCAD. Мы видим, что произошло редактирование второго  воздуховода. См. Рис. 22.

Автоматизация проектирования

Рис. 22. Второй участок воздуховода.

Преобразуем программу в команду Автокад.

Давайте нашу программу, при помощи функции defun, преобразуем в команду Автокад:

В начале программы добавим строку, в которой придумаем имя новой команды p_otv и перечислим все временные переменные:

(defun c:p_otv (/ obj_set obj1 lst_ml1 coor1 pm11 pm12 alf1 obj2 lst_ml2 coor2
                  pm21 pm22 alf2 alf alfg vla_puch RazP n Raz ra pp R AB ot ot1
                  ot2 ot3 ot4 ot5 osm acad_application active_document 
                  model_space bl_name lay blk_otv d_o
                  vla_bl np1 np2 vla_obj1 coord saf_ar var_coord vla_obj2)
    <наша программа>
); end_defun

В конце программы добавим закрывающую скобку.

Сохраните программы по именем P_otv.lst.

Теперь наша программа выглядит так. См. Рис. 23.

Автоматизация проектирования

рис. 23. Преобразуем программу в команду Автокад.

Давайте проверим, правильно ли работает программа?

Нажмите на кнопку «Загрузить активное окно редактора».

Перейдите AutoCAD.

В начале давайте построим серию воздуховодов. Наберите в командной строке pr_uch, нажмите <Enter> и постройте серию воздуховодов под произвольными углами, двигаясь почасовой стрелке. См. Рис. 24.

Автоматизация проектирования

Рис. 24. Сеть воздуховодов.

Затем наберите в командной строке p_otv, нажмите <Enter> и на запрос “Выберите воздуховод», укажите, в начале, первый, а затем второй воздуховод. Программа построит между ними отвод.

Снова нажмите <Enter>, чтобы повторить программу. Укажите второй и третий воздуховоды. Программа построит отвод между ними.

Затем постройте отвод между 4 и 5, 5 и 6. См. Рис. 25.

Автоматизация проектирования

Рис. 25. Отводы

Чтобы программа правильно строила отводы, воздуховоды нужно указывать в той последовательности в какой они были построены. Если, например, указать вначале 2-ой воздуховод, а затем 1-ый, отвод будет построен не верно.

Выбор воздуховодов в любой последовательности.

Давайте добавим в программу код, который позволит  пользователю выбирать воздуховоды в любой последовательности.

Если пользователь укажет воздуховоды в правильной последовательности (сначала 1-ый затем 2-ой).

Координаты точек относительно переменных будут выглядеть так. См. Рис. 26.

Автоматизация проектирования

Рис. 26. Правильная последовательность.

Если пользователь укажет воздуховоды в неправильно (сначала 2-ый затем 1-ой).

Координаты точек относительно переменных будут выглядеть так. См. Рис. 27.

Автоматизация проектирования

Рис. 27. Неправильная последовательность указания.

Обратите внимание, что расстояние между точками pm11 и pm22 стало равно 0. А между точками pm12 и pm21 увеличилось.

Давайте используем, эту закономерность.

Определим расстояние  между точками pm11 и pm22:

(setq dis1 (distance pm11 pm22))

И между точками pm12 и pm21:

(setq dis2 (distance pm12 pm21))

Добавим условие:

(if (< dis1 dis2)
  (prong
    <выражения>
  ); end prong
); end if

Если расстояние dis1 меньше dis2, то coor1 и coor2 меняем местами.

(setq coor1a coor1)
(setq coor1 coor2)
(setq coor2 coor1a)

Затем, заново определяем координаты точек и угол наклона:

Для первого воздуховода.

(setq pm11 (nth 0 coor1))
(setq pm12 (nth 1 coor1))
(setq alf1 (angle pm11 pm12))

И для второго воздуховода.

(setq pm21 (nth 0 coor2))
(setq pm22 (nth 1 coor2))
(setq alf2 (angle pm21 pm22))

Добавим вышесказанное в программу. См. Рис. 28.

Автоматизация проектирования

Рис. 28. Любая последовательность указания воздуховодов.

Теперь, пользователь может указывать воздуховоды в любой последовательности.

Сеть воздуховодов. Движение против часовой стрелки.

Теперь давайте, снова построим сеть воздуховодов, но при построении будем двигаться против часовой стрелки. См. Рис. 29.

Автоматизация проектирования

Рис. 29. Сеть воздуховодов.

Если Вы сейчас, попробуете, построит отводы при помощи нашей программы, все они построятся неверно. Причем, угол поворота будет определен верно, но все отводы поворачивают в сторону движения  часовой стрелки. См. Рис. 30

Автоматизация проектирования

Рис. 30. Отводы

Определяем угол вставки блока.

Очевидно, что перед тем как вставить отвод, нам нужно определить, куда он поворачивает: почасовой стрелке или против.

Как это сделать?

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

Для любителей головоломок предлагаю пока не читать статью дальше и попытаться решить эту задачу самостоятельно. И только потом сравнить с моим решением.

Может Вам удастся найти иное решение. Напишите об этом в комментариях.

Давайте расскажу о своем способе.

Я заметил, что если первый воздуховод расположить по направлению оси Х, то куда пойдет второй воздуховод, можно определить по изменению координаты Y. См. Рис. 31.

Автоматизация проектирования

Рис. 31. Изменение координаты Y.

Если Y уменьшается, воздуховод повернул по часовой стрелке, если увеличивается то против.

Вроде бы все просто, но как это определить если воздуховоды сориентированы по другому. См. Рис. 32.

Автоматизация проектирования

Рис. 32. Другая ориентация воздуховодов.

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

Решение, которое пришло мне в голову очень простое.

Я мысленно поворачиваю воздуховоды так, чтобы первый был направлен по оси Х,  и тогда в какую сторону повернул второй, определяется легко.

Давайте определим это программно.

Чтобы сделать, код программы короче, я использовал не разницу между значениями Y, а синус угла наклона прямой между точками pm11, pm22.

См. Рис. 33.

Автоматизация проектирования

Рис. 33. Синус угла наклона прямой

Если синус угла положительный, воздуховод повернул против часовой стрелки.

Если синус угла отрицательный, воздуховод повернул по часовой стрелки.

Определяем текущий угол наклона прямой pm11  pm22:

(setq ugl (angle pml11 pml22))

Отнимаем от этого угла, угол наклона первого воздуховода (тем самым мысленно поворачиваем воздуховоды, так, чтобы 1-ый воздуховод был расположен по направлению оси Х).

(- ugl alf1)

Берем от разницы синус и сохраняем значение в переменной znak:

(setq znak (sin (- ugl alf1)))

Добавляем условие:

(if (< znak 0) (setq alfv alf1) (setq alfv (+ (- alf1 pi) alf)))

Если znak меньше нуля

(< znak 0)

Угол вставки отвода alfv делаем равным alf1

(setq alfv alf1)

В противном случае, Угол вставки alfv будет равным (+ (- alf1 pi) alf)

(setq alfv (+ (- alf1 pi) alf))

В строке вставки блока:

(setq vla_bl (vla-insertblock model_space (vlax-3d-point pp) bl_name 1. 1. 1. alf1))

Меняем alf1 на alfv

(setq vla_bl (vla-insertblock model_space (vlax-3d-point pp) bl_name 1. 1. 1. alfv))

Добавим новые переменные dis1 dis2 coor1a ugl znak alfv в список описания временных переменных .

Окончательный вариант программы. См. Рис. 34.

Автоматизация проектирования

Рис. 34. Окончательный вариант программы.

Нажмите на кнопку «Загрузить активное окно редактора».

Перейдите AutoCAD.

При помощи команды pr_uch, постройте серию воздуховодов  так, чтобы они поворачивали и по часовой, и против часовой стрелки.  См. Рис. 35.

Автоматизация проектирования

Рис. 35. Сеть воздуховодов.

При помощи команды p_otv, постойте отводы. См. Рис. 36.

Автоматизация проектирования

Рис. 36. Отводы

Программный код:

(defun c:p_otv (/ obj_set obj1 lst_ml1 coor1 pm11 pm12 alf1 obj2 lst_ml2
                coor2 pm21 pm22 alf2 alf alfg vla_puch RazP n Raz ra pp
                R AB ot ot1 ot2 ot3 ot4 ot5 osm acad_application
                active_document model_space bl_name lay blk_otv d_o 
                vla_bl np1 np2 vla_obj1 coord saf_ar var_coord vla_obj2
                dis1 dis2 coor1a ugl znak alfv)
  (setq obj_set (ssadd))
  (setq obj1 (car (entsel "\nВыберите воздуховод 1: ")))
  (sssetfirst nil (ssadd obj1 obj_set))
  (setq lst_ml1 (entget obj1)) 
  (setq coor1 (mapcar 'cdr (vl-remove-if-not '(lambda (x)(=(car x) 11))
               lst_ml1)))
  (setq pm11 (nth 0 coor1))
  (setq pm12 (nth 1 coor1))
  (setq alf1 (angle pm11 pm12))
  ;------------------------
  (setq obj2 (car (entsel "\nВыберите воздуховод 2: ")))
  (sssetfirst nil (ssadd obj2 obj_set))
  (setq lst_ml2 (entget obj2)) 
  (setq coor2 (mapcar 'cdr (vl-remove-if-not '(lambda (x)(=(car x) 11))
               lst_ml2)))
  (setq pm21 (nth 0 coor2))
  (setq pm22 (nth 1 coor2))
  (setq alf2 (angle pm21 pm22))
  ;------------------------------------
  (setq dis1 (distance pm11 pm22))
  (setq dis2 (distance pm12 pm21))
  (if (< dis1 dis2)
    (progn
      (setq coor1a coor1)
      (setq coor1 coor2)
      (setq coor2 coor1a)
      (setq pm11 (nth 0 coor1))
      (setq pm12 (nth 1 coor1))
      (setq alf1 (angle pm11 pm12))
      (setq pm21 (nth 0 coor2))
      (setq pm22 (nth 1 coor2))
      (setq alf2 (angle pm21 pm22)
    );end progn
  ); end if 
  ;-------------------------------------------------------------
  (setq alf (abs(- alf2 alf1)))
  (if (> alf pi) (setq alf (- (* pi 2) alf))
  (setq alfg (/ (* alf 180) pi))
  (setq ugl (angle pm11 pm22))
  (setq znak (sin (- ugl alf1)))
  (if (< znak 0) (setq alfv alf1) (setq alfv (+ (- alf1 pi) alf)))
  ;-------------------------------------------------------------
  (vl-load-com)
  (setq vla_puch (vlax-ename->vla-object obj1))
  (setq RazP (vlax-ldata-get vla_puch "Razmer"))
  (setq n (vl-string-search "x" RazP))
  (setq Raz (atoi (substr RazP 1 n)))
  ;-------------------------------------------------------------
  (setq ra 150)
  (setq pp (inters pm11 pm12 pm21 pm22 nil))
  (setq R (/ Raz 2))
  (setq AB (* (+ R ra) (/ (sin (/ alf 2)) (cos (/ alf 2)))))
 
  (setq ot1 (polar pp pi AB))
  (setq ot2 (polar ot1 (/ pi 2) R))
  (setq ot3 (polar ot1 (/ pi 2) (- R)))
  (setq ot (polar ot3 (/ pi 2) (- ra)))
  (setq ot4 (polar ot (- (/ pi 2) alf) ra))
  (setq ot5 (polar ot (- (/ pi 2) alf) (+ Raz ra)))
  ;-------------------------------------------------------------
  (setq osm (getvar "osmode")); запоминаем привязки пользователя
  (setvar "osmode" 0) ; отключаем привязки
  (setq acad_application (vlax-get-acad-object))
  (setq active_document (vla-get-activedocument acad_application))
  (setq model_space (vla-get-modelspace active_document)) 
 
  (setq bl_name (STRCAT "otv" RazP "_" (rtos alfg 2 0)));задаем имя блока
  (if (not (tblsearch "block" bl_name))
    (progn
      (setq lay (getvar "CLAYER")) ; запоминаем текущий слой пользователя
      (setvar "CLAYER" "0")        ; делаем текущим слой "0"
      (setq blk_otv (vla-add(vla-get-blocks active_document)
                     (vlax-3d-point pp) bl_name))
      (vla-addline blk_otv (vlax-3d-point ot2) (vlax-3d-point ot3)) 
      (vla-addline blk_otv (vlax-3d-point ot4) (vlax-3d-point ot5))
 
      (vla-addarc blk_otv (vlax-3d-point ot) (+ Raz ra) (- (/ pi 2) alf)
                                              (/ pi 2))
      (vla-addarc blk_otv (vlax-3d-point ot) ra (- (/ pi 2) alf) (/ pi 2))
      (setq d_o (vla-addarc blk_otv (vlax-3d-point ot) (+ R ra)
                 (- (/ pi 2) alf)(/ pi 2))) 
      (vlax-put-property d_o 'Color 3)
 
      (setvar "CLAYER" lay) ; делаем текущим слой пользователя
    ); end progn
  ); end if
  (setq vla_bl (vla-insertblock model_space (vlax-3d-point pp) bl_name
                1. 1. 1. alfv))
  (setvar "osmode" osm) ; возвращает привязки пользователя
  ;-------------------------------------------------------------
  (setq np1 (polar pp alf1 (- AB)))
  (setq np2 (polar pp alf2 AB))
  (setq vla_obj1 (vlax-ename->vla-object obj1))
  (setq coord (append pm11 np1))
  (setq saf_ar (vlax-make-safearray vlax-vbDouble '(1 . 6)))
  (setq var_coord (vlax-make-variant (vlax-safearray-fill saf_ar coord)))
  (vlax-put-property vla_obj1 'coordinates var_coord)
  (vla-update vla_obj1)
  (setq vla_obj2 (vlax-ename->vla-object obj2))
  (setq coord (append np2 pm22)) 
  (setq var_coord (vlax-make-variant (vlax-safearray-fill saf_ar coord)))
  (vlax-put-property vla_obj2 'coordinates var_coord)
  (vla-update vla_obj2)
  (sssetfirst nil nil)
); end_defun

На этом наш урок окончен. В нем мы продолжили процесс автоматизации проектирования систем вентиляции и создали программу, которая стоит отводы.

Если у Вас появились вопросы, задавайте их в комментариях.

Если Вы нашли что-то полезное на моем сайте не забудьте порекомендовать статью в социальных сетях.

Пишите в комментариях или мне на почту Ваши пожелания о том, какие статьи Вы хотели бы увидеть на моем сайте.

Хотите получать информацию о выходе новых статей. Оформляйте подписку.

До новых встреч.

«Автор: Михаил Орлов»

Также на эту тему Вы можете почитать:

2 комментарии на “Автоматизация проектирования. Отвод.

  1. Антон 14.03.2015 19:32

    Супер! Так и проситься добавить возможность изменять размер воздуховода. Может оптимально было бы добавить программку в контекстное меню? Не знаю как не прерывая «рисования воздуховодов» можно было бы нажатием ПКМ и выбора програмки вызвать желаемое «стартовое» диалоговое окно. У полещука нашел такой код:

    (defun item_shcmenu ( / _mg _pm _it)
      (vl-load-com)
      (setq _mg (vla-item(vla-get-menugroups(vlax-get-acad-object))"ACAD"))
      (setq _pm (vla-item (Vla-get-menus _mg) "Меню по умолчанию"))
      (setq _it (vla-Addmenuitem _pm 0 "Размер" "p_otv"))
      (if _it (vla-put-helpstring _it "Задайте размер воздуховода"))
      (princ)
    )
    • Михаил Орлов 16.03.2015 18:05

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

Оставить комментарий

Ваш mail не будет опубликован.

Вы можете использовать HTML теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>