Данный документ содержит примеры по работе с API системы БАЗИС для создания пользовательских скриптов. Описываемая версия API = 2.
Встроенный модуль - глобальный объект, содержащий какие-либо свойства и методы, предоставляющий функционал для скриптов системы Базис.
Подключаемый модуль - объект, содержащий какие-либо свойства и методы, предоставляющий дополнительный функционал и недоступный без подключения модуля. Подключение модуля с помощью функции require
"собирает" модуль и возвращает объект модуля как результат выполнения функции require
.
Система координат - матрица 4х4, описывающая положение и поворот какого либо обьекта. Также она задаёт положение локальной точки объекта (0, 0, 0) и направление его осей
ЛСК - локальная система координат объекта. Она описывает положение и поворот объекта относительно ЛСК объекта-владельца, в котором исходный объект находится.
Примечание: положение объекта - точка (0, 0, 0), переведённая из ЛСК объекта в ЛСК его объекта-владельца.
ГСК - глобальная система координат модели. Она описывает некоторую "точку отсчёта", относительно которой расположены объекты модели.
Материал объекта - листовой или погонный материал с базовым набором свойств, используемый в 3D объектах, либо его частях (например, облицовка пласти панели).
Материал кромки - кромочный материал, обладающий дополнительными свойствами. Он используется для облицовки кромок панелей.
Функционал скриптов может меняться со временем. Для обеспечения работоспособности скриптов, написанных с использованием устаревшего функционала, добавлен модуль apiVersion
, содержащий функции для получения/назначения версии API. Если задать новое значение версии API (меньше текущего, но не меньше 0
), автоматически подгрузятся скрипты, реализующие устаревший функционал.
// Пример создания формы с использованием устаревшей функции "CreateForm"
// Если закомментировать строку с назначением нового значения версии API,
// то скрипт вернёт ошибку при доступе к глобальному свойству "CreateForm",
// т.к. в функционале версий от 1 и выше такой функции нет.
console.log(`Текущее значение версии API скриптов = ${apiVersion.GetScriptApiVersion()}`);
console.log(`Назначение нового значения версии API = 0`);
apiVersion.SetScriptApiVersion(0);
console.log(`Текущее значение версии API скриптов = ${apiVersion.GetScriptApiVersion()}`);
console.log(`Настоящее значение версии API скриптов = ${apiVersion.GetRealScriptApiVersion()}`);
//-- UserForm1 #def_starts
let UserForm1 = CreateForm(FileControl.Owner);
UserForm1.Width = 328;
UserForm1.Height = 289;
UserForm1.Caption = 'Форма-пример';
UserForm1.Show();
//-- UserForm1 #def_ends
Встроенный модуль objects3d
содержит методы создания новых ообъектов.
// Пример создания панели размером 100х200 в разных пространственных положениях
// (фронтальное, вертикальное и горизонтальное)
const width = 100; // Ширина панели
const height = 200; // Высота панели
// Фронтальная - панель с единичной матрицей поворота, то есть, оси её ЛСК
// сонаправлены осям ГСК
let panel = objects3d.NewPanel(width, height, objects3d.PanelOrientation.front);
panel.Name = 'Фронтальная';
panel = objects3d.NewPanel(width, height, objects3d.PanelOrientation.vertical);
panel.Name = 'Вертикальная';
panel = objects3d.NewPanel(width, height, objects3d.PanelOrientation.horizont);
panel.Name = 'Горизонтальная';
// Пример создания панели и изменения её контура
const radius = 200; // Радиус будущей окружности контура
let panel = objects3d.NewPanel(0, 0, objects3d.PanelOrientation.front);
panel.Name = 'Фронтальная';
let contour = panel.Contour;
contour.Clear(); // Очищение контура
contour.AddCircle(0, 0, radius); // Создание окружности с центром в точке (0, 0) и заданным радиусом
// Пример создания профиля с прямоугольным сечением 100х200 и длиной 300
const width = 100; // Ширина профили
const height = 200; // Высота профиля
const length = 300; // Длина профиля
let extrusion = objects3d.NewExtrusionBody(width, height, length);
extrusion.Name = 'Профиль';
// Пример создания тела по траектории с прямоугольным сечением 100х200 и траекторией в виде окружности с радиусом 300
const width = 100; // Ширина сечения
const height = 200; // Высота сечения
const radius = 300; // Радиус окружности траектории
let trajectoryBody = objects3d.NewTrajectoryBody();
trajectoryBody.Name = 'Тело по траектории';
// Редактирование сечения
let contour = trajectoryBody.Contour2D;
contour.Clear();
contour.AddRectangle(0, 0, width, height);
// Редактирование траектории
let trajectory = trajectoryBody.Trajectory2D;
trajectory.Clear();
trajectory.AddCircle(0, 0, radius);
Основные типы структурных объектов создаются с помощью соответствующих функций встроенного модуля objects3d
.
NewBlock
NewDraftBlock
NewAssembly
// Пример создания основных структурных объектов - блока, полуфабриката, покупного изделия.
objects3d.NewBlock('Блок');
objects3d.NewDraftBlock('Полуфабрикат');
objects3d.NewAssembly('Покупное изделие');
По умолчанию, все объекты, создаваемые с помощью функций встроенного модуля objects3d
размещаются во временной области модели. Многие методы позволяют задать объект-владельца для создаваемых объектов, также каждый объект имеет свойство Owner
, хранящее ссылку на объект-владельца.
// Пример создания панели внутри нового блока.
// Вариант 1 - задать объект-владельца при создании объекта
let block1 = objects3d.NewBlock('Блок 1');
let panel1 = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.front, block1);
panel1.Name = 'Панель 1';
// Вариант 2 - задать объект-владельца после создания объекта
let panel2 = objects3d.NewPanel(200, 300, objects3d.PanelOrientation.front);
panel2.Name = 'Панель 2';
panel2.Owner = block1;
Общая ориентация объекта относительно ГСК определеяется всеми ЛСК объектов-владельцев. При изменении объекта-владельца может измениться ориентация объекта относительно ГСК. Чтобы этого не произошло, следует использовать функцию ReTransform
для изменения ЛСК панели.
// Пример изменения объекта-владельца панели
/** @param {TFurnPanel} panel */
function LogPanelCoordinates(panel) {
console.log(`Координаты минимальной точки панели относительно ГСК = ${JSON.stringify(panel.GabMin)}\n Координаты максимальной точки панели относительно ГСК = ${JSON.stringify(panel.GabMax)}`);
}
let block1 = objects3d.NewBlock('Блок 1');
let block2 = objects3d.NewBlock('Блок 2');
block2.PositionX = 1000;
let panel = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.front, block1);
panel.Build();
console.log('Панель создана в блоке "Блок 1"');
LogPanelCoordinates(panel);
panel.Owner = block2
console.log('Объект-владелец панели изменён на "Блок 2"');
LogPanelCoordinates(panel);
panel.ReTransform(block1, block2);
console.log('Лск панели преобразована из блока "Блок 1" в блок "Блок 2"');
LogPanelCoordinates(panel);
Встроенный модуль historyOperations
содержит методы для работы с историей модели.
При использовании функций встроенных модулей не требуется дополнительных действий для регистрации добавления/изменения/удаления объектов в истории - все эти действия выполняются внутри вызываемых функций. Однако, при прямом изменении свойств объекта или вызове его методов, влияющих на значения свойств, необходимо вручную зарегистрировать изменение объекта. Также может оказаться полезной возможность сохранить промежуточные изменения в отдельной операции истории, либо отменить все внесённые скриптом изменения.
// Пример создания панелей с записью создания каждой панели в отдельную
// операцию истории
let panel = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.front);
panel.Name = 'Фронтальная';
historyOperations.CommitCurrentChanges('Создание фронтальной панели');
panel = objects3d.NewPanel(200, 200, objects3d.PanelOrientation.vertical);
panel.Name = 'Вертикальная';
historyOperations.CommitCurrentChanges('Создание вертикальной панели');
// Пример отмены изменений в модели - отмена создания первой панели
// По завершении скрипта в модель будет добавлена только вертикальная панель
let panel = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.front);
panel.Name = 'Фронтальная';
historyOperations.RevertCurrentChanges();
panel = objects3d.NewPanel(1200, 200, objects3d.PanelOrientation.vertical);
panel.Name = 'Вертикальная';
Регистрация изменения выполняется до непосредственного изменения, так как во время вызова метода в историю сохраняется текущее состояние объекта.
// Пример регистрации изменения объекта - создание фронтальной панели в одной
// операции и изменение её контура в другой
let panel = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.front);
panel.Name = 'Фронтальная';
historyOperations.CommitCurrentChanges('Создание фронтальной панели');
// Регистрация изменения объекта производится до изменения объекта
historyOperations.RegisterObjectChanging(panel);
let contour = panel.Contour;
contour.Clear();
contour.AddCircle(0, 0, 100);
panel.Build();
historyOperations.CommitCurrentChanges('Изменение контура панели');
// Пример очистки истории
historyOperations.ClearHistory();
Встроенный модуль materialData
содержит методы для работы с материалами.
Встроенный модуль materialData
предоставляет несколько функций для изменения текущего активного материала:
SetupActiveMaterial
и SetupActiveButtMaterial
- для ручного назначения параметровChooseActiveFurnMaterial
и ChooseActiveButtMaterial
- для вызова окна выбора материала и назначения параметров из выбранного пользователем материала.//Пример изменения текущих активных материала объекта и материала кромки
materialData.SetupActiveMaterial('ДСП бук 16\r60', 16, 0);
materialData.SetupActiveButtMaterial('Кромка ПВХ Бук 0,4/19', 0.4, 0, true, 'Бук0,4/19', 0, true, 0);
let panel = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.front);
panelOperations.AddButt(panel, 0);
materialData.ChooseActiveFurnMaterial();
materialData.ChooseActiveButtMaterial();
panel = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.vertical);
panelOperations.AddButt(panel, 0);
Наименование и артикул материала хранятся в одной строке (полное имя материала), разделённые символом перевода каретки \r
.
Встроенный модуль materialData
содержит следующие методы для упрощения извлечения наименования и артикула и форматирования полного имени материала:
ExtractMaterialName
- функция извлечения наименования материала из полного имени материалаExtractMaterialCode
- функция извлечения артикула материала из полного имени материалаFormatMaterialName
- функция форматирования полного имени материала. Возвращает строку в формате "<Наименование материала> (Артикул <Артикул материала>)"// Пример извлечения частей и форматирования полного имени материала
const material = materialData.ChooseActiveFurnMaterial();
const name = materialData.ExtractMaterialName(material.name);
const code = materialData.ExtractMaterialCode(material.name);
const formatted = materialData.FormatMaterialName(material.name);
console.log(`Наименование: "${name}"\nАртикул: "${code}"\nФорматированное имя материала: "${formatted}"`)
Встроенный модуль geometry3d
предоставляет методы для совершения математических операций над векторами.
// Пример математических операций над векторами без привязки к СК
const stringify = JSON.stringify;
// Создание вектора с помощью функции
let axisX = geometry3d.VectorMake(1, 0, 0);
let axisY = geometry3d.VectorMake(0, 1, 0);
// Создание вектора с использованием константы
let axisZ = AxisZ;
console.log(`Сумма векторов X и Y = ${stringify(geometry3d.VectorAdd(axisX, axisY))}`);
console.log(`Разность векторов X и Y = ${stringify(geometry3d.VectorSub(axisX, axisY))}`);
console.log(`Вектор X умноженный на 3 = ${stringify(geometry3d.VectorMul(axisX, 3))}`);
console.log(`Коллинеарность (со-/противонаправленность) векторов X и Y = ${stringify(geometry3d.VectorsAreColinear(axisX, axisY))}`);
let zResult = geometry3d.VectorCross(axisX, axisY);
console.log(`Вектороное умножение векторов X и Y = ${stringify(zResult)}`);
console.log(`Оно равно оси Z? - ${geometry3d.VectorEqual(axisZ, zResult)}`);
console.log(`Скалярное умножение векторов X и Y = ${geometry3d.VectorDot(axisX, axisY)}`);
console.log(`Инвертированный вектор X = ${stringify(geometry3d.VectorInvert(axisX))}`);
let v = geometry3d.VectorMake(30, 40, 50);
console.log(`Исходный вектор = ${stringify(v)}`);
console.log(`Длина вектора = ${geometry3d.VectorLength(v)}`);
console.log(`Нормализованный вектор (сонаправленный вектор единичной длины) = ${stringify(geometry3d.VectorNormalize(v))}`);
Каждый 3D объект предоставляет методы для преобразования векторов из/в СК объекта:
NToGlobal
- Перевод вектора из ЛСК объекта в ГСКNToObject
- Перевод вектора из ГСК в ЛСК объектаNObjectToObject
- Перевод вектора из ЛСК другого объекта в ЛСК объекта, у которого вызывается методToGlobal
- Перевод точки из ЛСК объекта в ГСКToObject
- Перевод точки из ГСК в ЛСК объектаObjectToObject
- Перевод точки из ЛСК другого объекта в ЛСК объекта, у которого вызывается метод// Пример математических операций над векторами относительно СК объектов 1
function LogVector(v, prefix) {
console.log(`${prefix}: ${JSON.stringify(v)}`);
}
/**
* Вывод минимальной и максимальной точек объектов относительно ГСК и ЛСК друг друга
* @param {TObject3D[]} objList Список объектов
*/
function LogObjectsMinMax(objList) {
let zero = geometry3d.VectorMake(0, 0, 0);
for (let i = 0; i < objList.length; i++) {
let obj = objList[i];
let min = obj.GMin;
LogVector(obj.ToObject(zero), `Начало ГСК относительно СК объекта ${obj.Name}`);
LogVector(min, `Минимальная координата объекта ${obj.Name} относительно её СК`);
LogVector(panel1.ToGlobal(min), `Минимальная координата объекта ${obj.Name} относительно ГСК`)
for (let k = 0; k < objList.length; k++)
if (k != i) {
let obj2 = objList[k]
LogVector(obj2.ObjectToObject(obj, min), `Минимальная координата объекта ${obj.Name} относительно СК объекта ${obj2.Name}`);
}
let max = obj.GMax;
LogVector(max, `Максимальная координата объекта ${obj.Name} относительно её СК`);
LogVector(panel1.ToGlobal(max), `Максимальная координата объекта ${obj.Name} относительно ГСК`)
for (let k = 0; k < objList.length; k++)
if (k != i) {
let obj2 = objList[k]
LogVector(obj2.ObjectToObject(obj, max), `Максимальная координата объекта ${obj.Name} относительно СК объекта ${obj2.Name}`);
}
}
}
let block1 = objects3d.NewBlock('Блок 1');
block1.PositionX = 200;
let panel1 = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.front, block1);
panel1.Name = 'Панель 1';
panel1.PositionX = 500;
panel1.Build();
let block2 = objects3d.NewBlock('Блок 2');
block2.PositionY = 300;
let panel2 = objects3d.NewPanel(50, 50, objects3d.PanelOrientation.front, block2);
panel2.Name = 'Панель 2';
panel2.PositionY = 600;
panel2.Build();
LogObjectsMinMax([panel1, panel2, block1, block2]);
// Пример математических операций над векторами относительно СК объектов 2
function LogVector(v, prefix) {
console.log(`${prefix}: ${JSON.stringify(v)}`);
}
/**
* Вывод направления осей XYZ объектов относительно ГСК и ЛСК друг друга
* @param {TObject3D[]} objList Список объектов
*/
function LogObjectsAxes(objList) {
for (let i = 0; i < objList.length; i++) {
let obj = objList[i];
LogVector(obj.NToObject(AxisX), `Ось Х ГСК относительно СК объекта ${obj.Name}`);
LogVector(obj.NToObject(AxisY), `Ось Y ГСК относительно СК объекта ${obj.Name}`);
LogVector(obj.NToObject(AxisZ), `Ось Z ГСК относительно СК объекта ${obj.Name}`);
LogVector(obj.NToGlobal(AxisX), `Ось Х СК объекта ${obj.Name} относительно ГСК`);
LogVector(obj.NToGlobal(AxisY), `Ось Y СК объекта ${obj.Name} относительно ГСК`);
LogVector(obj.NToGlobal(AxisZ), `Ось Z СК объекта ${obj.Name} относительно ГСК`);
for (let k = 0; k < objList.length; k++)
if (k != i) {
let obj2 = objList[k]
LogVector(obj2.ObjectToObject(obj, AxisX), `Ось X объекта ${obj.Name} относительно СК объекта ${obj2.Name}`);
LogVector(obj2.ObjectToObject(obj, AxisY), `Ось Y объекта ${obj.Name} относительно СК объекта ${obj2.Name}`);
LogVector(obj2.ObjectToObject(obj, AxisZ), `Ось Z объекта ${obj.Name} относительно СК объекта ${obj2.Name}`);
}
}
}
let front = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.front);
front.Name = "Фронтальная"
let vertical = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.vertical);
vertical.Name = "Вертикальная"
let horizont = objects3d.NewPanel(100, 100, objects3d.PanelOrientation.horizont);
horizont.Name = "Горизонтальная"
LogObjectsAxes([front, vertical, horizont]);
Встроенный модуль objectData
предоставляет функции для работы с данными объекта (пользовательскими свойствами, дополнительными материалами и т.д.)
// Пример получения списка пользовательских свойств выделенного объекта
// Проверка версии скрипта и выброс ошибки, если версия < 3
apiVersion.AwareAndThrowIfApiVersionIsLowestThan(3);
let obj = currentFileData.model.SelectedObj;
if (obj) {
const properties = objectData.GetObjectUserProperties(obj);
let output = '';
// Добавление пользовательских свойств в строку вывода в виде
// <Имя>: <Значение>
properties.forEach((value, key) => {
output += `"${value}": "${key}"\r\n`;
})
UI.dialogs.MessageBox(output);
}
// Пример получения списка дополнительных материалов выделенного объекта
// Проверка версии скрипта и выброс ошибки, если версия < 3
apiVersion.AwareAndThrowIfApiVersionIsLowestThan(3);
let obj = currentFileData.model.SelectedObj;
if (obj) {
const properties = objectData.GetObjectAdditionalMaterials(obj);
if (properties.length > 0) {
let output = '';
// Добавление дополнительных материалов в строку вывода в виде
// <Наименование> <Артикул> <Количество> <Единицы измерения>
properties.forEach(mt => {
output += `"${mt.name}" "${mt.art}" ${mt.count} "${mt.measure}"\r\n`
});
UI.dialogs.MessageBox(output);
}
else
UI.dialogs.MessageBox('У выделенного объекта нет дополнительных материалов')
}
// Пример получения заметок выделенного объекта
// Проверка версии скрипта и выброс ошибки, если версия < 3
apiVersion.AwareAndThrowIfApiVersionIsLowestThan(3);
let obj = currentFileData.model.SelectedObj;
if (obj) {
const notes = objectData.GetObjectNotes(obj);
if (notes)
UI.dialogs.MessageBox('Заметки:\r\n' + notes);
else
UI.dialogs.MessageBox('Объект не содержит заметок');
}
Встроенный модуль modelIOOperations
предоставляет функции для сохранения/загрузки модели в разные форматы.
Важно: при загрузке новой модели, старая модель уничтожается. Все переменные, указывающие на объекты старой модели, будут указывать на некорректные объекты. Следует отказаться от использования таких переменных, либо задать им новое значение во избежание возникновения ошибок.
// Пример добавления панели и сохранения изменённой модели в файл, а также
// загрузки модели
objects3d.NewPanel(100, 100);
historyOperations.CommitCurrentChanges('тест 1');
modelIOOperations.SaveModelToFile('тест 1.b3d');
objects3d.NewPanel(200, 200);
historyOperations.CommitCurrentChanges('тест 2');
modelIOOperations.SaveModelToFile('тест 2.b3d');
modelIOOperations.LoadModelFromFile('тест 1.b3d');
// Пример экспорта панели в файл полигонального формата и импорта
// экспортированной панели обратно в модель.
const fileName = 'Панель.obj';
let panel = objects3d.NewPanel(1000, 1000);
panel.Name = 'Исходная панель';
panel.Build();
modelIOOperations.ExportModelMeshFormat(panel, fileName);
let importedObjects = modelIOOperations.ImportModelMeshFormat(fileName);
importedObjects.PositionX += 1500;
importedObjects.Objects[0].Name = 'Импортированная панель'
Встроенный модуль currentFileData
предоставляет свойства, возвращающие актуальные (на момент доступа к свойству) значения.
Примечание: в большинстве случаев достаточно лишь одного обращения к свойствам встроенного модуля currentFileData
. В случае загрузки/создания новой модели следует произвести повторное обращение к используемым свойствам модуля для получения новых данных.
// Пример получения актуальных данных модели и опериования ими
/**
* Получить количество вложенных объектов (рекурсивно)
* @param {T3DObjectList} objList
*/
function GetInternalObjectCountRecursive(objList) {
let result = objList.Count;
for (let i = 0; i < objList.Count; i++) {
let obj = objList.Objects[i];
if (obj.List)
result += GetInternalObjectCountRecursive(obj);
}
return result;
}
let model = currentFileData.model;
console.log(`Количество объектов верхнего уровня в модели: ${model.Count}`);
console.log(`Общее количество объектов в модели: ${GetInternalObjectCountRecursive(model)}`);
let article = currentFileData.article;
console.log('Параметры изделия:');
console.log(`Наименование: ${article.Name}\nАртикул: ${article.Code}`);
console.log(`Имя текущего редактруемого файла: ${currentFileData.filename}`);
Встроенный модуль arrangePositions
предоставляет свойства и функции, необходимые для расстановки позиций и обозначений на объекты.
let arranger = arrangePositions.NewArranger();
arranger.parameters.arrangeMode = arrangePositions.ArrangeMode.allObjects;
arranger.parameters.designationPrefix = currentFileData.article.ShortSign;
arranger.parameters.list = currentFileData.model;
arranger.parameters.options.LoadFromSettings();
arranger.parameters.selectedOnly = false;
if (arranger.ArrangeObjects()) {
UI.dialogs.MessageBox('Расстановка позиций выполнена успешно');
historyOperations.CommitCurrentChanges('Выполнение расстановки позиций в скрипте')
}
// Пример сохранения параметров расстановки позиций в файл в формате JSON
// Необходимая версия API >=2
let options = arrangePositions.NewArranger().parameters.options;
options.SaveToJSON('arrangeOptions.json');
// Пример загрузки параметров расстановки из файла в формате JSON и
// выполнения расстановки позиций с загруженными параметрами.
// Необходимая версия API >=2
let arranger = arrangePositions.NewArranger();
arranger.parameters.options.LoadFromJSON('arrangeOptions.json');
arranger.parameters.arrangeMode = arrangePositions.ArrangeMode.allObjects;
arranger.parameters.designationPrefix = currentFileData.article.ShortSign;
arranger.parameters.list = currentFileData.model;
arranger.parameters.selectedOnly = false;
arranger.ArrangeObjects();
historyOperations.CommitCurrentChanges(
'Выполнение расстановки позиций в скрипте по загруженным параметрам'
);
Понятия "вертикальная", "горизонтальная", "фронтальная" для ориентации панели являются абстрактными. Они используются для определения поворота панели относительно ГСК при её создании. Для самостоятельного определения ориентации панели необходимо:
// Пример определения ориентации панели относительно другой СК.
// В этом примере будут созданы два блока, каждый с панелью внутри, имитирующей
// фасад модуля.
// Один из блоков будет повёрнут так, что фасад относительно ГСК станет
// "вертикальной" панелью.
//
// Ориентация панели определяется с помощью перевода вектора, направленного
// вдоль оси Z, из ЛСК панели в необходимую СК. Полученный вектор определяет,
// куда "смотрит" лицевая пласть панели относительно использованной СК
const { NewBlock, NewPanel, PanelOrientation } = objects3d;
const { VectorsAreColinear } = geometry3d;
let centerBlock = NewBlock('Центральный блок');
let leftBlock = NewBlock('Левый блок');
objectTransformation.RotateObject(leftBlock, AxisY, 90, true);;
let centerPanel = NewPanel(100, 100, PanelOrientation.front, centerBlock);
centerPanel.Name = 'Фасад центральный';
let leftPanel = NewPanel(200, 200, PanelOrientation.front, leftBlock);
leftPanel.Name = 'Фасад левый';
leftBlock.Build();
centerBlock.Build();
leftPanel.TranslateLCS(geometry3d.VectorMake(-leftPanel.GSize.x - centerPanel.Thickness, 0, - leftPanel.Thickness));
// Ориентация панели относительно ГСК
LogPanelOrientationDependOnCS(centerPanel);
// Ориентация панели относительно объекта-владельца
LogPanelOrientationDependOnCS(centerPanel, centerBlock);
// Ориентация панели относительно ГСК
LogPanelOrientationDependOnCS(leftPanel);
// Ориентация панели относительно объекта-владельца
LogPanelOrientationDependOnCS(leftPanel, leftBlock);
/**
* Записать в лог ориентацию панели относительно заданной СК.
* Если объект, задающий СК не указан, ориентация считается относительно ГСК
* @param {TFurnPanel} panel Панель.
* @param {TObject3D} [CSOwner] Объект, задающий СК
*/
function LogPanelOrientationDependOnCS(panel, CSOwner) {
let dir, dependString;
if (CSOwner) {
dir = CSOwner.NObjectToObject(panel, AxisZ);
dependString = `СК объекта "${CSOwner.Name}"`;
}
else {
dir = panel.NToGlobal(AxisZ);
dependString = 'ГСК';
}
let orientationString;
if (VectorsAreColinear(dir, AxisX))
orientationString = 'Вертикальная';
else if (VectorsAreColinear(dir, AxisY))
orientationString = 'Горизонтальная';
else if (VectorsAreColinear(dir, AxisZ))
orientationString = 'Фронтальная';
else
orientationString = 'Не ортогональная';
console.log(`Ориентация объекта "${panel.Name}" относительно ${dependString} : "${orientationString}"`);
}
//Пример добавления облицовки пласти разными материалами с обеих сторон панели.
let panel = objects3d.NewPanel(100, 100);
panel.Name = 'Панель с облицовкой пласти (скрипт)';
let material = materialData.CreateMaterialData('"Передний" пластик', 0.5);
panelOperations.AddPlastic(panel, true, material);
material = materialData.CreateMaterialData('"Задний" пластик', 1);
panelOperations.AddPlastic(panel, false, material);
//Пример добавления облицовки кромки на каждый элемент контура панели.
let panel = objects3d.NewPanel(100, 100);
panel.Name = 'Панель с облицовкой кромки (скрипт)';
for (let i = 0; i < panel.Contour.Count; i++) {
panelOperations.AddButt(panel, i);
}
//Пример добавления пазов (четверть и выемка) на панель.
let panel = objects3d.NewPanel(200, 200);
panel.Name = 'Панель с пазами (скрипт)';
// СК контура паза типа "выемка" эквивалентна СК контура панели
// Знак толщины выемки определяет сторону панели:
// При значении толщины больше нуля, выемка строится по направлени +Z от минимальной глубины панели
// При значении толщины меньше нуля, выемка строится по направлени -Z от максимальной глубины панели
let pocket = panelOperations.AddCut(panel, panelOperations.cutType.extrusion, 'Выемка', 'Выемка 10');
pocket.Contour.AddRectangle(50, 50, 150, 150);
pocket.Thickness = -10;
// СК траектории паза типа "по произвольной траектории" эквивалентна СК контура панели.
// СК контура сечения паза вычисляется относительно ЛСК панели и направления траектории в её начале:
// 1. Направлении оси Z сонаправлено с направлением траекториии в её начальной точке.
// 2. Направление оси Y всегда сонаправлено с направлением оси Z СК траектории (и ЛСК панели).
// 3. Направление оси X вычисляется векторным произведением найденных направлений осей Y и Z
let quarter1 = panelOperations.AddCut(panel, panelOperations.cutType.freeForm, 'Четверть', '5x5');
// В этом примере траектория паза идёт по направлению -X.
// Соответственно, остальные оси СК контура сечения паза:
// Ось Y идёт по направлению +Z панели (всегда)
// Ось Х вычисляется по описанию выше: (+Z) * (-X) = (-Y)
// Таким образом в СК сечения паза тело панели находится в прямоугольнике с углами (0, 0) и (-200, 200);
quarter1.Trajectory.AddLine(200, 0, 0, 0);
quarter1.Contour.AddRectangle(0, 0, -5, 5);
const contourY = AxisZ;
let ref = new ReferenceObject();
// Получение двумерного вектора направления первого элемента траектории в его начальной точке
quarter1.Trajectory.Objects[0].TangentOn(0, ref);
let contourZ = ref.value;
// Добавление двумерному вектору значения по оси Z во избежание ошибок в трёмерных вычислениях
contourZ.z = 0;
const contourX = geometry3d.VectorCross(contourY, contourZ);
console.log(`Направление оси X контура сечения паза относительно ЛСК панели: ${JSON.stringify(contourX)}`);
console.log(`Направление оси Y контура сечения паза относительно ЛСК панели: ${JSON.stringify(contourY)}`);
console.log(`Направление оси Z контура сечения паза относительно ЛСК панели: ${JSON.stringify(contourZ)}`);
// Пример определения отверстий, которые сверлятся в выделенную панель.
/**Объект, использующийся для сверления отверстий в объектах */
const holeDrilling = fastenerOperations.NewHoleDrilling();
/**
* Вывести сообщения об отверстиях, сверлящихся в тело
* Каждое сообщение содержит наименование фурнитуры и
* параметры сверлящегося отверстия фурнитуры
* @param {TBodyDrillInfo} info Информация о сверлении тела
*/
function OutputDrilledHoles(info) {
for (let i = 0; i < info.Holes.Count; i++) {
currentFileData.model.UnPickAll();
const hole = info.Holes.Items[i];
const fastener = hole.Fastener;
fastener.Selected = true;
UI.dialogs.MessageBox(`Фурнитура: "${materialData.FormatMaterialName(fastener.Name)}"\r\nОтверстие:${hole.Diameter.toFixed(3)}x${hole.Depth.toFixed(3)}`);
}
}
/**
* Вывести сообщения о фурнитуре, сверлящейся в тело
* Каждое сообщение содержит наименование фурнитуры и
* набор параметров сверлящихся отверстий, принадлежащих фурнитуре
* @param {TBodyDrillInfo} info Информация о сверлении тела
*/
function OutputDrilledHoles_GroupByFastener(info) {
/** Коллекция "фурнитура - список отверстий" @type {Map<TFastener, TDrilledHole[]>} */
const fastenerMap = new Map();
for (let i = 0; i < info.Holes.Count; i++) {
const hole = info.Holes.Items[i];
const fastener = hole.Fastener;
const holes = fastenerMap.get(fastener);
if (holes)
fastenerMap.set(fastener, holes.concat([hole]));
else
fastenerMap.set(fastener, [hole]);
}
// Вывод сообщений
fastenerMap.forEach((holes, fastener) => {
currentFileData.model.UnPickAll();
fastener.Selected = true;
const holeData = [];
holes.forEach(hole => holeData.push(` ${hole.Diameter.toFixed(3)}x${hole.Depth.toFixed(3)}`))
UI.dialogs.MessageBox(`Фурнитура: "${materialData.FormatMaterialName(fastener.Name)}"\r\nОтверстия:\r\n${holeData.join('\r\n')}`);
})
}
const selectedObject = currentFileData.model.Selected;
if (selectedObject) {
currentFileData.model.UnPickAll();
// Добавление панели, как тела, для которого будет рассчитываться сверление
holeDrilling.AddBody(selectedObject);
// Добавление всей фурнитуры из модели, т.к. заранее не известно,
// какая фурнитура сверлится в выделенную панель
holeDrilling.AddFasteners(currentFileData.model);
// Выполнение расчёта сверления отверстий
holeDrilling.DrillHoles();
const info = holeDrilling.Bodies.FindBodyInfo(selectedObject);
// Вывод сообщения для каждого сверлящегося отверстия
// OutputDrilledHoles(info);
// Вывод сообщения для каждой сверлящейся фурнитуры
// (в одном сообщение могут быть параметры нескольких отверстий)
OutputDrilledHoles_GroupByFastener(info);
// Возвращение выделения панели
currentFileData.model.UnPickAll();
selectedObject.Selected = true;
}
else
UI.dialogs.ErrorBox('Не выделен объект!')
// Пример выбора и установки фурнитуры.
/**
* Установка обычной фурнитуры
* @param {TFurnitureInfo} info
*/
function MountFastener(info) {
/**@type {MountParams} */
const params = {};
params.panel1 = interaction.getRequest.GetObject('Укажите панель 1', objectTypeChecker.ObjectTypeValue.panel);
params.panel2 = interaction.getRequest.GetObject('Укажите панель 2', objectTypeChecker.ObjectTypeValue.panel);
params.position = interaction.getRequest.GetVector('Укажите положение фурнитуры');
fastenerOperations.MountFurniture(info, params);
}
/**
* Установка схемы крепежа
* @param {TFurnitureInfo} info
*/
function MountScheme(info) {
/**@type {MountParams} */
const params = {};
params.panel1 = interaction.getRequest.GetObject('Укажите панель 1', objectTypeChecker.ObjectTypeValue.panel);
params.panel2 = interaction.getRequest.GetObject('Укажите панель 2', objectTypeChecker.ObjectTypeValue.panel);
params.basePlane = fastenerOperations.basePlaneMount.inside;
fastenerOperations.MountFurniture(info, params);
}
/**
* Установка секции
* @param {TFurnitureInfo} info
*/
function MountBox(info) {
/**@type {MountParams} */
const params = {};
const limits = objects3d.NewLimits();
const position = interaction.getRequest.GetVector('Укажите положение секции');
limits.Position = position;
interaction.windowData.SetPointAnchoring(true);
// Установка обработчика движения мыши для изменения размеров габаритной рамки,
// описывающей будущий размер секции.
interaction.events.SetMouseMoveHandler(() => {
let newPoint = interaction.windowData.GetPoint3D();
limits.LimitSize = geometry3d.VectorSub(newPoint, position);
limits.Build()
})
const secondPos = interaction.getRequest.GetVector('Укажите положение противоположного угла секции');
// Сброс обработчика движения мыши
interaction.events.SetMouseMoveHandler(undefined);
const size = geometry3d.VectorSub(secondPos, position);
// Проверка всех координат во избежание некорректной установки.
// Размер по каждой оси должен иметь положительное значение.
['x', 'y', 'z'].forEach(key => {
if (size[key] < 0) {
size[key] = Math.abs(size[key]);
position[key] -= size[key];
}
});
params.boxSize = size;
objects3d.DeleteObject(limits);
const box = fastenerOperations.MountFurniture(info, params);
box.Position = position;
}
const furnInfo = fastenerOperations.CreateFurnitureInfo();
if (fastenerOperations.ChooseFurnitureInfo(furnInfo,
fastenerOperations.PARAM_FASTENER_FILTER_ALL, fastenerOperations.DATUM_MODE_FILTER_ALL)) {
const datumMode = furnInfo.FindDatumMode();
switch (datumMode) {
case fastenerOperations.datumMode.faceButt:
case fastenerOperations.datumMode.faceEdge:
case fastenerOperations.datumMode.faceFace:
case fastenerOperations.datumMode.parallelFaces:
MountFastener(furnInfo);
break;
case fastenerOperations.datumMode.joint:
MountScheme(furnInfo);
break;
case fastenerOperations.datumMode.box:
MountBox(furnInfo);
break;
}
}
// Пример вызова функций для запроса элементов из окна модели и обработки полученного результата
let vector = interaction.getRequest.GetVector('Укажите точку');
console.log(`Указана точка с координатами ${JSON.stringify(vector)}`);
let object = interaction.getRequest.GetObject('Укажите объект');
console.log(`Указан объект с именем "${object.Name}"`);
let panel = interaction.getRequest.GetObject('Укажите панель', objectTypeChecker.ObjectTypeValue.panel);
console.log(`Указана панель с именем "${panel.Name}"`);
// Пример скрипта, использующего функционал диалоговых окон
// В этом скрипте:
// 1. Запрашивается файл у пользователя
// 2. Выводится содержимое выбранного файла и запрашивается подтверждение
// сохранения содержимого в файл под другим именем
// 3. В случае подверждения сохраняется содержимое в выбранный файл и выводится
// сообщение о сохранении файла
const fs = require('fs');
const path = require('path');
/**@type {DialogParams} */
let dialogParams = {
extensions: ['txt'],
initialDir: '',
title: 'Выберите файл для отображения его содержимого'
}
const button = UI.dialogs.DialogMessageButton;
let filename = UI.dialogs.RunOpenFileDialog(dialogParams);
if (filename) {
let content = fs.readFileSync(filename, 'utf8');
if (UI.dialogs.RunMessageDialog(
`Содержимое файла:\n${content}\nСохранить его под другим именем?`,
UI.dialogs.DialogMessageType.confirmation,
new Set([button.yes, button.no])) == UI.dialogs.DialogMessageResult.yes) {
dialogParams.initialDir = path.dirname(filename);
filename = UI.dialogs.RunSaveFileDialog(dialogParams);
if (filename) {
fs.writeFileSync(filename, content);
UI.dialogs.MessageBox(`Файл ${filename} сохранён!`);
}
else
UI.dialogs.ErrorBox('Файл не был выбран');
}
}
else
UI.dialogs.ErrorBox('Файл не был выбран');
// Пример обработки событий в окне модели.
// В этом примере задаются обработчики событий нажатия клавиши мыши и нажатия кнопок.
// При нажатии кнопки мыши работает следующий алгоритм:
// 1. Продолжаем, если нажата левая клавиша мыши
// 2. Если в списке клавиш-модификаторов нет клавиши "Shift", снимаем выделение
// со всех объектов.
// 3. Получаем данные модели относительно положения мыши.
// 4. Если под курсором мыши есть объект, инвертируем его выделение
//
// При нажатии клавиши клавиатуры работает следующий алгоритм:
// 1. Продолжаем, если нажата кнопка "Escape",
// 2. Запрашиваем подтверждение отмены скрипта у пользователя.
// 3. Если пользователь не подтвердил отмену скрипта, выставляем значение
// кнопки равное нулю. Это предотвратит дальнейшую обработку нажатия
// клавиши "Escape" после завершения назначенного обработчика
execution.ContinueExecution();
const shiftState = UI.constants.shiftState;
let clickPos;
interaction.events.SetMouseDownHandler((sender, button, shift, x, y) => {
if (button == UI.constants.mouseButton.left) {
if (!shift.has(shiftState.shift)) {
currentFileData.model.UnSelectAll();
}
let pointInfo = interaction.windowData.GetPointInfo(x, y);
if (pointInfo && pointInfo.obj)
pointInfo.obj.Selected = !pointInfo.obj.Selected;
}
})
interaction.events.SetKeyDownHandler((sender, key, shift) => {
if (key.value == UI.constants.keys.escape) {
if (!UI.dialogs.RunYesNoDialog('Отменить выполнение скрипта?'))
key.value = 0;
}
})