Скачайте здесь и сохраните на своем компьютере файл программы.

При помощи кнопки 1 на панели LABPP_Calc для Revit откройте диалог выбора файла на компьютере.
Найдите текстовый файл с расширением cpp, в котором записана программа и нажмите "Ок".

На экране появится диалог 2.

В поле 3 введите плотность.

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

Нажмите "Расчет" (5).

Программа выберет в проекте элементы, у которых имеется материал, содержащий слово "Бетон".

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

Суммарный объем запишется в поле A, а суммарная масса - в поле, которое вы выбрали в пункте 4.


Вот полный текст этого программного файла.


//*********************************************************************************
// LABPP Calc weight by density and volume with dialog and insert to calulator.cpp
// LABPP C++ for Revit
// Jurii@Tsepov.com
//*********************************************************************************

// Дескрипторы объектов - это целые числа, которые присваиваются каждому создаваемому объекту
int iDialog;
int iButton_Calculate;
int iTextEdit;
int iLabel1, iLabel2;
int iPopUp;

int main()
{
       object("create", "ts_dialog", iDialog); // Создать объект ts_dialog и получить его дескриптор в переменную iDialog
       ts_dialog(iDialog, "init_dialog", "palette", 0, 0, 200, 400); // инициализировать ts_dialog как немодальный (плавающий) диалог Revit
       ts_dialog(iDialog, "settitle", "Мой диалог LABPP в Revit"); // задать заголовок окна
       ts_dialog(iDialog, "SetClientWH", 300, 150); // задать размеры окна 
       ts_dialog(iDialog, "set_as_main_panel"); // установить этот диалог как главный - когда он закроется, все остальные окна тоже закроются

       object("create", "ts_dialogcontrol", iLabel1); // Создать элемент текст на панели диалога
       ts_dialogcontrol(iLabel1, "init_control", "LeftText", iDialog, 10, 10, 170, 24); // инициализация как текст, выравненный по левой стороне
       ts_dialogcontrol(iLabel1, "SetText", "Расчетная плотность"); // задать текст

       object("create", "ts_dialogcontrol", iTextEdit); // Создать поле для ввода текста
       ts_dialogcontrol(iTextEdit, "init_control", "TextEdit", iDialog, 190, 10, 80, 24); // инициализация как текстового редактора, положение x,y и ширина и высота
       ts_dialogcontrol(iTextEdit, "settooltip", "Плотность материала"); // задать всплывающий текст (при наведении мыши)
       ts_dialogcontrol(iTextEdit, "SetText", "2,2"); // предустановить текст

       object("create", "ts_dialogcontrol", iLabel2); // Создать текст 2
       ts_dialogcontrol(iLabel2, "init_control", "LeftText", iDialog, 10, 35, 170, 24);
       ts_dialogcontrol(iLabel2, "SetText", "Результат записать в поле");

       object("create", "ts_dialogcontrol", iPopUp); // Создать popup элемент диалога (ниспадающий список)
       ts_dialogcontrol(iPopUp, "init_control", "PopUp", iDialog, 190, 35, 80, 25); // инициализировать как popup, задать положение x,y и ширину и высоту
       ts_dialogcontrol(iPopUp, "AppendItem"); // добавить пустой пункт
       ts_dialogcontrol(iPopUp, "SetItemText", 1,"B"); // задать текст для пункта 1
       ts_dialogcontrol(iPopUp, "AppendItem");
       ts_dialogcontrol(iPopUp, "SetItemText", 2, "C");
       ts_dialogcontrol(iPopUp, "AppendItem");
       ts_dialogcontrol(iPopUp, "SetItemText", 3, "D");
       ts_dialogcontrol(iPopUp, "SelectItem", 1); // сделать выбранным первый элемент ("B")

       object("create", "ts_dialogcontrol", iButton_Calculate, "iButton_Calculate"); // Создать кнопку
       ts_dialogcontrol(iButton_Calculate, "init_control", "button", iDialog, 190, 75, 80, 24); // инициализировать кнопку, задать положение  x,y и ширину и высоту
       ts_dialogcontrol(iButton_Calculate, "eventreaction", "Event_ButtonClicked", "Event_ButtonClicked_DCName"); // задать обработчик событий (тип "Event_ButtonClicked" и имя функции "Event_ButtonClicked_DCName")
       ts_dialogcontrol(iButton_Calculate, "settext", "Расчет"); // задать надпись на кнопке
       
       bool bres;
       ts_dialog(iDialog, "invoke", bres); // запустить диалог
}

// Обработчик события нажатия (Event Handler) для кнопки
// когда кнопка нажата, эта функция выполняется
// здесь iDescr - это дескриптор нажатой кнопки (iButtonCalculate в этом примере)
// и sDescr - текстовое имя элемента ("iButtonCalculate" в этом примере);
int Event_ButtonClicked_DCName(int iDescr, string sDescr)
{
       // в конструкциях if скобки { и } обязательны
       if (sDescr == "iButton_Calculate") 
       { 
               Do_iButton_Calculate(); 
       }
}

// функция, которая выполняется когда нажата кнопка iButton_Calculate
int Do_iButton_Calculate()
{
       string s;
       ts_dialogcontrol(iTextEdit, "gettext", s); // Получить текст из iTextEdit - плотность как текст, содержащий число с плавающей точкой
       strreplaceall(s, ",", ".");                // Если пользователь ввел "," мы заменяем его на "."
       double density = atof(s); // конвертируем текст в число с плавающей точкой

       // загрузить элементы из проекта Revit во внутренний список № 1 с фильтром:
       // любые элементы ("OST_Zombie"), MainFilter = 0,
       // параметр с генезисом "EP" (вкладка Common параметров на панели LABPP BIM Master) "ZFromProject0" должен быть >= 0 И
       // параметр с генезисом "UPt" (уровень типа элемента TypeProps на панели LABPP BIM Master) "Имя типа" должен содержать "бетон"
       // "_CONTAINS" - если есть знак подчеркивания, то при сравнении не учитывается регистр текста (все равно если "бетон", "Бетон" или "БЕТОН")
       rvt_request("load_elements_list", 1, "OST_Zombie", "MainFilter", 0,
               "(","EP","ZFromProject0",">=",0,")", "AND",
               "(","UPt", "Имя типа", "_CONTAINS", "бетон",")"
       );

       rvt_request("get_loaded_elements_list_count", 1); // запрос сколько элементов загружено в список 1
       int icount = rvt_getnumvalue(); // поместить результат запроса в переменную icount
       // объявить и присвоить первичные значения требуемым переменным
       string selement_name = "";
       double dvolume = 0;
       double dvolumeall = 0;
       double dmassa = 0; 
       double dmassaall = 0;
       int i;
       // напечатать в окре сообщений программ
       // ---------------
       // Элементы 10 шт
       //----------------
       cout << "\r\n---------------" << "\r\nЭлементы " << itoa(icount) << "шт\r\n---------------";
       // Расчетный цикл
       for (i = 0; i < icount; i++)
       {
               rvt_request("set_current_element_from_list", 1, i); // установить элемент i из списка № 1 как текущий для работы с ним
               rvt_request("get_element_value", "EP", "element_name"); // запросить имя элемента (параметр с генезисом "EP" - Common в LABPP BIM Master
               selement_name = rvt_getstrvalue(); // поместить результат запроса в переменную selement_name
               rvt_request("get_element_value", "UP", "Объем"); // запросить значение параметра UP/Объем (генезис "UP" - значит переменная уровня экземпляра элемента, вкладка ElemProps в LABPP_BIM_Master.
               dvolume = tsround(rvt_getnumvalue(),4); // получить результат запроса и округлить до 4-х знаков после запятой
               dmassa = dvolume * density; // расчитать массу умножением объема на плотность
               dmassaall += dmassa; // суммировать массу
               // напечатать строку отчета
               cout << "\r\n" << itoa(i+1) << "). "<< selement_name << ": объем= " << dvolume << " масса при плотности " << s << "=" << dmassa;
               dvolumeall += dvolume; // суммировать объем
       }
       // печатать итоговую строку
       cout << "\r\n" << "Суммарный объем элементов= " << dvolumeall << " суммарная масса при плотности " << s << "=" << dmassaall;
       // поместить в поле "A" LABPP_Calc суммарное значение объема и комментарий
       rvt_request("calc_field", "set", "a", 0, ftoa(tsround(dvolumeall,4)), "Объем элементов");

       string fieldletter2;
       ts_dialogcontrol(iPopUp, "GetText", fieldletter2); // получить из элемента popup имя поля, куда записать массу ("B", "C" or "D")
       rvt_request("calc_field", "set", fieldletter2, 0, ftoa(tsround(dmassaall,4)), "Масса при плотности "+s); // поместить в поле LABPP_Calc итоговую массу и комментарий
}



На самом деле LABPP C++ для Revit скрывает и делает за вас множество технологических операций.

Поэтому вам остается только понять его простые конструкции и использовать в своих целях. 

Разберем по порядку текст программы.


В начале программы идет объявление переменных.

Если они объявляются вне функций, то они будут доступны в любой функции и подпрограмме.


В программе обязательно должна быть функция 


int main() 
{
}


Ее тело выполняется в первую очередь.

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

Функции и процедуры пишутся после так же как main, например функция, которая на входе получает строку в переменной s, строку в переменной sres и целое число в переменной i, а возвращает число и... строку в переменную sres:


int my_function(string s, string & sres, int i)
{
     sres = s + itoa(i);
     return 11;
}


В так выглядит программа с этой функцией. 


int main()
{
       int a, res;
       string strres;
       a = 1;
       strres = "строка";
       res = my_function("строка", strres, a); // в res запишется 11, а strres будет "строка 1"
}


int my_function(string s, string & sres, int i)
{
     sres = s + " " + itoa(i);
     return 11;
}


Символ "&" означает, что sres в подпрограмме - это ссылка на входящую переменную указанную в аргументе и изменение sres будет отражаться на содержимом аргумента, т.е. strres.


Мы объявили переменную iDialog (могли бы назвать иначе или объявить несколько для разных объектов диалогов).

int iDialog;
...

int main()

{

Создаем объект диалога и получаем его дескриптор в эту переменную iDialog.

       object("create", "ts_dialog", iDialog); // Создать объект ts_dialog и получить его дескриптор в переменную iDialog

       ...

При обращении к функции ts_dialog мы указываем дескриптор нужного диалога, который, хранится в переменной iDialog, поэтому программа понимает 

у какого диалога мы хотим задать заголовок.

       ts_dialog(iDialog, "settitle", "Мой диалог LABPP в Revit"); // задать заголовок окна

       ...
}


Итак, в самом начале мы объявляем переменные для хранения так называемых дескрипторов объектов.

Окно диалога, текст в окне диалога, поле для ввода текста и кнопки - это все объекты, обращение к которым делается с использованием их дескриптора.


// Дескрипторы объектов - это целые числа, которые присваиваются каждому создаваемому объекту
int iDialog; // дестриптор диалога
int iButton_Calculate; // дескриптор кнопки
int iTextEdit;         // дескриптор поля редактирования текста
int iLabel1, iLabel2;  // дескрипторы текста
int iPopUp;            // дескриптор ниспадающего списка  


Дальше начинается главная функция main() от { до }


int main()
{


создаем окно диалога и настраиваем:
       object("create", "ts_dialog", iDialog); // Создать объект ts_dialog и получить его дескриптор в переменную iDialog
       ts_dialog(iDialog, "init_dialog", "palette", 0, 0, 200, 400); // инициализировать ts_dialog как немодальный (плавающий) диалог Revit
       ts_dialog(iDialog, "settitle", "Мой диалог LABPP в Revit"); // задать заголовок окна


       ts_dialog(iDialog, "SetClientWH", 300, 150); // задать размеры окна 
       ts_dialog(iDialog, "set_as_main_panel"); // установить этот диалог как главный - когда он закроется, все остальные окна тоже закроются


       object("create", "ts_dialogcontrol", iLabel1); // Создать элемент текст на панели диалога
       ts_dialogcontrol(iLabel1, "init_control", "LeftText", iDialog, 10, 10, 170, 24); // инициализация как текст, выравненный по левой стороне
       ts_dialogcontrol(iLabel1, "SetText", "Расчетная плотность"); // задать текст


       object("create", "ts_dialogcontrol", iTextEdit); // Создать поле для ввода текста
       ts_dialogcontrol(iTextEdit, "init_control", "TextEdit", iDialog, 190, 10, 80, 24); // инициализация как текстового редактора, положение x,y и ширина и высота
       ts_dialogcontrol(iTextEdit, "settooltip", "Плотность материала"); // задать всплывающий текст (при наведении мыши)
       ts_dialogcontrol(iTextEdit, "SetText", "2,2"); // предустановить текст


       object("create", "ts_dialogcontrol", iLabel2); // Создать текст 2
       ts_dialogcontrol(iLabel2, "init_control", "LeftText", iDialog, 10, 35, 170, 24);
       ts_dialogcontrol(iLabel2, "SetText", "Результат записать в поле");



       object("create", "ts_dialogcontrol", iPopUp); // Создать popup элемент диалога (ниспадающий список)
       ts_dialogcontrol(iPopUp, "init_control", "PopUp", iDialog, 190, 35, 80, 25); // инициализировать как popup, задать положение x,y и ширину и высоту
       ts_dialogcontrol(iPopUp, "AppendItem"); // добавить пустой пункт
       ts_dialogcontrol(iPopUp, "SetItemText", 1,"B"); // задать текст для пункта 1
       ts_dialogcontrol(iPopUp, "AppendItem");
       ts_dialogcontrol(iPopUp, "SetItemText", 2, "C");
       ts_dialogcontrol(iPopUp, "AppendItem");
       ts_dialogcontrol(iPopUp, "SetItemText", 3, "D");


       ts_dialogcontrol(iPopUp, "SelectItem", 1); // сделать выбранным первый элемент ("B")



       object("create", "ts_dialogcontrol", iButton_Calculate, "iButton_Calculate"); // Создать кнопку
       ts_dialogcontrol(iButton_Calculate, "init_control", "button", iDialog, 190, 75, 80, 24); // инициализировать кнопку, задать положение  x,y и ширину и высоту
       ts_dialogcontrol(iButton_Calculate, "eventreaction", "Event_ButtonClicked", "Event_ButtonClicked_DCName"); // ** задать обработчик событий (тип "Event_ButtonClicked" и имя функции "Event_ButtonClicked_DCName")
       ts_dialogcontrol(iButton_Calculate, "settext", "Расчет"); // задать надпись на кнопке
       
       bool bres;
       ts_dialog(iDialog, "invoke", bres); // запустить диалог

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

Не экране остается диалог, который все события обрабатывает самостоятельно.


}

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

для нажатия (см. выше п. **)

Внутри нее проверяется какая кнопка обратилась к этому обработчику.

И если это кнопка с именем "iButton_Calculate", то запускается функция Do_iButton_Calculate().



// Обработчик события нажатия (Event Handler) для кнопки
// когда кнопка нажата, эта функция выполняется
// здесь iDescr - это дескриптор нажатой кнопки (iButtonCalculate в этом примере)
// и sDescr - текстовое имя элемента ("iButtonCalculate" в этом примере);
int Event_ButtonClicked_DCName(int iDescr, string sDescr)
{
       // в конструкциях if скобки { и } обязательны
       if (sDescr == "iButton_Calculate") 
       { 
               Do_iButton_Calculate(); 
       }
}

// функция, которая выполняется когда нажата кнопка iButton_Calculate
int Do_iButton_Calculate()
{
       string s;
       ts_dialogcontrol(iTextEdit, "gettext", s); // Получить текст из iTextEdit - плотность как текст, содержащий число с плавающей точкой
       strreplaceall(s, ",", ".");                // Если пользователь ввел "," мы заменяем его на "."
       double density = atof(s); // конвертируем текст в число с плавающей точкой

В LABPP C++ для Revit имеется 10 встроенных списков элементов (количество списков увеличивается командой при необходимости).

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

Возможно неограниченное количество скобок, команды "И" и "ИЛИ", указание различных функций и параметров элементов.

LABPP для Revit использует понятие Генезис для разделения параметров на категории чтобы избежать путанницы.

Какие параметры использовать в фильтрах вы можете понять запустив LABPP BIM Master.

На вкладке Common (общие) расположены параметры с генезисом "ЕP". На вкладке "ElemProps" (параметры на уровне экземпляра элемента) - генезис "UP". На вкладке "TypeProps" (параметры на уровне типа) - генезис "EPt". На вкладке BuiltInPars (встроенные параметры) - "UPb", и на вкладке "QTY" (quantity, количественные) - генезис "Q".

Команды для сравнения параметров разнообразны. От простого сравнения значений, до попадания в диапазон и наличия текстового шаблона Regex.



       // загрузить элементы из проекта Revit во внутренний список № 1 с фильтром:
       // любые элементы ("OST_Zombie"), MainFilter = 0,
       // параметр с генезисом "EP" (вкладка Common параметров на панели LABPP BIM Master) "ZFromProject0" должен быть >= 0 И
       // параметр с генезисом "UPt" (уровень типа элемента TypeProps на панели LABPP BIM Master) "Имя типа" должен содержать "бетон"
       // "_CONTAINS" - если есть знак подчеркивания, то при сравнении не учитывается регистр текста (все равно если "бетон", "Бетон" или "БЕТОН")
       rvt_request("load_elements_list", 1, "OST_Zombie", "MainFilter", 0,
               "(","EP","ZFromProject0",">=",0,")", "AND",
               "(","UPt", "Имя типа", "_CONTAINS", "бетон",")"
       );

       rvt_request("get_loaded_elements_list_count", 1); // запрос сколько элементов загружено в список 1
       int icount = rvt_getnumvalue(); // поместить результат запроса в переменную icount
       // объявить и присвоить первичные значения требуемым переменным
       string selement_name = "";
       double dvolume = 0;
       double dvolumeall = 0;
       double dmassa = 0; 
       double dmassaall = 0;
       int i;
       // напечатать в окре сообщений программ
       // ---------------
       // Элементы 10 шт
       //----------------
       cout << "\r\n---------------" << "\r\nЭлементы " << itoa(icount) << "шт\r\n---------------";
       // Расчетный цикл
       for (i = 0; i < icount; i++)
       {
               rvt_request("set_current_element_from_list", 1, i); // установить элемент i из списка № 1 как текущий для работы с ним
               rvt_request("get_element_value", "EP", "element_name"); // запросить имя элемента (параметр с генезисом "EP" - Common в LABPP BIM Master
               selement_name = rvt_getstrvalue(); // поместить результат запроса в переменную selement_name
               rvt_request("get_element_value", "UP", "Объем"); // запросить значение параметра UP/Объем (генезис "UP" - значит переменная уровня экземпляра элемента, вкладка ElemProps в LABPP_BIM_Master.
               dvolume = tsround(rvt_getnumvalue(),4); // получить результат запроса и округлить до 4-х знаков после запятой
               dmassa = dvolume * density; // расчитать массу умножением объема на плотность
               dmassaall += dmassa; // суммировать массу
               // напечатать строку отчета
               cout << "\r\n" << itoa(i+1) << "). "<< selement_name << ": объем= " << dvolume << " масса при плотности " << s << "=" << dmassa;
               dvolumeall += dvolume; // суммировать объем
       }
       // печатать итоговую строку
       cout << "\r\n" << "Суммарный объем элементов= " << dvolumeall << " суммарная масса при плотности " << s << "=" << dmassaall;
       // поместить в поле "A" LABPP_Calc суммарное значение объема и комментарий
       rvt_request("calc_field", "set", "a", 0, ftoa(tsround(dvolumeall,4)), "Объем элементов");

       string fieldletter2;
       ts_dialogcontrol(iPopUp, "GetText", fieldletter2); // получить из элемента popup имя поля, куда записать массу ("B", "C" or "D")
       rvt_request("calc_field", "set", fieldletter2, 0, ftoa(tsround(dmassaall,4)), "Масса при плотности "+s); // поместить в поле LABPP_Calc итоговую массу и комментарий
}