Вы находитесь на странице: 1из 43

AVEVA

ОФФЛАЙН ВЕРСИЯ САЙТА PML.DABACON.RU


Помощь в программировании на макроязыке PML
cистем AVEVA PDMS и AVEVA MARINE

СОДЕРЖАНИЕ
01.Об AVEVA ................................................................................................................................................................. 3
02.Об AVEVA PDMS и AVEVA MARINE ......................................................................................................................... 3
03.Об этом блоге (справочнике) ................................................................................................................................. 3
04.Терминология ......................................................................................................................................................... 4
05.Что такое PML .......................................................................................................................................................... 4
06.Базовые конструкции языка. Условия................................................................................................................... 5
07.Запросы к Dabacon. Часть 1.................................................................................................................................... 5
08.Базовые конструкции языка. Работа с циклами. Часть 1 .................................................................................... 6
09.Пример работы с базой .......................................................................................................................................... 6
10.Базовые конструкции языка. Работа с циклами. Часть 2 .................................................................................... 7
11.Запросы к Dabacon. Часть 2.................................................................................................................................... 7
12.Работа с файлами. Часть 1 ..................................................................................................................................... 8
13.Работа с графикой. Часть 1 ..................................................................................................................................... 8
14.Работа со строками. Часть 1 ................................................................................................................................... 9
15.Работа с графикой. Часть 2 ................................................................................................................................... 10
16.Пример работы с коллекцией ............................................................................................................................. 11
17.Сообщения пользователю. Часть 1 ..................................................................................................................... 11
18.Пример использования коллекций. Обработка модели................................................................................... 12
19.Пример редактирования атрибутов .................................................................................................................... 13
20.Работа с датой и временем ................................................................................................................................. 14
21.Пример обработки ссылок ................................................................................................................................... 14
22.Пример обработки ссылок. Продолжение ......................................................................................................... 15
23.Автоматизация работы администратора. Часть 1 .............................................................................................. 15
24.Автоматизация работы администратора. Часть 2 .............................................................................................. 16
25.Механизмы работы с объектами. Часть 1 .......................................................................................................... 17
26.Автоматизация работы администратора. Часть 3 .............................................................................................. 18
27.Автоматизация работы администратора. Часть 4,5 ........................................................................................... 18
28.Автоматизация работы администратора. Часть 6,7 ........................................................................................... 19
29.Работа с графикой. Часть 3 ................................................................................................................................... 20
30.Пользовательские проверки данных построения ............................................................................................. 20
31.Файловый проводник ........................................................................................................................................... 22
32.Автоотключение MTOC при создании трубопроводного компонента ............................................................ 22
33.Массовая печать из Draft в DXF/PDF ................................................................................................................... 23
34.Визуальное отображение "головы"/"хвоста" трубопровода ............................................................................ 24
35.Макрос для подсчета элементов......................................................................................................................... 24
36.Подсчет количества сварных швов ..................................................................................................................... 25
37.Разбивка трубопровода фланцами ..................................................................................................................... 26
38.Масштабирование и центрирование содержимого экрана ............................................................................. 27
39.Нахождение коллизий указанного элемента ..................................................................................................... 28
40.Описание опор в зависимости от координаты .................................................................................................. 29
41.Автоизменение параметров каталога................................................................................................................. 29
42.Удаление элементов с помощью графического выделения ............................................................................. 29
43.Раскрашивание элементов бранча в 3D-модели ............................................................................................... 30
44.Когда длина детального текста превышает 120 символов... ............................................................................ 30
45.Вычисляем реальную длину текста на чертеже ................................................................................................. 31
46.Маркировка в Design выбранным атрибутом .................................................................................................... 31
47.Пример команды FLIP для SCTN .......................................................................................................................... 32
48.Пишем свой класс на PML 2. Часть 1 ................................................................................................................... 32
49.Пишем свой класс на PML 2. Часть 2 ................................................................................................................... 32

Автор: Сергей Лебедев


AVEVA

50.Как работать с новым классом ............................................................................................................................ 33


51.Вычисление длины текста. Продолжение .......................................................................................................... 34
52.Найти связанные системы, обвязку .................................................................................................................... 34
53.Создание разрыва на чертеже ............................................................................................................................ 35
54.Расширяем возможности PML ............................................................................................................................. 37
55.Автозапуск формы или функции ......................................................................................................................... 38
56.Пример сортировки сложного массива по одной из составных частей .......................................................... 39
57.Коллекция элементов - Drawlist + Volume .......................................................................................................... 39
58.Замена отводов на гибы и наоборот .................................................................................................................. 40
59.Пример проверки битых ссылок и отчет ............................................................................................................ 42
60.Пример сохранения текущего Drawlist в файл ................................................................................................... 43

Автор: Сергей Лебедев


AVEVA

01.Об AVEVA
Компания AVEVA является ведущим разработчиком решений для проектирования, инжиниринга и
управления проектами в нефтегазовой, энергетической, судостроительной и шельфовой промышленности.

Система интегрированных решений AVEVA сопровождает объект на всем протяжении его жизненного цикла
- от создания проекта и его разработки, до управления проектными данными, технического обслуживания,
модернизации и вывода объекта из эксплуатации. Решения AVEVA позволяют инжиниринговым компаниям
максимально эффективно осуществлять проектные работы по всем дисциплинам, а эксплуатирующим
организациям дают возможность управлять всеми данными и процессами на базе единой платформы, что в
разы сокращает материальные и временные затраты.

ООО “АВЕВА” – дочерняя компания Aveva Group Plc., осуществляющая свою деятельность на территории
России и стран СНГ. Решения, прошедшие проверку многолетним международным опытом работы
крупнейших организаций и ставшие мировым стандартом, на сегодняшний день адаптированы к условиям
российского рынка. Клиенты ООО “АВЕВА” - это ведущие компании энергетической промышленности,
нефтегазового сектора и судостроения.

Официальный сайт - http://www.aveva.com/en.aspx?sc_lang=ru-RU

02.Об AVEVA PDMS и AVEVA MARINE


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

AVEVA MARINE – это набор интегрированных программных продуктов для проектирования и постройки
судов в сочетании с открытыми и гибкими решениями по управлению жизненным циклом объекта в целом.
Эти продукты обеспечивают быстрое и продуктивное проектирование без рисков, постройку и
эксплуатацию судов и средств освоения шельфа любых размеров и сложности.

Канал на Youtube c с демонстрациями - http://www.youtube.com/user/AVEVAPlantMarine


Facebook сообщество - http://www.facebook.com/pages/Aveva-PDMS/205740419473700

03.Об этом блоге (справочнике)


Данный блог посвящен рассмотрению базовых приемов работы с использованием макроязыка
программирования PML систем AVEVA PDMS/MARINE, а также решению автоматизации повседневных задач
проектировщика.

Задача блога (справочника) - дать информацию по использованию различных конструкций и методов,


которую можно использовать далее, при создании собственных функций автоматизации. Для корректного
использования необходимо знать азы программирования в системе: необходимая базовая информация по
языку, примеры программ и методология работы дается на учебных курсах, которые предоставляет
компания AVEVA.
По вопросам обучения можно связать с представительством ООО АВЕВА через электронную почту training.russia@aveva.com
Просьба указывать контактные данные, название вашей компании.

Автор: Сергей Лебедев


AVEVA

04.Терминология
Для правильного понимания сущности проектирования с использованием AVEVA PDMS и AVEVA MARINE
необходим владеть соответствующей терминологией. Далее приведены некоторые термины, важные для
понимания в первую очередь.

Объектно-ориентированное проектирование – методика проектирования, при использовании которой, в


центре находится объект, его функции, характеристики и поведение относительно других объектов, как
прямо влияющих на жизнь этого объекта, так и косвенно связанных. Характеристики объекта могут также
быть, как только собственными, так и связанными с другими объектами. Объектом может являться как
отдельный элемент, так и сборка с этим элементов в составе, так и узел, в который входит сборка и т.д.

Цифровая интегрированная модель - совокупность данных по проектируемому объекту, генерируемых


различными приложениями для проектирования. Цифровая интегрированная модель может включать:
модель процессов, схемную модель, 3D-модель, расчетную модель, конструкторскую модель и т.д.

Объектно-ориентированная инженерная база данных - база данных, специально предназначенная для


хранения информации о проектируемом объекте (см.объектно-ориентированное проектирование) с точки
зрения различных проектных дисциплин. База данных, имеющая функции расширения стандартной
атрибутики пользовательскими атрибутами. База данных, объединяющая все дисциплины и являющая
ядром проекта. База данных, позволяющая управлять объектом, его характеристиками и жизненным
циклом объекта. В основе базы данных лежит объект (отдельный элемент, сборка, узел, блок и т.д.)

05.Что такое PML


PML - Programmable Macro Language - макроязык программирования, используемый в системах AVEVA PDMS
/ AVEVA MARINE.
Используя PML возможно:
 автоматизировать некоторые рутинные действия проектировщика
 разрабатывать отдельные интерфейсы для обработки данных
 автоматизировать выдачу рабочей документации
 добавлять вспомогательный функционал и редактировать существующий (при необходимости)

PML нужно знать администраторам системы.


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

Автор: Сергей Лебедев


AVEVA

06.Базовые конструкции языка. Условия


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

Базовый синтаксис:
if ( УСЛОВИЕ ) then
--код, выполняемый при выполнении УСЛОВИЯ
--если УСЛОВИЕ не выполняется, код тоже не будет выполнен
endif

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

--если тип текущего элемента равен VALV, тогда


if ( !!CE.Type EQ 'VALV' ) then
--объединяем в переменной !var тип текущего элемента и его имя в виде
!var = !!CE.Type + ' - ' + !!CE.Name
--выводим полученное значение на экран в командной строке
$P $!var
endif

(вернуться к содержанию)

07.Запросы к Dabacon. Часть 1


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

Базовый синтаксис:
VAR !items COLLECT ALL что_искать FOR где_искать
где
что_искать - тип элемента для поиска
где_искать - место в иерархии где будет происходит поиск

Результат:
В переменную !items запишется массив значений типа STRING референтных номеров найденных элементов.
При отсутствии элементов размер массив будет равен 0 (для использования с условными операторами)

Пример:
VAR !items COLLECT ALL VALV FOR CE
в этом случае в переменную !items запишется массив референтных номеров, найденных элементов типа
VALV. Поиск будет осуществлен внутри текущего элемента.

VAR !items COLLECT ALL ( VALV INST ) FOR /zone1000


в этом случае в переменную !items запишется массив референтных номеров, найденных элементов типа
VALV и INST. Поиск будет осуществлен внутри элемента с именем /zone1000

VAR !items COLLECT ALL EQUI


в этом случае будут найдены все элементы типа EQUI по всем базам данным, которые могут содержать
данный тип, включенных в текущую MDB.
Предупреждение:
возможно более длительное по времени ожидание выполнение такого формата запроса (без указания
места иерархии к которому идет запрос) особенно на больших проектах с больших количеством элементов

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


следующих частях....

(вернуться к содержанию)

Автор: Сергей Лебедев


AVEVA

08.Базовые конструкции языка. Работа с циклами. Часть 1


Одной из важных составляющих является возможность проводить операции над массивом элементов,
выбирая каждый по очереди и применяя определенные команды.

Синтаксис:
do !x from ИНДЕКС_СТАРТА to КОНЕЧНАЯ_ТОЧКА
--действия, которые выполняются с элементами относительно индекса !x
enddo

Пример:
Напечатать в командной строке значений от 1 до 10

do !x from 1 to 10
$P $!x
enddo
В результате в командную строчку будут выведены значения переменной !x, являющейся индексом.
Приращение индекса, или шаг цикла в данном случае = 1. Соответственно выводимые значения будут
начинаться с единицы, как стартовой точки, и далее с шагом 1 до десяти..
(1,2,3,4,5,6,7,8,9,10)

Другой пример:

do !x from 1 to 10 by 0.5
$P $!x
enddo
В результате в командную строчку будут выведены значения переменной !x, являющейся индексом. В
данном случае приращение указано специально и составляет 0.5. Соответственно выводимые значения
будут начинаться с единицы как стартовой точки, и далее с шагом 0.5 до десяти.
(1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5,10)

(вернуться к содержанию)

09.Пример работы с базой


Задача:
найти все элементы оборудования (тип EQUI) внутри текущего элемента и вывести в командную строчку
информацию вида "имя:описание"

Решение:
необходимо использовать синтаксис обращения к базе для запроса элементов, далее в запустить цикл по
полученном массиву, запросить необходимые атрибуты и вывести на экран

--находим все элементы типа EQUI внутри текущего элемента


--и записываем в массив !equiRefs их референтные номера
VAR !equiRefs COLLECT ALL EQUI FOR CE
--запускаем цикл по элементам найденного массива,
--используя в качестве конечной точки размер массива,
--то есть общее количество найденных элементов. Размер массива определяется методом .Size()
do !x from 1 to !equiRefs.Size()
--вводим переменную, которая будет отвечать за необходимые значения вывода
--в эту переменную будут попадать значения атрибутов элемента из массива
--учитывая то, что в массиве хранятся референтные номера в виде строкового значения, а для обращения к
--атрибуту нам нужен объект базы, то с помощью метода .Dbref() мы переводим строку в объект и
--запрашиваем необходимые атрибуты
!output = !equiRefs[!x].Dbref().Name + ':' + !equiRefs[!x].Dbref().Desc
--выводим значения переменной !output (эти значения будут всегда новые в данном случае по мере
--изменения индекса !x и соответственно обращения к следующему элементу массива)
$P $!output
enddo
(вернуться к содержанию)

Автор: Сергей Лебедев


AVEVA

10.Базовые конструкции языка. Работа с циклами. Часть 2


Вложенные циклы.
Самый простой пример, на котором можно увидеть работу вложенных циклов - вывод на экран таблицы
умножения. Рассматривая этот пример, мы также познакомимся с другими функциями обработки данных.

Итак, есть ряд цифр от 1 до 9.

Задача:
вывести на экран результаты умножения цифры из ряда на все цифры из ряда по очереди.

Решение:
--Вводим массив цифр. Далее приведен один из способов генерации массива из строки
!digitString = '1 2 3 4 5 6 7 8 9'
--с помощью метода .Split(), который применен к строковой переменной, мы получаем массив данных.
--Если .Split() применен без параметров, тогда применяется разделитель по умолчанию - пробел
!digitArray = !digitString.Split()
--Запускаем первый цикл для того, чтобы определить множимое число
do !x from 1 to !digitArray.Size()
--записываем первый множитель в переменную, которая будет использована во втором цикле
!var1 = !digitArray[!x].Real()
--запускаем второй цикл по той же самой конечной точке для того, чтобы выполнить операцию умножения
--множимого числа.
--Метод .Real() применятся к строковому значению для преобразования его в число, чтобы производить арифметические операции
--NB: переменная-индекс внутри вложенного цикла не должна иметь одинаковое имя с переменной индекса циклов-хозяев
do !y from 1 to !digitArray.Size()
!var2 = !digitArray[!y].Real()
--умножаем два элемента: первый из первого цикла, неменяющийся пока не кончится второй цикл, второй – из второго цикла,
--меняющийся по ходу работы второго цикла
!resultReal = !var1 * !var2
--формируем визуальное составляющее - строчку для печати
!resultToPrint = !var1.String() + 'x' + !var2.String() + '=' + !resultReal.String()
--печатаем на экран
$P $!resultToPrint
enddo

--печатаем разделитель, который будет визуально отделять блоки таблицы


$P -----------------------
Enddo

NB. не забывайте следить, чтобы каждый цикл был "закрыт" командой enddo
(вернуться к содержанию)

11.Запросы к Dabacon. Часть 2


Пример нахождения элементов по определенных условиям и вывод информации.

Задача:
найти и вывести все элементы типа EQUI, у которых в атрибуте Desc встречается слово "Насос"

Вариант 1.
Запрос типа без фильтра и фильтрация в цикле (долгий вариант)

--запрашиваем элементы типа EQUI


VAR !equi COLLECT ALL EQUI FOR CE
--запускаем цикл с конечной точкой = размер полученного массива элементов
do !x from 1 to !equi.Size()
--пропускаем с помощью команды SKIP элемент и переходим к следующему, если условие не выполнилось
--используется метод .Matchwild(), применяемый к строке, для поиска вхождения подстроки
--метод .Matchwild() возвращает логическое значение "да" TRUE или "нет" FALSE
--соответственно следующая команда трактуется как "если в атрибуте Desc НЕ (.Not()) встретилось
--значение Насос, тогда пропустить
SKIP IF (!equi[!x[.Dbref().Desc.Matchwild('*Насос*').Not())
--выводим на печать
$P $!equi[$!x]
Enddo

Автор: Сергей Лебедев


AVEVA

Вариант 2.
Запрос типа с указанием фильтра (быстрый вариант)

--запрашиваем элементы типа EQUI сразу включая фильтр, чтобы в коллекцию попали элементы типа EQUI у которых в
--атрибуте Desc было слово Насос
VAR !equi COLLECT ALL EQUI WITH ( MATCHWILD(NAME,'*Насос*') ) FOR CE
--запускаем цикл с конечной точкой = размер полученного массива элементов
do !x from 1 to !equi.Size()
--сразу выводим на печать, так как в найденном массиве уже есть нужные элементы
$P $!equi[$!x]
Enddo

PS. На печать выводятся референтные номера, содержащиеся в массиве !equi


Данные операции удобно применять когда необходимо найти элементы по определенному критерию

(вернуться к содержанию)

12.Работа с файлами. Часть 1


Основные задачи работы с файлами заключаются в следующем:
 Обработать набор директорий
 Открыть и прочитать содержимое файла (целиком или построчно)
 Произвести поиск по содержимому и обработать данные
 Записать информацию в файл (создав новый или добавив в существующий)
Вот несколько приемов работы с файлами.

Пример 1.
Открыть файл с определенным именем и считать информацию в массив

--определяем имя файла в строковой переменной


!fileName = 'C:\test.txt'
--создаем объект типа File
!fileObj = OBJECT FILE(!fileName)
--считываем данные в массив (получится массив, где каждая ячейка = строка из файла)
--метод .Readfile(), применяемый к файловому объекту, открывает файл, считывает данные и закрывает
!fileContent = !fileObj.Readfile()
--Далее можно в цикле обработать полученный массив. Например вывести на экран
do !x from 1 to !fileContent.Size()
$P $!fileContent[$!x]
enddo

Пример 2.
Считать содержимое файла и проверить нахождение слова "Задвижка" в каждой из строк

--определяем имя файла в строковой переменной


!fileName = 'C:\test.txt'
--создаем объект типа File
!fileObj = OBJECT FILE(!fileName)
--считываем данные
!fileContent = !fileObj.Readfile()
do !x from 1 to !fileContent.Size()
--проверяем вхождение нужного слова в каждой строке, используя условный оператор
--и если слово встречает - печатает на экран
if (!fileContent[!x].Matchwild('*Задвижка*')) then
$P $!fileContent[$!x]
endif
enddo
(вернуться к содержанию)

13.Работа с графикой. Часть 1


Далее приведены несколько примеров запросов атрибутов у объектов модели. В примерах для указания
объекта мышью применяется команда ID (оригинальная команда системы, в версиях, начиная с 12.1
рекомендовано работать с графикой через пакет EDG)

Автор: Сергей Лебедев


AVEVA

Синтаксис:
ID @
после выполнения этой команды система переходит в режим ожидания, когда пользователь выберет на
экран элемент (любой). После выбора элемент станет текущим в иерархии.

Разновидности синтаксиса:
ID ТИП_ЭЛЕМЕНТА @
явное указание какой тип элемента должен быть выбран. Система будет находиться в режиме ожидания
пока не будет выбран корректный тип элемента.

Пример 1.
указать элемент типа EQUI
ID EQUI @

Пример 2.
указать элемент типа либо EQUI либо VALV
ID EQUI VALV @

Пример 3.
диалог с пользователем - перед тем как войти в режим указания элемента, пользователю будет открыто
окно с подсказкой
!!Alert.Message('Укажите EQUI')
ID EQUI @

(вернуться к содержанию)

14.Работа со строками. Часть 1


Некоторые приемы работы со строковыми переменными.

Исходная строковая переменная:


!stringVar = 'Задвижка клиновая с выдвижным шпинделем # 30c41нж/30нж41нж'

Пример 1.
Отделение части строки ДО определенного символа или выражения
!resultVar = !stringVar.Before('#')
В результате в переменную !resultVar запишется значение 'Задвижка клиновая с выдвижным шпинделем ', то
есть то, что находится ДО значения, указанного в качестве параметра метода, то есть в примере это #.
Применяется метод .Before('СТРОКОВОЕ_ЗНАЧЕНИЕ_ВЫРАЖЕНИЯ_ДО_КОТОРОГО')
NB: пробелы тоже считаются

Пример 2.
Отделение части строки ПОСЛЕ определенного символа или выражения
!resultVar = !stringVar.After('#')
В результате в переменную !resultVar запишется значение ' 30c41нж/30нж41нж', то есть то, что находится
ПОСЛЕ значения, указанного в качестве параметра метода.
Применяется метод .After('СТРОКОВОЕ_ЗНАЧЕНИЕ_ВЫРАЖЕНИЯ_ПОСЛЕ_КОТОРОГО')
NB: пробелы тоже считаются

Пример 3.
Отделение подстроки указанной длины, начиная с определенного места (по порядковому номеру в строке)
!resultVar = !stringVar.Substring(1,8)
В результате в переменную !resultVar запишется значение 'Задвижка' - то есть, начиная с первого символа и
длиной 8.
Применяется метод .Substring(начало(тип Real),длина(тип Real))
NB:Если не указывается длина (то есть будет указан только один параметр), то будет взята вся оставшаяся
строка, начиная с указанного места

Пример 4.
Разбить строку на массив строковых значений по указанному разделителю
!resultArray = !stringVar.Split('#')

Автор: Сергей Лебедев


AVEVA

Применяется метод .Split('СИМВОЛ_РАЗДЕЛИТЕЛЬ'). В результате переменная !resultArray будет массивом


строк, полученных путем разбития исходной строки по указанному разделителю. В данном примере это
будет массив из двух ячеек со значениями 'Задвижка клиновая с выдвижным шпинеделем' и
'30c41нж/30нж41нж' соответственно.
NB: Если не указать символ-разделитель, то есть написать просто .Split(), то система будет пытаться разбить
исходную строчку по пробелу

Пример 5.
Разбить исходную строку таким образом, чтобы в первую переменную записалось наименование,
расположенное до символа '#', а во вторую переменную - массив фигур (ячейка=фигура)
!description = !stringVar.Before('#').Trim()
!figuresArray = !stringVar.After('#').Split('/')
Последовательно применяется несколько методов к одному объекту. В объектно-ориентированном языке,
каким является PML 2, методы применяются последовательно. В первом случае применено два метода:
сначала получаем то, что следует до указанного строкового значения, а потом сразу метод .Trim(),
позволяющий убрать пробелы по краям строки. Во втором случае тоже используется два метода
последовательно: сначала получаем то, что следует после указанного строкового значения, а затем, зная
разделитель, получаем массив, разбив значение.

(вернуться к содержанию)

15.Работа с графикой. Часть 2


Методы указания характерных точек или линий элементов:

Указание P-точек.
В отличии от обычной команды указания элемента, команда указания точек используется только в виде
запроса:
Q IDP @
после выполнения команды система переходит в режим ожидания указания P-Точки

Для того, чтобы обработать информацию, взятую из точки, можно использовать следующий синтаксис:
VAR !ppointData IDP @
При этом система переходит в режим выбора точки и, после того, как пользователь указал точку в
переменную !ppointData запишется атрибутика точки, например:
'Ppoint 1 =23584/378 100 U E 9630 N 3463 U 9295 FBB'
где
Ppoint 1 - точка и ее номер,
=23584/378 - референтный номер элемента, которому принадлежит точка,
100 - диаметр в точке (если точка имеет его, в противном случае это значение будет пропущено),
U - направление точки,
E 9630 - координата по E/W,
N 3463 - координата по N/S,
U 9295 - координата по U/D и
FBB - тип присоединения (если точка имеет его, в противном случае значение будет пропущено)
Указание P-линий
По аналогии с точкам команда указания P-линий используется только для запроса атрибутики:
Q IDPLI @
после выполнения команды система переходит в режим ожидания указания P-линии

Для обработки информации взятой из P-линии можно использовать синтаксис:


VAR !plineData IDPLI @
При этом система переходит в режим выбора P-линии и, после того, как пользователь указал P-линию, в
переменную !plineData запишется атрибутика P-линии, например:
'Pline NARO of /A-4'
где
Pline NARO - название P-линии,
of /A-4 - принадлежность элементу.

(вернуться к содержанию)

Автор: Сергей Лебедев


AVEVA

16.Пример работы с коллекцией


Пример именования элементов согласно определенным правилам.

Задача:
необходимо найти все элементы типа VALV, у которых в наименовании есть слово 'Задвижка' и присвоить
каждому найденному элементу уникальный идентификатор, базирующийся на атрибуте Styp из
спецификации + номер суффикса.

Решение:

--сначала проверяем уровень иерархии для которого нужно вести поиск


--и если это не ZONE с атрибутом Purp=PIPE, тогда останавливаем выполнение
if (!!CE.Type NEQ 'ZONE' AND !!CE.Purp NEQ 'PIPE') then
!!Alert.Message('Перейдите на зону с трубами')
RETURN
endif
--если же уровень верный - запрашиваем элементы по критерию
VAR !valves COLL ALL VALV WITH (MATCHWILD(DTXR,'*Задвижка*')) FOR CE
--далее запускаем цикл, где по очереди переходим на элементы,
--убираем текущее имя, и задаем новое, согласно правилу V-номер-styp
--при этом сразу вводим перехватчик ошибки – HANDLE на тот случай, если такое имя уже есть
do !x from 1 to !valves.Size()
$!valves[$!x]
UNNAME
!styp = !!CE.Styp
!newname = '/V-$!x' + '-$!styp'
NAME $!newname
HANDLE (41,12)
$P Имя $!newname уже существует. Пропускаем
SKIP
ENDHANDLE
enddo

(вернуться к содержанию)

17.Сообщения пользователю. Часть 1


Для того, чтобы сделать ваши интерфейсы более интерактивными и дружелюбными к пользователю,
необходимо предусматривать систему сообщений.
Возможно использовать несколько видов сообщений:
 Так называемые Алерты - всплывающие окошки с сообщением, а также Алерты с предложением
выполнения простого действия, например ввода значения
 Сообщение в нижней статусной строке
 Сообщения в верхней статусной строке

В данной статье рассмотрим работу с Алертами. Их бывает несколько видов.

Первый тип: информационные сообщения:


!!Alert.Error('Это сообщение об ошибке!')

!!Alert.Warning('Это предупреждение с восклицательным знаком!')

Автор: Сергей Лебедев


AVEVA

!!Alert.Message('Это обычное сообщение!')

Второй тип: запрос действия и диалог


!answer = !!Alert.Confirm('Это вопрос, подразумевающий диалог!')

Причем в переменную !answer будет записано либо 'YES' либо 'NO' в зависимости от нажатой кнопки

!answer = !!Alert.Question('Это вопрос с тремя вариантами ответа!')


Причем в переменную !answer будет записано либо 'YES' либо 'NO' либо 'CANCEL' в зависимости от нажатой
кнопки

!answer = !!Alert.Input('Это ввод данных','10')


Причем в переменную !answer будет записано строковое значение, введенное в поле окошка. Второй
параметр (в примере это 10) - это значение по умолчанию

(вернуться к содержанию)

18.Пример использования коллекций. Обработка модели


Задача:
Были созданы несколько трубопроводов (PIPE), однако не задавался атрибут Bore (диаметр). В именовании
трубопроводов присутствует обозначение диаметра, в качестве первой части имени (до знака минус),
например /100-B-1 (здесь 100 - основной диаметр линии). Необходимо найти этот диаметр по части имени и
присвоить это значение атрибуту Bore элемента Pipe.
Вторая часть задачи: добавить найденные элементы на экран и задать временный цвет согласно схеме:
Диаметр-цвет: 40-BLUE,80-RED,100-GREEN,150-YELLOW,200-GREY,250-DARKBROWN

Решение:
делаем запросы к базе на предмет нахождения элементов типа PIPE, далее запускаем
цикл, в цикле обрабатываем каждый элемент на предмет нахождения диаметра (функция .Before(), .After()),
присвоения атрибута Bore в найденное значение, учитывая что это должно быть число, вывод на экран и
раскраской согласно указанной фильтрации

VAR !pipes COLLECT ALL PIPE FOR CE


do !x from 1 to !pipes.Size()
--находим диаметр из имени, сначала предварительно превратив элемент массива в объект
--и обработав его атрибут Name
!boreS = !pipes[!x].Dbref().Name.Before('-').After('/')
--превращаем найденное значение в объект типа BORE
--пропуская элемент, если конвертация невозможна
!boreB = OBJECT BORE(!boreS)

Автор: Сергей Лебедев


AVEVA

HANDLE ANY
SKIP
ENDHANDLE
--задаем атрибут через обращение к объекту массива
!pipes[!x].Dbref().Bore = !boreB
--вычисляем нужный цвет
if (!boreS EQ '40') then
!colour = 'BLUE'
elseif (!boreS EQ '80') then
!colour = 'RED'
elseif (!boreS EQ '100') then
!colour = 'GREEN'
elseif (!boreS EQ '150') then
!colour = 'YELLOW'
elseif (!boreS EQ '200') then
!colour = 'GREY'
elseif (!boreS EQ '250') then
!colour = 'DARKBROWN'
else
!colour = 'WHITE'
endif
--добавляем элемент
ADD $!pipes[$!x]
--раскрашиваем
ENHANCE $!pipes[$!x] COLOUR $!colour
enddo
--далее следует набор команд для выполнения операции
--Walk to drawlist (центрирование всех объектов экрана)
var !collection COLLECT ALL FROM DRAWLIST
!block = OBJECT BLOCK('!collection[!evalindex].dbref()')
!list = !collection.evaluate(!block)
!volume = object volume(!list)
!lim = OBJECT GPHVIEWS()
!lim.limits(!!gph3ddesign1.view, !volume)

Работу примера можно проверить на проекте SAM

(вернуться к содержанию)

19.Пример редактирования атрибутов


Задача:
выгрузить в формат Excel (.csv) элементы типа EQUI для редактирования атрибута Description. После
редактирования (в Excel) загрузить информацию обратно, так чтобы соответствующему элементу
присвоилось соответствующее значение атрибута.

Решение:
состоит из двух частей - коллекция и запись в файл и считывание файла и запись атрибута
Часть первая (код первого макроса): собираем все элементы типа EQUI внутри текущего элемента -->
формируем массив для вывода во внешний файл --> выводим в файл, затем файл редактируется средствами
Excel

--собираем коллекцию
VAR !allEqui COLLECT ALL EQUI FOR CE
--запускаем цикл для формирования массива данных на вывод
--разделитель - точка с запятой для того, чтобы Excel автоматически разбил по столбцам при открытии
do !x from 1 to !allEqui.Size()
!outputArray[!x] = !allEqui[!x].Dbref().Name + ';' + !allEqui[!x].Dbref().Desc
enddo
--формируем файл
!fileName = 'c:\equips.csv'
!fileObj = OBJECT FILE(!fileName)
--записываем информацию, используя метод .Writefile(‘СПОСОБ_ЗАПИСИ’,МАССИВ_ДАННЫХ)
!fileObj.Writefile('OVERWRITE',!outputArray)

Часть вторая (код второго макроса): считываем файл и загружаем данные, присваивая атрибут
!fileName = 'c:\equips.csv'
!fileObj = OBJECT FILE(!fileName)
--считываем данные в массив
!fileData = !fileObj.Readfile()

Автор: Сергей Лебедев


AVEVA

--проходим по циклу считанных данных и заносим данные в модель


--принцип: указываем системе имя в этот момент элемент становится текущим
--далее даем команду назначения атрибута Desc
do !x from 1 to !fileData.Size()
!equiName = !fileData[!x].Split(';')[1]
!equiDesc = !fileData[!x].Split(';')[2]

$!equiName
DESC |$!equiDesc|
Enddo

Приведены базовые варианты, без отслеживания возможных ошибок

(вернуться к содержанию)

20.Работа с датой и временем


В PML получение информации о текущем времени и дате происходит в момент интерпретации части кода, в
которой указаны функции работы с датой и временем. Для запроса необходимо ввести объект, отвечающий
за время/дату и обращаться к его методам.

Пример:
получить текущую дату и время в формате <день>-<месяц>-<год>,<час>:<минуты>:<секунды>

--вводим объект, отвечающий за оборабттку даты и времени


!dateObj = OBJECT DATETIME()
--запрашиваем день
!day = !dateObj.Date()
--запрашиваем месяц
!month = !dateObj.month()
--запрашиваем год
!year = !dateObj.year()
--запрашиваем час
!hour = !dateObj.Hour()
--запрашиваем минуты
!minute = !dateObj.Minute()
--запрашиваем секунды
!second = !dateObj.Second()
--Выполняем "склейку" полученных данных
!result = !day & '-' & !month & '-' & !year & ',' & !hour & ':' & !minute & ':' & !second

Результатом будет:
<STRING> '12-3-2011,13:38:6'

(вернуться к содержанию)

21.Пример обработки ссылок


Задача:
указав на экране элемент оборудования (EQUI), отобразить всю обвязку трубопроводов этого элемента...
Решение:
трубопроводы присоединяются к штуцерам оборудования (NOZZ), при этом у штуцеров заполняется атрибут
Cref, в который попадает имя присоединенного к штуцеру бранча (BRAN). Соответственно решение задачи
заключается в нахождении всех штуцеров указанного мышью оборудования, проверке заполнения атрибута
Cref, и если он заполнен (то есть бранч присоединен), то отобразить на экране этот бранч.

!!Alert.Message('Укажите элемент оборудования...')


ID EQUI @
VAR !nozzles COLL ALL NOZZ FOR CE
--проверка найдены ли штуцеры у указанного элемент путем проверки размера массива !nozzles
if (!nozzles.Size() EQ 0) then
!!Alert.Message('Штуцеры не найдены. Операция прервана...')
return
endif
--проходим по массиву штуцеров
--пропускаем штуцер, если атрибут Cref не заполнен
--если заполнен - добавляем бранч, взяв его данные из Cref
do !x from 1 to !nozzles.Size()

Автор: Сергей Лебедев


AVEVA

SKIP IF (!nozzles[!x].DbRef().Cref.Unset())
!link = !nozzles[!x].DbRef().Cref
ADD $!link
enddo

(вернуться к содержанию)

22.Пример обработки ссылок. Продолжение


Расширим задачу из предыдущего примера. Теперь нужно не просто добавить обвязку трубопроводов
выбранного элемента оборудования, но и подсветить разными цветами: синим, если поток среды выходит
из штуцера, красным - если входит.

Для того, чтобы понять вход или выход потока на штуцере необходимо запросить псевдоатрибут CEND, в
который записывается либо HEAD либо TAIL (выход и вход соответственно)

!!Alert.Message('Укажите элемент оборудования…')


ID EQUI @
VAR !nozzles COLL ALL NOZZ FOR CE
–-проверка найдены ли штуцеры по размеру массива
if (!nozzles.Size() EQ 0) then
!!Alert.Message('Штуцеры не найдены. Операция прервана…')
return
endif
--выполняем команду снятия ранее заданной раскраски
UNENHANCE ALL
-–проходим по массиву штуцеров
--находим трубопроводы и
--если поток входит в штуцер - подсвечиваем красным
--если выходит - синим
do !x from 1 to !nozzles.Size()
SKIP IF (!nozzles[!x].DbRef().Cref.Unset())
!link = !nozzles[!x].DbRef().Cref
--используем псеводатрибут CEND у штуцера
--чтобы понять голова или хвост присоединены
!cend = !nozzles[!x].DbRef().CEND
if (!cend EQ 'HEAD') then
!colour = 'BLUE'
else
!colour = 'RED'
endif
ADD $!link
ENHANCE $!link COLOUR $!colour
enddo

(вернуться к содержанию)

23.Автоматизация работы администратора. Часть 1


В задачи администратора системы входит достаточно много функций по обслуживанию проекта. Это
например: периодическая проверка баз данных, подшивка сессий, выгрузка RVM-файлов, запуск
межбазовых макросов (Inter-db макросы). Многие из этих процедур можно автоматизировать, используя
PML.

В этом и нескольких следующих темах рассмотрим примеры автоматизации некоторых рутинных действий
администратора.

--Сначала сформируем несколько папок на жестком диске для вывода логов


--Первый файл - для вывода логов по проверке баз данных
--второй файл - проверки трубопроводов
--третий файл - папка для хранения моделей AVEVA Review
--Если указанные папки не существуют, создаем их системной командой - MKDIR
!folders[1] = 'D:\temp\NIGHT-WORK\DatabaseCheck\'
!folders[2] = 'D:\temp\NIGHT-WORK\PipingCheck\'
!folders[3] = 'D:\temp\NIGHT-WORK\Review\'
do !x from 1 to !folders.Size()

!fo = object file('$!folders[$!x]')


if (!fo.Exists().Not()) then

Автор: Сергей Лебедев


AVEVA

!comm = |SYSCOM 'MKDIR $!folders[$!x]'|


$!comm
endif
Enddo

--Блок 1. EXPUNGE ALL CLAMILISTS/USERS BEFORE


--(УБРАТЬ ИЗ ПРОЕКТА ВСЕХ ПОЛЬЗОВАТЕЛЕЙ ПЕРЕД ПРОДОЛЖЕНИЕМ)
--Переходим в модуль Admin
ADMIN
--выполняем команду удаления
EXPUNGE
--проходим по всем базам данных и удаляем из клеймлистов
VAR !DBS COLLECT ALL DB
do!x from 1 to !DBS.Size()
!DBNA = !DBS[!X].Dbref().Name.After('/*')
EXPUNGE DB $!DBNA
HANDLE (1,271)(1,273)
--перехват ошибки и пропуск, если база не-MULTIWRITE или FOREIGN
ENDHANDLE
ENDDO
--Конец блока 1

Процедура описанная в блоке 1, позволяет автоматически закрыть работу всех пользователей. Безусловно
такая операция должна выполнять только ночью на сервере в автоматическом режиме. Для запуска
автоматического режима необходимо предусмотреть обычный планировщик Windows в который прописать
команду запуска PDMS в терминальном режиме (без интерфейса) и дать команду на выполнение
необходимого макроса.
Пример: свойства запускаемого ярлыка - \.....\pdms.bat TTY SAM SYSTEM/XXXXXX /SAMPLE $M/d:\night-
process-run.pmlmac
При этом в файле night-process-run.pmlmac будет записан рассматриваемый код автоматизации действий
администратора.

(вернуться к содержанию)

24.Автоматизация работы администратора. Часть 2


--Блок 2. CHECK DATABASES
--ПРОВЕРКА БАЗ ДАННЫХ
-собираем все базы и конструируем лог-файл
VAR !DBS COLL ALL DB
!outputLOG = object array()
!outputLOGFILE = object file('$!folders[1]' + '!TotalLOG-DB.log')
VAR !mdbn MDB
--команда задания опций проверки
CHECKOPTION EXT CHECK PREF $!mdbn

do !x from 1 to !DBS.Size()
--пропускаем если база является Foreign
skip if (!DBS[!x].DbRef().Fore EQ 'FOREIGN')
!dbName = !DBS[!x].DbRef().Name

!nfile = '$!folders[1]' & !DBS[!x].DbRef().Name.After('/*').Replace('/','!') & '.txt'

ALPHA LOG/$!nfile OVER


!dbN = !DBS[!x].DbRef().Name.After('/*')
--выполняем команду, причем результаты будут записаны в спец.файл (первый лог)
CHECK DB $!dbN
ALPHA LOG END

--проверяем получившийся лог-файл


--на предмет нахождения фатальных ошибок
!logfile = object file(!nfile)
!logfileRead = !logfile.ReadFile()
if (!logfileRead[!logfileRead.Size() - 1].Matchwild('*Database has no structural errors*').Not()) then
!outputLOG.Append('DBS $!dbName : обнаружены несоответствия.. Необходима проверка...')
endif
do !y from 1 to !logfileRead.Size()
if (!logfileRead[!y].Matchwild('*invalid*') OR !logfileRead[!y].Matchwild('*unknown*')) then
!outputLOG.Append('DBS $!dbName : обнаружены несоответствия.. Необходима проверка...')
SKIP

Автор: Сергей Лебедев


AVEVA

endif
enddo
enddo
--выводим результаты проверки первого лог-файла во второй лог файл
!outputLOGFILE.WriteFile('OVERWRITE',!outputLOG)
--Конец части 2

В строчке !outputLOGFILE = object file('$!folders[1]' + '!TotalLOG-DB.log') упоминается переменная !folder[1]. См. первую
часть

Эта часть является продолжением. Соответственно все части кода могут объединяться в один файл или
запускать по очереди из разных

(вернуться к содержанию)

25.Механизмы работы с объектами. Часть 1


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

Что нужно понимать во взаимоотношении элементов


 элементы между собой связаны ссылками
 ссылка между элементами устанавливается по внутреннему (референтному) номеру элемента
(визуально – с помощью имени элемента, если задан атрибут Name)
 внутренний номер (референтный номер) присваивается элементу в момент его создания, не может
быть изменен и всегда уникален
 если элемент, на который ссылается другой элемент, поменял имя (Name), то в ссылке имя
поменяется автоматически (так ссылка по внутреннему номеру)
 если элемент удален из базы, то номер, который у него был, больше не может быть использован
 любая ссылка – это ссылка не на имя элемента, а на сам элемент базы данных (или объект типа
Dbref), соответственно при обращении по ссылке мы обращаемся к элементу

Пример:
Есть элемент технологического оборудования, у которого есть штуцер (NOZZ). К штуцеру впоследствии
должен быть присоединен участок трубопровода (BRAN). В момент создания BRAN мы указываем точку –
штуцер и система понимает, как присоединять трубу. При этом у элемента BRAN есть атрибут Href и Tref, в
которые, в момент указания штуцера присоединения и в зависимости от того, что мы присоединяем (голову
- Href или хвост - Tref) записывается имя этого штуцера (или его референтный номер).
У штуцера же в свою очередь заполняется атрибут Cref, в который попадает имя присоединенного BRAN (а
если запросить еще и псевдоатрибут CEND, можно понять - голова или хвост бранча присоединены в этот
штуцер).
Таким образом устанавливается двухсторонняя связь между элементами...

Следующие обращения возможно применять для получения информации о ссылках


На примере обращения к штуцеру:
Q Cref – отобразится имя присоединенного бранча (если есть)

Запрос на PML1
VAR !nozzcref CREF
В переменную !nozzcref запишется строчка с именем бранча. При этом идет попытка запросить атрибут у
текущего элемента (CE), и если у CE нет такого атрибута, будет ошибка.

Запрос на PML2
!ncref = !!CE.Cref
В переменную !ncref запишется объект (типа Dbref()) (!) базы данных со всеми атрибутами. Это большое
отличие от запроса на PML1, где все результаты трактуются как строковые объекты.
Соответственно, продолжив цепочку обращений к объекту, указанному в ссылке, можно получить любой
атрибут. Например, обращаясь к штуцеру, нужно получить значение Description присоединенного бранча

Автор: Сергей Лебедев


AVEVA

Пример:
!brandesc = !!CE.Cref.Desc
То есть через ’точку’ можно получить любой атрибут, главное чтобы в цепочке появился объект. В данном
случае он появляется с выражением !!CE.Cref

Другой пример
В модели есть задвижка. Необходимо обратиться через модель к каталогу и получить атрибут Description из
SCOM (каталожного компонента).
Предположим, что текущий элемент это VALV, тогда, зная, что у элемента трубопроводов в модели есть
атрибут Spref, указывающий на компонент спецификации (SPCO), а у того в свою очередь есть атрибут Catref,
указывающий на каталожный компонент, выражение будет выглядеть следующим образом:
!scomdesc = !!CE.Spref.Catref.Desc
В переменную !scomdesc запишется значение атрибута Desc из SCOM. (Следует, учитывать, что если ссылка не
установлены, тогда система выдаст ошибку. Как ее отследить – в других темах.)
(вернуться к содержанию)

26.Автоматизация работы администратора. Часть 3


Продолжение. Запуск межбазовых (Inter-DB макросов)

--Блок 3. Запуск межбазовых макросов, если таковые были образованы


--считываем папку с макросами
VAR !PROJCODE PROJ CODE
!TOEVAL = |VAR !MACFOLDER EVAR '$!PROJCODE| & |MAC'|
$!TOEVAL
!MacroFolder = object file(!MACFOLDER)
--заходим в Design
DESIGN
!files = !MacroFolder.Files()
if (!files.Size() NEQ 0) then
--запускаем каждый макрос по очереди
do !x from 1 to !files.Size()
!path = !files[!x].String()
$M/$!path
enddo
--возвращаемся в Monitor
MONITOR
do !x from 1 to !files.Size()
--удаляем макрос
DELETE MAC $!x
enddo
endif
--Конец блока 3

(вернуться к содержанию)

27.Автоматизация работы администратора. Часть 4,5


Обновление данных о пространстве
--Блок 4. Обновление пространственной карты
DESIGN
MAP BUILD MDB
HANDLE (69,97)
--перехват ошибки если Read-Only база
ENDHANDLE
--Конец блока 4

Проверки
--Блок 5. Проверка трубопроводов. На примере проекта SAM
--Встаем на SITE
SITE /STABILIZER
ZONE /PIPES
--собираем трубы
!pipes = !!CollectAllFor('PIPE',||,CE)
--формируем лог
!outputLOG = object array()

Автор: Сергей Лебедев


AVEVA

!outputLOGFILE = object file('$!folders[2]' + '!TotalLOG-PIPES.log')


--запускаем цикл, формируем данные и выводим в файл
do !x from 1 to !pipes.Size()
!nfile = '$!folders[2]' & !pipes[!x].Name.Replace('/','!') & '.txt'
ALPHA LOG/$!nfile OVER
$!pipes[$!x]
VAR !userm USERM
VAR !lastm LASTM
!user = 'Модифицировано пользователем: $!userm , $!lastm'
$P $!user
CHECK CE
ALPHA LOG END
--проверяем лог-файл, и если встретились несоответствия
--выводим сообщения в общий лог
!logfile = object file(!nfile)
!logfileRead = !logfile.ReadFile()
if (!logfileRead[!logfileRead.Size()].Matchwild('*NO DATA INCONSISTENCIES*').Not()) then
!outputLOG.Append('PIPE $!!CE.Name : обнаружены несоответствия.. Необходима проверка...')
endif
enddo

!outputLOGFILE.WriteFile('OVERWRITE',!outputLOG)
--Конец блока 5

(вернуться к содержанию)

28.Автоматизация работы администратора. Часть 6,7


Создание модели для AVEVA Review

--Блок 6. Создание модели Review для просмотра на совещаниях. На примере проекта SAM
--переходим на сайт
SITE /STABILIZER
!CEName = !!CE.Name
--формируем файл ревью
VAR !projcode PROJ CODE
!revFile = object file('$!folders[3]' + '$!projcode' + '_model.rvm')

--выполняем команды экспорта


EXPORT FILE/$!revFile OVER
EXPORT ENCODING UTFE

EXPORT ALL PIPE FOR CE COLOUR 10

EXPORT ALL PIPE WITH (NAME OF ZONE EQ '/CABLETRAY') FOR CE COLOUR 11

EXPORT ALL PIPE WITH (MATCHWILD(NAME,'*A*') AND NAME OF ZONE EQ '/PIPES') FOR CE COLOUR 2
EXPORT ALL PIPE WITH (MATCHWILD(NAME,'*B*') AND NAME OF ZONE EQ '/PIPES') FOR CE COLOUR 3
EXPORT ALL PIPE WITH (MATCHWILD(NAME,'*C*') AND NAME OF ZONE EQ '/PIPES') FOR CE COLOUR 6

EXPORT ALL PIPE WITH (NAME OF ZONE EQ '/HEATING-VENTS') FOR CE COLOUR 12

EXPORT ALL EQUI FOR CE COLOUR 4

EXPORT ALL STRU FOR CE COLOUR 8


EXPORT ALL STRU WITH (NAME OF ZONE EQ '/STEEL' OR NAME OF ZONE EQ '/RACKPIPES') FOR CE COLOUR 7

EXPORT FINISH
--Конец блока 6

Подшивка сессий

--Блок 7. Подшивка сессий


--Не использовать если в проекте используется механизм работы с сессиями
--для анализа изменений, возврата, контроля работы пользователей или Global
--использовать только при необходимости уменьшения физического
--объема данных проекта на жестком диске)
--заходим в ADmin
ADMIN
VAR !DBS COLL ALL DB
do !x from 1 to !DBS.Size()

Автор: Сергей Лебедев


AVEVA

--пропускаем если Foreign


skip if (!DBS[!x].DbRef().Fore EQ 'FOREIGN')
!mergewhere = !DBS[!x].DbRef().Name.After('/*')
--команда подшивки
MERGE CHAN $!mergewhere
HANDLE (1,18)(1,293)
--перехват, если Foreign база
ENDHANDLE
enddo
--Конец блока 7

(вернуться к содержанию)

29.Работа с графикой. Часть 3


Далее приведем несколько команд, которые помогут переключать различные уровни отображения
элементов.
Вариант использования - сделать макрос или функцию и сделать его вызов на кнопке в модуле Design, для
быстрого включения/выключения свойств.
Введем функцию с параметром, показывающим, что хочет включить/выключить пользователь

define function !!arrepr(!para is string)


--если переданный параметр равен OBST
--тогда выполняем код для обстракции
if (!para EQ 'OBST') then
--вычисляем текущее значение обстракции
VAR !OBST REPR OBST
--если выключено, то включаем с прозрачностью 50
if (!OBST EQ 'Off') then
repr obst on transl 50
repr update
else
--если включено - выключаем
repr obst off
repr update
endif
endif

--если же переданный параметр равен INSU


--тогда выполняем код для изоляции
if (!para EQ 'INSU') then
--вычисляем текущее значение изоляции
VAR !INSU REPR INSU
--если выключено - включаем с прозрачностью 50
if (!INSU EQ 'Off') then
repr insu on transl 50
repr update
else
--если включено - выключаем
repr insu off
repr update
endif
endif

endfunction

Код функции необходимо сохранить в файле с именем таким же как и имя функции, то есть в данном случае
- arrepr и расширением .pmlfnc. Файл должен находиться в PMLLIB. После создания функции нужно
обновить индекс файлов командой PML REHASH ALL .
Пример вызова функции - !!arrepr('INSU')

(вернуться к содержанию)

30.Пользовательские проверки данных построения


Очень часто поднимается вопрос о возможности включить средства проверки модели на соответствие
различным нормах и правилам проектирования. Рассмотрим пример как это можно сделать.

Автор: Сергей Лебедев


AVEVA

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

Создаем в папке %PMLLIB%/Check файл aechkattaweld.pmlfnc со следующей функцией

define function !!aechkattaweld (!element is DBREF, !dummyCheck is CHKDEFINITION) is CHKRETURN


-- инициализируем переменные
!return = object CHKRETURN()
!return.passed = true
--снимаем раскраску и маркировку если была
UNENHANCE ALL
UNMARK ALL

--запрос на значение расстояния


!distance = !!Alert.Input('Мин.расстояние между опорой и швом, мм:','200')
!where = !element.name
--собираем опоры
var !coll COLL ALL ATTA FOR $!where
if (!coll.Size() EQ 0) then
!!Alert.Message('Опор не найдено.. Прервано...')
RETURN !return
else

do !x from 1 to !coll.Size()
$!coll[$!x]
--высчитываем расстояние слева от опоры
VAR !distL CONST DIST P1 OF CE TO P2 OF PREV
HANDLE (2,113)
VAR !distL CONST DIST P1 OF CE TO PH
ENDHANDLE

--высчитываем расстояние справа от опоры


VAR !distR CONST DIST P2 OF CE TO P1 OF NEXT
HANDLE (2,113)
VAR !distR CONST DIST P1 OF CE TO PT
ENDHANDLE

--если слева меньше - раскрашиваем и маркируем


--и формируем сообщение для формы
if (!distL.Real() LEQ !distance.Real() AND !distR.Real() GE !distance.Real()) then
!return.Passed = false
!return.Messages.append('Слева меньше ' + !distance + 'мм до шва у опоры ' + !!CE.Name + '...')
ENHANCE CE COLOUR RED
MARK WITH '<--' CE
endif
--если слева и справа меньше - раскрашиваем и маркируем
--и формируем сообщение для формы
if (!distL.Real() LEQ !distance.Real() AND !distR.Real() LEQ !distance.Real()) then
!return.Passed = false
!return.Messages.append('Слева меньше ' + !distance + 'мм до шва у опоры ' + !!CE.Name + '...')
ENHANCE CE COLOUR RED
MARK WITH '<--.-->' CE
endif
--если справа меньше - раскрашиваем и маркируем
--и формируем сообщение для формы
if (!distL.Real() GE !distance.Real() AND !distR.Real() LEQ !distance.Real()) then
!return.Passed = false
!return.Messages.append('Слева меньше ' + !distance + 'мм до шва у опоры ' + !!CE.Name + '...')
ENHANCE CE COLOUR RED
MARK WITH '-->' CE
endif

enddo
return !return
endif
return !return
endfunction

Далее в папке с дефолтами проекта (%PDMSDFLTS% или %proj_idDFLTS%) создаем файл des-checks.pmldat и
вписываем в него определение правила

Автор: Сергей Лебедев


AVEVA

--2. Проверки трубопроводов


--2.1 Проверка расстояния между опорой и швом
!Check = object CHECK()
--название правила
!Check.Name = 'AECHKATTAWELD'
--название для формы
!Check.Title = 'Расстояние между опорой и сварным швом'
--класс правила
!Check.Class = 'Трубопроводы. ПБ 03-585-03'
--группа правил
!Check.Group = 'Трубопроводы'
--проверяемые элементы
!Check.Types = 'BRAN'
!Check.Rule = ''
--название выполняемой функции
!Check.Function = '!!aechkattaweld'
--модуль
!Check.Module = 'Design'
!Check.FileType = '$1'
!!AddCheckerCheck(!Check)

(вернуться к содержанию)

31.Файловый проводник
В следующем коде показан пример сохранения и открытия файла с помощью диалога Windows.

--Открытие
--Подключаем драйвер
using namespace 'Aveva.Pdms.Presentation'
Import 'pmlfilebrowser'
handle any
endhandle
--открытие
!browser = object PMLFILEBROWSER('LOAD')
!filePath = 'D:\'
!browser.show(!filePath, '', 'Открытие текстового файла’, false, 'Файлы txt (*.txt)|*.txt', 2)
!FileName = !browser.file()
--Сохранение
using namespace 'Aveva.Pdms.Presentation'
Import 'pmlfilebrowser'
handle any
endhandle
!browser = object PMLFILEBROWSER('SAVE')
!filePath = 'D:\'
!browser.show(!filePath, '', 'Сохранение текстового файла’, false, 'Файлы txt (*.txt)|*.txt', 2)
!FileName = !browser.file()

В переменную !FileName вернется имя файла

(вернуться к содержанию)

32.Автоотключение MTOC при создании трубопроводного компонента


В данной теме рассмотрим как можно отредактировать стандартные функции системы, добавив
необходимый функционал.

Пример:
необходимо при создании элемента типа OLET (врезка) автоматически ставить значение атрибута
MTOC=OFF, то есть выключать его из в спецификацию

Решение (без добавления переключателя на форму создания):


 необходимо найти в установочной папке PMLLIB файл componentcreation.pmlfrm и скопировать его
в сетевой, пользовательский PMLLIB. Это должно быть выполнено обязательно. Запрещается
редактировать файлы в папке установки системы!
 отредактировать файл следующим образом (пример для версии 12.0.SP6) - в конец метода create()
в районе строчки номер 5328 вставляем следующий код

Автор: Сергей Лебедев


AVEVA

--lsa установка MTOC при создании врезки


if (!!CE.Type EQ 'OLET') then
!lsaISMTOC = !!Alert.Confirm('Отключить OLET из спецификации??')
if (!lsaISMTOC EQ 'YES') then
MTOC OFF
endif
endif
--end of lsa

Здесь lsa – это просто метка, которая впоследствии поможет быстро найти место редактирования. Всегда,
при редактировании стандартных файлов, рекомендуется использовать метки, показывающие место
редактирования

Скриншот места вставки кода

Теперь при создании элемента, если это OLET, система будет спрашивать - Установить ли значения MTOC.

(вернуться к содержанию)

33.Массовая печать из Draft в DXF/PDF


Пример задачи выполнения массовой печати в форматы DXF и PDF всех чертежей внутри одного DEPT.

--сообщение об ошибке, если уровень не DEPT


if (!!CE.Type NEQ 'DEPT') then
!!Alert.Message('Перейдите на DEPT...')
return
endif

--путь вывода
!outputFolder = 'd:'
--собираем листы
VAR !sheets COLLECT ALL SHEE FOR CE

--запускаем цикл по листам


do !x from 1 to !sheets.Size()

--переходим на лист
$!sheets[$!x]

--формируем имя выходного файла


!fileNameDXF = !!CE.Name.Replace('/','_').Replace('\','_') + '.dxf'
!fileNamePDF = !!CE.Name.Replace('/','_').Replace('\','_') + '.pdf'

--печать в файл
PLOT CE DXF/$!outputFolder\$!fileNameDXF OVER
PLOT CE PDF/$!outputFolder\$!fileNamePDF 'MINL 0.22,COL BW' OVER
enddo
--открываем папку
SYSCOM 'EXPLORER $!outputFolder &'

Автор: Сергей Лебедев


AVEVA

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

(вернуться к содержанию)

34.Визуальное отображение "головы"/"хвоста" трубопровода


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

--останавливаем выполнение, если это не бранч


if (!!CE.Type NEQ 'BRAN') then
!!Alert.Message('Перейдите на бранч...')
return
endif

--очищаем все ранее сделанные вспомогательные метки


AID CLEAR ALL
--вычисляем позицию головы бранча и диаметр
!branHpos = !!CE.Hpos
VAR !branPHBore PH BORE
--задаем будущий размер вспомогательного элемента относительно диаметра
!sizeH = !branPHBore.Real() + 100
--вычисляем позицию головы бранча и диаметр
!branTpos = !!CE.Tpos
VAR !branPTBore PT BORE
--задаем будущий размер вспомогательного элемента относительно диаметра
!sizeT = !branPTBore.Real() + 50

--выводим текстовую метку в голову и хвост


AID TEXT 'Head -->' AT $!branHpos
AID TEXT '--> Tail' AT $!branTpos

--выводим вспомогательную графику (сферу - в голову, бокс - в хвост)


AID SPHERE $!branHpos DIA $!sizeH
AID BOX XLEN $!sizeT YLEN $!sizeT ZLEN $!sizeT FILL ON AT $!branTpos

(вернуться к содержанию)

35.Макрос для подсчета элементов


Данный макрос пригодится для подсчета определенных элементов, содержащихся в текущем элементе, с
разбивкой по зонам, сайтам и т. д.
Пример:
мы хотим подсчитать количество созданных подразделениями чертежей (DRWG) с разбивкой их по
подразделениям (DEPT). Встаем в корень дерева чертежей Draft, запускаем макрос и в окне ввода пишем:
"DEPT DRWG".
Программа в командной строке сформирует отчет вида:
=== ПОДСЧЕТ КОЛИЧЕСТВА ЭЛЕМЕНТОВ DRWG в DEPT: ===
1) 10_ОТДЕЛ : 4
2) 21_ОТД : 179
3) 22_ОТДЕЛ : 338
4) 41_ОТДЕЛ : 30
5) Магистр_Тр : 6
6) 42_ОТДЕЛ : 32
7) 50_ОТДЕЛ : 57
8 ) 12_ОТДЕЛ : 36
9) 23_OTDEL_DRAW : 26
10) 30_OTDEL : 177
11) Тех.Проект : 5
ВСЕГО ЭЛЕМЕНТОВ DRWG: 890
==========================

!question = !!alert.input('Введите через пробел В КАКИХ ЭЛЕМЕНТАХ и КАКИЕ ЭЛЕМЕНТЫ считать.')


--Например, чтобы посчитать количество шаблонов TMPL в определенном SITE,
--введите: SITE TMPL', '')

Автор: Сергей Лебедев


AVEVA

if (!question EQ '') then


return
endif

!param = split(!question, ' ')


!inelem = UpCase(!param[1])
!outelem = UpCase(!param[2])
!z = !!collectallfor(!inelem, '', !!ce)
$P
$p === ПОДСЧЕТ КОЛИЧЕСТВА ЭЛЕМЕНТОВ $!outelem в $!inelem: ===
$P
!counter = 0

do !f from 1 to !z.size()
!z[!f]
!x = !!collectallfor(!outelem, '', !z[!f])
!m = !x.size()
$p $!f) $!z[$!f].namn : $!m
!counter = !counter + !m
!x.clear()
enddo

$p
$p ВСЕГО ЭЛЕМЕНТОВ $!outelem: $!counter
$p
$p ==================================

(вернуться к содержанию)

36.Подсчет количества сварных швов


Необходимо подсчитать количество сварных швов внутри текущего элемента и вывести в файл. Необходимо
отдельно считать сварные компоненты и сварные швы на трубе и вывести результат в файл.
Решение:

--запоминаем текущий элемент


!backCE = !!CE.Name
--запрос имени файла для вывода
!fileName = !!Alert.Input('Введите имя файла для вывод информации','d:\welds.txt')

!outputA = OBJECT ARRAY()


!finalOutput = OBJECT ARRAY()
!finalOutput[1] = 'Подсчет сварных элементов для ' + !!CE.Type + ' ' + !!CE.Name
---1.Блок 1. Компоненты трубопроводов отдельно от WELD
--собираем все компоненты трубопроводов, исключая сварные швы
VAR !branmem COLL ALL BRAN MEM WITH ( TYPE NEQ 'WELD' AND TYPE NEQ 'TUBI' ) FOR CE
do !x from 1 to !branmem.Size()
$!branmem[$!x]
--собираем информацию о точках присоединения каждого компонента
VAR !p1con P1 CONN
VAR !p1bor P1 BORE
VAR !p2con P2 CONN
VAR !p2bor P2 BORE
if (!!Ce.Type EQ 'TEE' OR !!CE.Type EQ 'OLET') then
VAR !p3con P3 CONN
VAR !p3bor P3 BORE
else
!p3con = 'NULL'
!p3bor = 'NULL'
endif
if (!!Ce.Type EQ 'CROS') then
VAR !p4con P3 CONN
VAR !p4bor P3 BORE
else
!p4con = 'NULL'
!p4bor = 'NULL'
endif

--если сварка - добавляем


if (!p1con EQ 'BWD') then
!outputA.Append(!p1bor + ',' + !p1con)
endif

Автор: Сергей Лебедев


AVEVA

if (!p2con EQ 'BWD') then


!outputA.Append(!p2bor + ',' + !p2con)
endif
if (!p3con EQ 'BWD') then
!outputA.Append(!p3bor + ',' + !p3con)
endif
if (!p4con EQ 'BWD') then
!outputA.Append(!p4bor + ',' + !p4con)
endif

enddo

--вводим второй массив и сортируем его уникально


!newOutputA = !outputA
!newOutputA.SortUnique()

--окончательный массив для вывода - ищем количество по диаметрам


do !x from 1 to !newOutputA.Size()
!findwhat = !newOutputA[!x]
!howmuch = !outputA.Find(!findwhat).Size()
!finalOutput.Append('Компонент Ду=' + !newOutputA[!x].Split(',')[1] + ', сварных швов=' + !howmuch.String())
enddo

--возвращаемся к элементу
$!backCE
---2.Блок 2. Отдельно сварные швы - WELD
--очищаем предыдущий вспомогательный массив
!outputA.Clear()
VAR !welds COLL ALL WELD FOR CE
do !x from 1 to !welds.Size()
$!welds[$!x]

--собираем информацию о точках присоединения каждого WELD - только два точки!


VAR !p1con P1 CONN
VAR !p1bor P1 BORE
!outputA.Append(!p1bor + ',' + !p1con)

enddo

--очищаем второй уникальный массив


!newOutputA.Clear()
--вводим воторой массив и сортируем его уникально
!newOutputA = !outputA
!newOutputA.SortUnique()

--добавляем данные в окончательный массив - ищем количество по диаметрам


do !x from 1 to !newOutputA.Size()
!findwhat = !newOutputA[!x]
!howmuch = !outputA.Find(!findwhat).Size()
!finalOutput.Append('Отдельно сварных швов на трубе Ду=' + !newOutputA[!x].Split(',')[1] + ', ' + !howmuch.String())
enddo

--выводим в файл и открываем


!FO = OBJECT FILE(!fileName)
!FO.Writefile('OVERWRITE',!finalOutput)
SYSCOM |EXPLORER $!fileName &|

(вернуться к содержанию)

37.Разбивка трубопровода фланцами


Необходимо разбить трубопровод с помощью сборки фланцев под покрасочную ванну. Длина ванны
задается пользователем.

Решение:

--проверяем текущий тип - нужен бранч


if (!!CE.Type NEQ 'BRAN') then
!!Alert.Message('Нужно выделить бранч...')
RETURN
endif

Автор: Сергей Лебедев


AVEVA

--просим ввести длину ванны и переводим ее в тип Real


!lengthOfBasinS = !!Alert.Input('Введите длину ванны','4000')
!lengthOfBasin = !lengthOfBasinS.Real()
--собираем все прямые участки труб
VAR !tubis COLLECT ALL TUBI FOR CE
--запускаем по ним цикл для проверки длины
do !x from 1 to !tubis.Size()
$!tubis[$!x]
!number = '0'
--больше ли длина текущего прямого участка длины ванны
--если да то ищем сколько будет разбивок
if (!!CE.Itle GT !lengthOfBasin) then
!howmuch = !!CE.Itle / !lengthOfBasin
!number = !howmuch.String().Before('.')
endif

--идем по количеству разбивок и создаем сборки


do !n from 1 to !number.Real()
--команда создания фланца с дефолтным значением селектора
NEW FLAN CHOOSE DEF
--сдвигаем его на нужное расстояние
if (!!CE.Sequ EQ 1 AND !tubis.Size() NEQ 1) then
POS PA AT PH OF BRAN
MOVE PA ALONG PH OF BRAN DIST $!lengthOfBasin FROM PH OF BRAN
endif
if (!!CE.Sequ EQ 1 AND !tubis.Size() EQ 1) then
POS PA AT PH OF BRAN
MOVE PA ALONG PH OF BRAN DIST $!lengthOfBasin FROM PH OF BRAN
endif
if (!!CE.Sequ NEQ 1) then
CONN TO PREV
MOVE PA ALONG PL OF PREV DIST $!lengthOfBasin FROM PL OF PREV
endif
--прокладка
NEW GASK CHOOSE DEF
CONN
-ответный фланец
NEW FLAN CHOOSE DEF
CONN
enddo
Enddo

(вернуться к содержанию)

38.Масштабирование и центрирование содержимого экрана


Очень простая функция для выполнения масштабирования и центрирования содержимого экрана.
Бывает очень полезна при обработке графики. Аналог функции Walk to Drawlist

Вариант 1 (с циклом обработки каждого элемента)

--определяем функцию
define function !!arwalktodrawlist()
--вводим объем типа Drawlist
!draw = object drawlist()
--получаем содержимое
!glbDraw = !draw.Globaldrawlist().Members()
--проверяем что Dralist не пустой
if (!glbdraw.size() EQ 0) then
RETURN
Endif
--обрабатываем элементы
!RT = object array()
do !x from 1 to !glbDraw.Size()
!RT[!x] = !glbDraw[!x].String()
enddo

--выполняем обработку и центрируем


!BLOCK = OBJECT BLOCK('!RT[!EVALINDEX].DBREF()')
!LIST = !RT.EVALUATE(!BLOCK)
!VOLUME = OBJECT VOLUME(!LIST)

Автор: Сергей Лебедев


AVEVA

!LIM = OBJECT GPHVIEWS()


!LIM.LIMITS(!!GPH3DDESIGN1.VIEW, !VOLUME)

Endfunction

Вариант 2 (более простой, без цикла)

--определяем функцию
define function !!arwalktodrawlist()

--запрашиваем элементы Drawlist


!volume = object VOLUME(!!gphdrawlists.drawlists[1].members())
--масштабируем
!!gphViews.limits(!!gphviews.views[1], !volume)

Endfunction

(вернуться к содержанию)

39.Нахождение коллизий указанного элемента


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

Решение:

!!Alert.Message('Укажите элемент для проверки на столкновения (HH)...')


ID @
DESCLASH
OVERRIDE ON
REM OBST ALL
OBST ALL
--выбрать элемент
!currE = !!CE.Name
CHECK $!currE
--найти общее количество клэшей для CE
VAR !allClashes CLASH COUNT CLASHES
!clashesArr = object Array()
--Цикл по всем клэшам и добавление на экран
Do !x from 1 to !allClashes.Real()

VAR !Clashee CLASH $!x SECOND

--проверка есть ли труба в том, с чем столкнулись


--и формирование массива с командами для последующего выполнения (команды формируются в синтаксисе PDMS)
If (!Clashee.Matchwild('*(tube)*')) then
!elToAdd = !Clashee.Split()[1]
!element = !elToAdd.Dbref().Owner
else
!element = !Clashee.Dbref()
Endif
!clashesArr.Append('ADD $!element ENHANCE $!element COLOUR 2')

enddo
EXIT
--вывести коллизии выполнив команды добавления и раскраски, записанные ранее
do !x from 1 to !clashesArr.Size()
$!clashesArr[$!x]
enddo

--сообщение если коллизий нет


if (!clashesArr.Size() EQ 0) then
!!Alert.Message('У выбранного элемента коллизий не обнаружено')
endif

Автор: Сергей Лебедев


AVEVA

40.Описание опор в зависимости от координаты


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

Решение:

--собираем опоры
VAR !attas COLL ALL ATTA FOR CE
do !x from 1 to !attas.Size()
$!attas[$!x]
--запрашиваем позиции по высоте
VAR !CEU U
--если позиция по U в указанном диапазоне, назначаем текст
if (!CEU.Real() GT -1000 AND !CEU.Real() LT 1000) then
Stext |Уровень 0|
endif
if (!CEU.Real() GT 1000 AND !CEU.Real() LT 5000) then
Stext |Уровень 1|
endif
enddo

(вернуться к содержанию)

41.Автоизменение параметров каталога


Задача:
в Paragon у всех найденных категорий изменить название третьего параметра на "Тип присоединения"
и всем компонентам в качестве значения третьего параметра установить BWD.

Решение:

--собираем категории для CE


VAR !cates COLL ALL CATE FOR CE
--проходим в цикле по категориям и меняем описание третьего параметра
--при этом описание хранится в элементе TEXT с суффиксом PA3
do !x from 1 to !cates.Size()
!textPara3Name = !cates[!x].Dbref().Name + '-PA3'
--попытка сделать TEXT текущим
$!textPara3Name
HANDLE ANY
ENDHANDLE
Stext |Тип присоединения|
--часть2.компоненты
VAR !scoms COLL ALL SCOM FOR $!cates[$!x]
--проходим во втором цикле по каждому элементу и задаём ему значение третьего параметра
do !y from 1 to !scoms.Size()
$!scoms[$!y]
PARA N3 BWD
enddo
enddo

(вернуться к содержанию)

42.Удаление элементов с помощью графического выделения


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

--Вызываем конструктор объекта selection


!CurSel = object selection()
--Получаем текущее на экране выделение
!CurSel.GetCurrent()
--Число элементов в выделении
!CurSelEl = !CurSel.GetSelection()

if ( !CurSelEl.Size() EQ 0 ) then
!!Alert.Message('Выделите элементы')

Автор: Сергей Лебедев


AVEVA

return
endif
--Удаляем в цикле все найденное
do !Entity values !CurSelEl
!ElName = !Entity.Name
!ElType = !Entity.Type
delete $!ElType
$P Удалено $!ElName
Enddo

(вернуться к содержанию)

43.Раскрашивание элементов бранча в 3D-модели


Стандартные правила автораскраски элементов (Autocolor Rules) не позволяют раскрашивать отдельные
компоненты бранчей в модуле Design, однако можно воспользоваться приведенным ниже кодом для
подсветки, к примеру, шаровых кранов красным цветом:
--Собираем все шаровые краны - элементы VALV с STYP=BALL
var !BranchMem coll all valv with styp eq 'BALL' for ce
--В цикле красим каждый найденный элемент с помощью команды ENHANCE
do !x values !BranchMem
ENHANCE $!x COLOUR RED
enddo

То же самое в более компактной форме:


ENHANCE ALL VALV WITH ( STYP EQ 'BALL' ) COLOUR RED FOR CE

Вместо названия цвета можно использовать его код. Ниже приведены коды основных цветов:
Grey 1
Red 2
Orange 3
Yellow 4
Green 5
Cyan 6
Blue 7
Violet 8
Brown 9
White 10
Pink 11
Mauve 12
Turquoise 13
Indigo 14
Black 15
Magenta 16

(вернуться к содержанию)

44.Когда длина детального текста превышает 120 символов...


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

--Собираем в коллекцию все SPCO


var !AllSpco coll all SPCO for ce
do !x Index !AllSpco
--Проверяем наличие ссылки на детальный текст
!SpcoText[!x] = !AllSpco[!x].Dbref().Dtxr
HANDLE (2,220)(2,232)
$P У компонента $!AllSpco[$!x] отсутствует ссылка на детальный текст
skip
ENDHANDLE

--Если длина превышена, выводим информацию в командную строку


!SpcoTextLength[!x] = !SpcoText[!x].Length()
if (!SpcoTextLength[!x] GE 120) then

Автор: Сергей Лебедев


AVEVA

$P У компонента $!AllSpco[$!x] длина текста $!SpcoTextLength[$!x] символов


endif
enddo

Запускать макрос можно находясь в иерархии на спецификации, или можно собрать компоненты
спецификации по всей MDB - для этого достаточно удалить фразу for ce в первой строчке кода.

(вернуться к содержанию)

45.Вычисляем реальную длину текста на чертеже


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

У всех текстовых примитивов на чертеже (TEXP) есть псевдо-атрибут extent btext, в котором содержится
массив координат x,y габаритного прямоугольника, в котором размещается текст. Нумерация точек
начинается с верхней левой и далее по часовой стрелке. Характерная особенность: запросить extent btext
можно только на PML1.

Пример макроса для вычисления длины текста в мм:


!string = 'Отвод-2", 1.5ND, LR90, приварной, WPHY42, 2.0MПa'
NEW TEXP
BTEX '$!string'
-- Вычисляем пары x,y четырех точек габаритного бокса
var !texcoord extent btext
-- В массиве !texcoord содержатся данные вида:
-- X 791 Y 514 X 866 Y 514 X 866 Y 510 X 791 Y 510
!texsplit = !texcoord.Split()
-- Вычисляем длину текста по оси Х
!texlen = !texsplit[6].Real() - !texsplit[2].Real()
!texlen = !texlen.String('D0').Real()
$P Длина текста в мм: $!texlen

Далее можно продолжить и написать функцию для переноса части текста в случае, если он не помещается в
колонку.

(вернуться к содержанию)

46.Маркировка в Design выбранным атрибутом


Задача:
проставить визуальные метки в модуле Design на выбранные элементы с содержимым выбранных
атрибутов. Например, вывести значение атрибута Desc на все элементы SCTN внутри CE (строительные оси)

Решение:

--Что ищем
!what = !!Alert.Input('Тип для поиска',|SCTN|)
--Какой атрибут
!att = !!Alert.Input('Атрибут для маркирования',|DESC|)
--собираем элементы
VAR !items COLLECT ALL $!what FOR CE
do !x from 1 to !items.Size()
$!items[$!x]
--запрашиваем атрибут
var !scAtt $!att
--маркируем
MARK WITH '$!scAtt' CE
enddo

(вернуться к содержанию)

Автор: Сергей Лебедев


AVEVA

47.Пример команды FLIP для SCTN


Задача:
реализовать команду FLIP для SCTN (поменять местами Начало и Конец SCTN)

Решение:

--собираем все SCTN внутри CE


VAR !sctns COLLECT ALL SCTN FOR CE
do !x from 1 to !sctns.Size()
--запоминаем текущие значения
!scposS = !sctns[!x].Poss
!scposE = !sctns[!x].Pose
--меняем местами
!sctns[!x].Poss = !scposE
!sctns[!x].Pose = !scposS
enddo

(вернуться к содержанию)

48.Пишем свой класс на PML 2. Часть 1


Немного теории
Язык PML 2 является объектно-ориентированным языком программирования (ООП), хотя и с некоторыми
оговорками. Тем не менее, в технологии ООП ключевым является понятие классов, которые представляют
собой пользовательские (абстрактные) типы данных.
Классы объединяют в себе члены классов, представляющие собой данные и способы их обработки.
Членами классов являются: поля, описывающие данные класса, методы, задающие поведение класса, и
события, обеспечивающие связь между различными классами и объектами.
В рамках языка PML 2 можно выделить такие члены класса как members (поля) и methods (методы). Поля
представляют собой переменные, непосредственно объявленные в области класса. Поля подобны
переменным в том, что их можно прочитать или изменить напрямую. Метод – это функциональный
элемент класса, содержащий некоторый набор инструкций, выполняемых классом. Совокупность методов
класса определяет, что конкретно может выполнять класс.
Чтобы использовать класс необходимо в коде создать его экземпляр. Делается это с помощью ключевого
слова object:
!a = object имя_класса()
В переменной !a хранится ссылка на объект, построенный на основе указанного класса. Для вызова методов
используется “точечный” синтаксис:
!a.метод()
Просмотреть все доступные методы класса можно с помощью команды:
q methods !a или q meth !a

(вернуться к содержанию)

49.Пишем свой класс на PML 2. Часть 2


Реализация
В спецификации языка PML предусмотрено множество полезных математических функций (их описание
приведено во встроенной справке). Вместе с тем отсутствуют, например, встроенный генератор случайных
чисел, а также функции, связанные с целочисленным делением. Последние на практике встречаются
довольно часто. Исправим ситуацию, написав собственный класс Math, в котором реализуем недостающие
функции. Реализация генератора случайных чисел (точнее псевдослучайных чисел) была взята по аналогии с
языком Visual Basic (см. ссылку ниже).
Ниже представлен код класса Math. Комментарии даны по ходу.

-- Определение класса Math


define object Math
-- Поле Result хранит результат, возвращаемый методами класса Math
member .Result is real
-- *Конструктор по умолчанию*
-- Это метод, который не принимает никакх аргументов и его имя совпадает с именем класса.
-- Его может и не быть, но если он присутствует в классе, то он будет автоматически вызван при создании экземпляра класса.
define method .Math()
!this.Result = 0

Автор: Сергей Лебедев


AVEVA

-- Глобальная переменная !!Rndx0 - стартовое значение для фукнции генерирования случайных чисел (см. формулу)
-- Реализация генератора псевдослучайных чисел см. http://support.microsoft.com/kb/231847
!!Rndx0 = 327680
endmethod
-- *Метод .div(), вычисляющий неполное частное*
-- Подразумевается val1 - делимое, val2 - делитель
-- Используется стандратная функция INT(), отбрасывающая дробную часть
define method .div(!val1 is real, !val2 is real) is real
!this.Result = INT(!val1 / !val2)
return !this.Result
endmethod

-- *Метод .mod(), вычисляющий остаток от деления*


-- Подразумевается val1 - делимое, val2 - делитель
-- Используется написанный выше метод .div()
define method .mod(!val1 is real, !val2 is real) is real
!this.Result = !val1 - !val2 * !this.div(!val1, !val2)
return !this.Result
endmethod
-- *Mетод .rnd(), реализующий генерирование случайных чисел в диапазоне от 0 до 1*
define method .rnd() is real
-- Функция, генерирующая случайные числа линейным конгруэнтным методом
-- Коэффициенты а, с см. формулу
-- Используется написанный ранее метод .mod()
!a = 1140671485
!c = 12820163
!!Rndx1 = !this.mod ((!!Rndx0 * !a + !c ),POWER(2,24))
!!Rndx1 = !this.Result / POWER(2,24)
!this.Result = !!Rndx1
!!Rndx0 = !!Rndx1
return !this.Result
endmethod
-- *Перегруженный метод .rnd(val1, val2)*
-- Перегруженные методы - это методы имена которых совпадают, но тип их возвращаемых значений разный и/или набор
входных аргументов также отличается
-- Реализует генерирование случайных чисел в диапазоне от 0 до val2 (предполагается val1 = 0)
define method .rnd(!val1 is real, !val2 is real) is real
if (!val1 NEQ 0) then
!!Alert.Error('Нижняя граница должна быть 0')
return
endif
!a = 1140671485
!c = 12820163
!!Rndx1 = !this.mod ((!!Rndx0 * !a + !c ),POWER(2,24))
!!Rndx1 = !val2 * !this.Result / POWER(2,24)
!this.Result = !!Rndx1
!!Rndx0 = !!Rndx1
return !this.Result
endmethod
Endobject

(вернуться к содержанию)

50.Как работать с новым классом


В языке PML 2 пользовательские классы хранятся в файлах с расширением *.pmlobj. Для того чтобы
использовать новый класс, его необходимо поместить в папку PMLLIB и отработать команду PML REHASH
ALL.
Далее создается экземпляр класса:
!x = object Math()
А затем вызываются его методы:
!y = !x.div(20,7) –> q var !y
или сразу
q var !x.div(20,7)
По аналогии:
!y = !x.mod(20,7)
!y = !x.rnd()
!y = !x.rnd(0,50)

Заключение

Автор: Сергей Лебедев


AVEVA

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

(вернуться к содержанию)

51.Вычисление длины текста. Продолжение


В одной из предыдущих тем был рассмотрен способ нахождения длины текста. В этом разделе представлен
макрос адаптивной подгонки текста с расстановкой переносов в зависимости от ширины колонки. Макрос
может быть полезен при оформлении таблиц и спецификаций в модуле DRAFT.

!InputText = !!Alert.Input('Введите текст',' ')


NEW TEXP AT @
BTEXT '$!InputText'
var !Text extent btext
!TextSpl = !Text.Split()
-- Длина текста
!TextLen = !TextSpl[6].Real() - !TextSpl[2].Real()
-- Ширина колонки
!InputTextLen = 60
-- Сравниваем длину строки с шириной колонки
if (!TextLen GT !InputTextLen) then
!TextOutput = ''
!n = 1
-- Разделяем слова по пробелам
!Split = !InputText.Split()
do !x index !Split
!TextOutput = !TextOutput & !Split[!x] & ' '
-- Удаляем последний пробел
if (!x eq !Split.Size()) then
!TextOutput = !TextOutput.Trim()
endif

BTEXT '$!TextOutput'

-- Вычисляем длину каждого слова


var !TextCoord extent btext
!TextParts = !TextCoord.Split()
!TextLen = !TextParts[6].Real() - !TextParts[2].Real()

if (!TextLen GT !InputTextLen) then


-- Заменяем предпоследний пробел на знак переноса #/
!TextOutput = !TextOutput.Replace(' ','#/',!x - !n,1)
!n = !n + 1
endif
enddo
BTEXT '$!TextOutput'
endif

(вернуться к содержанию)

52.Найти связанные системы, обвязку


Как с помощью PML-команды добавить все связанные с текущим элементом объекты - например обвязку:
другие бранчи этой системы, оборудование, к которому ведет система и т.д
Для этого есть команда:
!network = CONNECTIONSH
При этом в переменную !network запишется массив "значимых" объектов, соединенных с текущим.

Далее по циклу делаем с ними то, что нужно, например добавляем на экран, таким образом, получая
отображение обвязки:

do !x from 1 to !network.Size()
$!network[$!x]
ADD CE
Enddo

(вернуться к содержанию)

Автор: Сергей Лебедев


AVEVA

53.Создание разрыва на чертеже


Ниже представлен макрос для простановки разрывов на чертеже – путем указания элемента

-- текущий вид
if (!!CE.Type NEQ 'VIEW') then
VIEW
handle (2,111)
!!alert.Message('Перейдите на Вид...')
return
endhandle
endif
!view = !!CE
!draw = !!CE.Owner.Owner
!vdir = !!CE.dir
!viewname = !!CE.name.String()
if (!vdir eq D) then
!defdir = 'N'
!defSectdir = 'U'
elseif (!vdir eq U) then
!defdir = 'N'
!defSectdir = 'D'
elseif (!vdir eq E) then
!defdir = 'N'
!defSectdir = 'W'
elseif (!vdir eq W) then
!defdir = 'N'
!defSectdir = 'E'
elseif (!vdir eq N) then
!defdir = 'E'
!defSectdir = 'S'
elseif (!vdir eq S) then
!defdir = 'E'
!defSectdir = 'N'
else
!!alert.Message('Данная утилита работает только для ортогональных видов')
return
endif
!libraryName = !viewname & '/PLANES'
!standardLibrary = object DBREF(!libraryName)
handle ANY
-- ищем все библиотеки PLLB вида
-- если нет - создаем новую
!!ce = !view
end
var !planeLibraries COLLECT ALL (PLLB) FOR CE
if (!planeLibraries.size() gt 0) then
!standardLibrary = !planeLibraries[1].dbref()
else
!!ce = !view
NEW PLLB $!libraryName
!standardLibrary = !!ce
endif
endhandle
-- формируем имя SPLA
do !i from 1 to 10
!newName = !viewname & '/SP' & !i.string()
!unusedTestName = object DBREF(!newName)
handle (2,109)
-- если имя еще не используется - выход из цикла
break
elsehandle ANY
!!alert.error(!!error.text)
return
break
elsehandle NONE
-- Имя уже используется - продолжаем цикл
endhandle
enddo
!scale = !view.vscale
!size = !view.size[1]
!position1 = !view.thpos
!position1.east = (!position1.east - ((!size / 2) / !scale) - ((!size * 0.05) / !scale))
!position2 = !view.thpos

Автор: Сергей Лебедев


AVEVA

!position2.east = (!position2.east + ((!size / 2) / !scale) + ((!size * 0.05) / !scale))


-- библиотеки
!dllb = !!CollectAllFor('DLLB',||, $!draw)
--создаем SPLA
!!ce = !standardLibrary
new spla $!newName
direction $!defSectdir
Gtype CLOS
new wpos
!pos1string = !position1.wrt(/* )
pos $!pos1string
new wpos
!pos2string = !position2.wrt(/* )
pos $!pos2string
--создаем VSEC
!!ce = !view
!vsecName = !newName & '/VSEC'
NEW VSEC $!vsecName
PLRF $!newName
!reference = !!ce.plrf.reference.string()
!newSectionPlane = object SECTIONPLANE(!!ce.plrf.reference)
!sectionPlanes = object SECTIONPLANEMANAGER()
!sectionPlanes.add(!newSectionPlane)
!element = object SECTIONPLANE(!reference.dbref())
!element.highlight()
--указываем трубу - TUBI
!!alert.Message('Укажите элемент')
ID @
if (!!CE.Owner.Type eq 'BRAN') then
!elem = !!CE
!own = !!CE.Owner
!owntype = !!CE.Owner.Type
var !pldir Pl dir of CE
var !bore Lodiam
!bor = !bore.Real() + 10
elseif (!!CE.Type eq 'BRAN') then
!own = !!CE
var !pldir hdir of CE
var !bore Phod
!bor = !bore.Real() + 10
elseif ( !!CE.dbtype eq 'DESI') then
!own = !!CE.Owner
!owntype = !!CE.Owner.Type
!bore = !!alert.input('Введите значение','20')
!bor = !bore.Real()
!pldir = !defdir
else
!!alert.Message('Элемент модели не выбран')
$!vsecName
DELETE VSEC
return
endif
--вычисление координаты точки разрыва
!!alert.Message('Укажите место разрыва')
$!view
var !posTemp ENUPOS OF @
!posR = !posTemp.Position()
--формируем Drawlist
-- переход на нужный уровень иерархии - DLLB
$!dllb[1]
-- формируем имя Drawlist
do !m from 1 to 10
!idlistname = !viewname & '/DR' & !m.string()
!unusedTestName = object DBREF(!idlistname)
handle (2,109)
-- неопределенное имя
break
elsehandle ANY
!!alert.error(!!error.text)
return
break
elsehandle NONE
-- если имя уже есть

Автор: Сергей Лебедев


AVEVA

endhandle
enddo
-- создание Drawlist
NEW IDLIST $!idlistname
NEW ADDENTRY
IDNM $!owntype $!own
--расчет положения и ориентации плоскости
!ortd = !vdir.Orthogonal($!pldir)
!ort = !ortd.String().Before('WRT')
!opd = !ortd.Opposite()
!op = !opd.String().Before('WRT')
--обновляем плоскость
-- ссылка на Drawlist
$!vsecName
IDLN IDLIST $!idlistname
!delta = !bor
-- точка 1
WPOS 1 of SPLANE $!newName
!pos1 = !posR.Offset($!pldir,-($!delta))
!pos11 = !pos1.Offset($!op,$!delta)
POS $!pos11
-- точка 2
WPOS 2 of SPLANE $!newName
!pos2 = !posR.Offset($!pldir,-($!delta))
!pos22 = !pos2.Offset($!ort,$!delta)
POS $!pos22
-- точка 3
NEW WPOS
!pos3 = !posR.Offset($!pldir,$!delta)
!pos33 = !pos3.Offset($!ort,$!delta)
POS $!pos33
-- точка 4
NEW WPOS
!pos4 = !posR.Offset($!pldir,$!delta)
!pos44 = !pos4.Offset($!op,$!delta)
POS $!pos44
--обновляем вид
$!view
UPDATE ALL

(вернуться к содержанию)

54.Расширяем возможности PML


Ранее мы уже рассматривали создание пользовательского объекта (класса) на примере генератора
случайных чисел. Теперь рассмотрим, как расширить функциональность языка PML, передав ему родной
объект Random из библиотеки классов .NET.

В Visual Studio пишем следующий код:

using Aveva.PDMS.PMLNet;
namespace AVEVA.PDMS.NetRandom
{
//Атрибутом PMLNetCallable помечается класс, публикуемые члены, а так же сборка
[PMLNetCallable()]
public class NetRandom
{
//Число знаков после запятой
private int _decim = 4;
//Задаем свойство
[PMLNetCallable()]
public double Decimals
{
get { return _decim; }
set { _decim = (int)value; }
}
//Конструктор по умолчанию
[PMLNetCallable()]
public NetRandom()
{
}
//Метод Assign

Автор: Сергей Лебедев


AVEVA

[PMLNetCallable()]
public void Assign(NetRandom that)
{
}
//Генерирование случайного числа в диапазоне от 0 до 1
[PMLNetCallable()]
public double GetRnd()
{
Random rnd = new Random();
return Math.Round(rnd.NextDouble(), (int)Decimals);
}
//Генерирование случайного числа в диапазоне от min до max
[PMLNetCallable()]
public double GetRnd(double min, double max)
{
Random rnd = new Random();
return Math.Round((int)min, (int)max);
}
}
}

Компилируем dll библиотеку и выкладываем ее по пути установки PDMS. Обращение к классу NetRandom из
кода PML выглядит следующим образом:

-- Подгружаем сборку netrandom.dll


import 'netrandom'
-- Обращаемся к пространству имен 'Aveva.Pdms.NetRandom'
using namespace 'Aveva.Pdms.NetRandom'
-- Создаем экземпляр класса
!x = object netrandom()
-- Вызываем методы
q var !x.getrnd()
q var !x.getrnd(10,20)
Подобным образом можно расширять спецификацию PML, дополняя ее любыми другими объектами .NET в
том числе и графическими контролами.

(вернуться к содержанию)

55.Автозапуск формы или функции


Задача:
автоматически открыть форму или запустить функцию/макрос при запуске системы, например модуля
Design.

Вариант 1
При запуске модуля обрабатывается файл с синонимами, называемый VARS, который расположен в пути
%PDMSUI%\des\admin\
Соответственно, копируем это файл в точно такой же путь, но в нашу собственную папку, например
%MYPDMSUI%\des\admin\, чтобы не трогать оригинальный путь (при этом наша папка должна быть указана
в запускаемом бат-файле на первом месте перед оригинальным %PDMSUI%) и редактируем следующим
образом, добавляя в конец (перед строчкой CHOOSE AUTOC OFF) следующие строчки:

--Для автозапуска формы:


SHOW !!MYFORM
--или для автозапуска максроа
$M/путь_к_моему_макросу
или для автозапуска функции
!!MYFUNCTION()

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

Вариант 2
Использовать файл start, расположенный по такому же пути. Действия одинаковые. Автовызов добавляется
в конец файла

(вернуться к содержанию)

Автор: Сергей Лебедев


AVEVA

56.Пример сортировки сложного массива по одной из составных частей


Задача:
необходимо обработать коллекцию элементов (компоненты ветви трубопровода) и составить массив
строковых данных, который выглядит как:
Ду;Наименование;Материал
при этом необходимо отсортировать этот массив по Ду в порядке увеличения значения.

Решение:

--собираем нужные элементы внутри текущего (в примере - арматура) и запускаем цикл обработки
var !allValves COLLECT ALL VALV FOR CE
do !x from 1 to !allValves.Size()
--первый массив - массив диаметров, взятых из каталога. ВАЖНО - массив имеет тип REAL для последующей сортировки
!DuArray[!x] = !allValves[!x].Dbref().Spref.Catref.Para[1]
--второй массив - массив Наименований, взятых из Dtxr, каждая ячейка соответствует ячейке первого массива
--и перехватываем ошибку на случай, если не задана ссылка на каталог
!dtxrArray[!x] = !allValves[!x].Dbref().Dtxr
HANDLE ANY
!dtxrArray[!x] = 'нет наименования-проверьте каталог/ссылку Detref'
ENDHANDLE
--третий массив - массив Материалов, взятых из Mtxx, каждая ячейка соответствует ячейке первого (И второго) массива
--и перехватываем ошибку на случай, если не задана ссылка на каталог
!mtxxArray[!x] = !allValves[!x].Dbref().Mtxx
HANDLE ANY
!mtxxArray[!x] = 'нет материала-проверьте каталог/ссылку Matext'
ENDHANDLE
--формирование выходного, несортированного массива
!nonSortedArray[!x] = !DuArray[!x].String() + ';' + !dtxrArray[!x] + ';' + !mtxxArray[!x]
enddo
--вывод несортированного массива
q var !nonSortedArray
--запоминаем массив индексов, как если бы была применена операция сортировки
--пример
--!q[1] = 200 !q[2] = 50 !q[3] = 100 - здесь индексы (indexes) 1=200,2=50,3=100
--операция sortedindices вернет следующее:
--1=2,2=3,3=1 то порядок следования ячеек прошлого массива как если бы была сортировка
!changedOrder = !DuArray.SortedIndices()
--запускаем цикл и формируем новый массив
--ячейки которого будут сформированы путем вытаскивания нужных (по сортированному порядку) ячеек из оригинальных
массивов
do !x from 1 to !changedOrder.Size()
--формирование массива
!sortedArray[!x] = !DuArray[!changedOrder[!x]].String() + ';' + !dtxrArray[!changedOrder[!x]] + ';' + !mtxxArray[!changedOrder[!x]]
enddo
--вывод сортированного массива
q var !sortedArray

(вернуться к содержанию)

57.Коллекция элементов - Drawlist + Volume


Задача:
на экране находятся некоторое количество элементов модели (текущий Drawlist). необходимо собрать
коллекцию элементов, которые в одно и тоже время находятся внутри определенного объема и при этом
находятся в текущем Drawlist.

Автор: Сергей Лебедев


AVEVA

Решение:
Базовый синтаксис для коллекции элементов из Drawlist
VAR !itemInDrawlist COLLECT ALL FROM DRAWLIST
Базовый синтаксис для коллекции элементов внутри определенного объема
VAR !itemInVolume COLLECT ALL WITHIN En1 Sn1 Un1 TO En2 Sn2 Un2
где ESU - мировые оси, по которым нужно провести объем (могут быть E или W, N или S, U или D), а n1, n2 -
значения координат по этим осям. При этом если представить себе объем в виде куба, то En1 Sn1 Un1 - это
координата нижнего левого ближнего угла, а En2 Sn2 Un2 - координата верхнего правого угла куба, то есть
диагональ. (См.рисунок внизу)

А вот код, который позволяет провести сравнение двух коллекций и выполнить поставленную задачу:

--собираем все элементы из Drawlist


var !itemsInDrawlist COLLECT ALL FROM drawlist
--собираем все, что попало в необходимый намобъем
var !itemsInVolume COLLECT ALL WITHIN E9700 S71000 U429 TO E9954 S68000 U660
--определяем финальный массив
!itemsOnScreenAndInVolume = object array()
--запускаем цикл поиска вхождения элементов первого массива во второй
do !x from 1 to !itemsInDrawlist.Size()
--если элемент первого массива найден во втором - добавляем его в финальный массив
if (!itemsInVolume.FindFirst(!itemsInDrawlist[!x]).String() NEQ '') then
!itemsOnScreenAndInVolume.Append(!itemsInDrawlist[!x])
endif
enddo
q var !itemsOnScreenAndInVolume

(вернуться к содержанию)

58.Замена отводов на гибы и наоборот


Задача:
В существующей компоновке трубопровода массово заменить все отводы (ELBO) на гибы-бенды (BEND) или
наоборот

--запрос в какую сторону менять


!how = !!Alert.Question('ELBO-->BEND (Нажмите YES)
BEND-->ELBO (Нажмите NO)')

--выбираем тип в заивсимости от ответа пользователя


if (!how EQ 'YES') then
!getTypeFind = ' ELBO '
!getTypeReplace = ' BEND '
endif
if (!how EQ 'NO') then
!getTypeFind = ' BEND '
!getTypeReplace = ' ELBO '
endif
if (!how EQ 'CANCEL') then
RETURN
endif

--пытаемся собрать выбранный тип, если не найдено - выходим


VAR !getItems COLLECT ALL $!getTypeFind FOR CE

Автор: Сергей Лебедев


AVEVA

if (!getItems.Size() EQ 0) then
!!Alert.Message('Элементов типа $!getTypeFind не найдено внутри CE. Остановлено...')
RETURN
endif

--подсвечиваем найденные
do !x from 1 to !getItems.Size()
$!getItems[$!x]
ENHANCE CE COLOUR RED
MARK WITH '$!getTypeFind' CE
enddo

--и задаем вопрос о продолажении


!continue = !!Alert.Confirm('Найдено ' + !getItems.Size().String() + ' $!getTypeFind .
Заменить на $!getTypeReplace?')
if (!continue EQ 'NO') then
RETURN
endif

--снимаем маркировку
UNMARK ALL

--запоминаем трубопроводную спецификацию


!getPspec = !getItems[1].Dbref().Spow.Name
--включаем режим - "по потоку"
FORWARDS

--запускаем процесс
do !x from 1 to !getItems.Size()

--переходим на элемент и запоминаем атрибуты


$!getItems[$!x]
VAR !getBore P1 BORE
!getBoreReal = !getBore.Real().Value()
VAR !getOri ORI WRT /*
VAR !getPos POS WRT /*
VAR !getPLDir PL DIR
VAR !getRadi RADI
VAR !getAngle ANGLE

--пытаемся найти SPCO соответствующего типа и параметров


if (!how EQ 'YES') then
VAR !getSpref COLLECT ALL SPCO WITH ( GTYP OF CATREF EQ 'BEND' AND PARA[1] OF CATREF EQ $!getBoreReal ) FOR
$!getPspec
if (!getSpref.Size() EQ 0) then
!!Alert.Message('В текущей спецификации $!getPspec необнаружено бендов на диаметр $!getBore . Выход их
программы..')
RETURN
endif
!newSpref = !getSpref[1]
endif
if (!how EQ 'NO') then
VAR !getSpref COLLECT ALL SPCO WITH ( GTYP OF CATREF EQ 'ELBO' AND PARA[1] OF CATREF EQ $!getBoreReal ) FOR $!getPspec
if (!getSpref.Size() EQ 0) then
!!Alert.Message('В текущей спецификации $!getPspec необнаружено отводов на диаметр $!getBore . Выход их
программы..')
RETURN
endif
!newSpref = !getSpref[1]
endif

--меняем тип и переформируем атрибуты


CHANGETYPE TO $!getTypeReplace
Spref $!newSpref
CONN
Radi $!getRadi
Angl $!getAngle
POS $!getPos
DIR $!getPLDir
MARK WITH '$!getTypeReplace' CE
ENHANCE CE COLOUR GREEN

enddo

OWNER

Автор: Сергей Лебедев


AVEVA

59.Пример проверки битых ссылок и отчет


Задача:
Необходимо проверить элементы трубопровода на предмет:
 Наличия битых ссылок Spref (связь с каталогом)
 Наличия битых ссылок у бранчей Href/Tref (связь со штуцерами и другими бранчами)

--определяем файл отчета


!repFilePath = 'C:\temp\badrefs.txt'
!reportFile = object file(!repFilePath)

--ищем элементы имеющие битые ссылки


var !badBranchesH COLLECT ALL BRAN WITH ( BADREF ( HREF ) ) FOR CE
var !badBranchesT COLLECT ALL BRAN WITH ( BADREF ( TREF ) ) FOR CE

var !badMembers COLLECT ALL BRAN MEM WITH ( BADREF ( SPREF ) ) FOR CE

--формируем массивы для отчета


!output = object array()
if (!badBranchesH.Size() NEQ 0) then
do !x from 1 to !badBranchesH.Size()
!output.Append(!badBranchesH[!x].Dbref().Name + ' - Href')
enddo
endif
if (!badBranchesT.Size() NEQ 0) then
do !x from 1 to !badBranchesT.Size()
!output.Append(!badBranchesT[!x].Dbref().Name + ' - Tref')
enddo
endif
if (!badMembers.Size() NEQ 0) then
do !x from 1 to !badMembers.Size()
!output.Append(!badMembers[!x].Dbref().Name + ' - Sref')
enddo
endif

--открываем файл или открываем на экране


if (!output.Size() NEQ 0) then
!reportFile.Writefile('OVERWRITE',!output)

!getConfirm = !!Alert.Confirm('Найдены элементы с битыми/пустыми ссылками. Что делать?


YES - открыть файл отчета, NO - Открыть на экране')

--открыть файл
if (!getConfirm EQ 'YES') then
SYSCOM '$!repFilePath &'
endif
--открыть на экране
if (!getConfirm EQ 'NO') then
do !x from 1 to !output.Size()
ADD $!output[$!x]
ENHANCE $!output[$!x] COLOUR RED
enddo

---масштабировать
!draw = object drawlist()
!glbDraw = !draw.Globaldrawlist().Members()
if (!glbdraw.size() EQ 0) then
RETURN
endif
!RT = object array()
do !x from 1 to !glbDraw.Size()
!RT[!x] = !glbDraw[!x].String()
enddo

!BLOCK = OBJECT BLOCK('!RT[!EVALINDEX].DBREF()')


!LIST = !RT.EVALUATE(!BLOCK)
!VOLUME = OBJECT VOLUME(!LIST)

!LIM = OBJECT GPHVIEWS()


!LIM.LIMITS(!!GPH3DDESIGN1.VIEW, !VOLUME)

endif
endif

Автор: Сергей Лебедев


AVEVA

60.Пример сохранения текущего Drawlist в файл


Задача:
Необходимо сохранить текущий Drawlist в файл

--Запоминаем текущий Drawlist


!draw = object drawlist()
!glbDraw = !draw.Globaldrawlist().Members()

--если он пуст - сообщение и выход


if (!glbDraw.Size() EQ 0) then
$P ==========================
$P <СИСТЕМА ПОЛЬЗОВАТЕЛЮ>Внимание: Drawlist пустой... Выход из программы
$P ==========================
RETURN
endif

--подгружаем драйвер для диалогового окна указания файла


using namespace 'Aveva.Pdms.Presentation'
Import 'pmlfilebrowser'
handle any
endhandle
!browser = object PMLFILEBROWSER('SAVE')
!filePath = 'c:\temp\'
!browser.show(!filePath, '', 'Сохранение Drawlist в файл', false, 'Файлы txt (*.txt)|*.txt', 2)
!FileName = !browser.file()
!tempFile = object file(!FileName)

--проходим по массиву и запоминаем имя элемента


do !x from 1 to !glbDraw.Size()
!arrayOutput[!x] = !glbDraw[!x].Name
enddo
--выодим в файл
!tempFile.Writefile('OVERWRITE',!arrayOutput)

--сообщение
$P ==========================
$P <СИСТЕМА ПОЛЬЗОВАТЕЛЮ>Сообщение: Drawlist сохранен в $!FileName

Автор: Сергей Лебедев

Вам также может понравиться